1 package reverseproxy 2 3 import ( 4 "errors" 5 "fmt" 6 "io" 7 8 "vimagination.zapto.org/byteio" 9 "vimagination.zapto.org/memio" 10 ) 11 12 const maxTLSRead = 5 + 65536 13 14 func readTLSServerName(c io.Reader, buf []byte) (string, []byte, error) { 15 mbuf := memio.Buffer(buf[1:5]) 16 n, err := io.ReadFull(c, mbuf) 17 if err != nil { 18 return "", buf, err 19 } 20 r := byteio.StickyBigEndianReader{ 21 Reader: &mbuf, 22 } 23 24 mbuf = mbuf[1:] // skip major version 25 mbuf = mbuf[1:] // skip minor version 26 27 length := r.ReadUint16() 28 29 if cap(mbuf) < int(length) { 30 return "", buf, io.ErrShortBuffer 31 } 32 33 mbuf = mbuf[:length] 34 m, err := io.ReadFull(c, mbuf) 35 if err != nil { 36 return "", buf, err 37 } 38 n += m 39 40 if r.ReadUint8() != 1 { 41 return "", buf, errNoClientHello 42 } 43 44 l := r.ReadUint24() 45 if l != uint32(length)-4 { 46 return "", buf, fmt.Errorf("error reading body: %w", errInvalidLength) 47 } 48 49 mbuf = mbuf[1:] // skip major version 50 mbuf = mbuf[1:] // skip minor version 51 52 mbuf = mbuf[4:] // skip gmt_unix_time 53 mbuf = mbuf[28:] // skip random_bytes 54 55 sessionLength := r.ReadUint8() 56 if sessionLength > 32 || len(mbuf) < int(sessionLength) { 57 // invalid length 58 return "", buf, fmt.Errorf("error reading sesion id: %w", errInvalidLength) 59 } 60 mbuf = mbuf[sessionLength:] // skip session id 61 62 cipherSuiteLength := r.ReadUint16() 63 if cipherSuiteLength == 0 || len(mbuf) < int(cipherSuiteLength) { 64 // invalid length 65 return "", buf, fmt.Errorf("error reading cipher suites: %w", errInvalidLength) 66 } 67 mbuf = mbuf[cipherSuiteLength:] // skip cipher suites 68 69 compressionMethodLength := r.ReadUint8() 70 if compressionMethodLength < 1 || len(mbuf) < int(compressionMethodLength) { 71 return "", buf, fmt.Errorf("error reading compressions: %w", errInvalidLength) 72 } 73 mbuf = mbuf[compressionMethodLength:] // skip compression methods 74 75 extsLength := r.ReadUint16() 76 if len(mbuf) < int(extsLength) { 77 return "", buf, fmt.Errorf("error reading extensions: %w", errInvalidLength) 78 } 79 mbuf = mbuf[:extsLength] 80 81 for len(mbuf) > 0 { 82 extType := r.ReadUint16() 83 extLength := r.ReadUint16() 84 if len(mbuf) < int(extLength) { 85 return "", buf, fmt.Errorf("error reading extension: %w", errInvalidLength) 86 } 87 if extType == 0 { // server_name 88 l := r.ReadUint16() 89 if l != extLength-2 { 90 return "", buf, fmt.Errorf("error reading server name extension: %w", errInvalidLength) 91 } 92 93 mbuf = mbuf[1:] // skip name_type 94 95 nameLength := r.ReadUint16() 96 if len(mbuf) < int(nameLength) { 97 return "", buf, fmt.Errorf("error reading server name: %w", errInvalidLength) 98 } 99 return string(mbuf[:nameLength]), buf[:n+1], nil 100 } 101 mbuf = mbuf[extLength:] 102 } 103 return "", buf, errNoName 104 } 105 106 var ( 107 errNoClientHello = errors.New("not a client hello") 108 errInvalidLength = errors.New("invalid length") 109 errNoName = errors.New("no server name") 110 ) 111