github.com/EagleQL/Xray-core@v1.4.3/common/protocol/tls/sniff.go (about) 1 package tls 2 3 import ( 4 "encoding/binary" 5 "errors" 6 "strings" 7 8 "github.com/xtls/xray-core/common" 9 ) 10 11 type SniffHeader struct { 12 domain string 13 } 14 15 func (h *SniffHeader) Protocol() string { 16 return "tls" 17 } 18 19 func (h *SniffHeader) Domain() string { 20 return h.domain 21 } 22 23 var errNotTLS = errors.New("not TLS header") 24 var errNotClientHello = errors.New("not client hello") 25 26 func IsValidTLSVersion(major, minor byte) bool { 27 return major == 3 28 } 29 30 // ReadClientHello returns server name (if any) from TLS client hello message. 31 // https://github.com/golang/go/blob/master/src/crypto/tls/handshake_messages.go#L300 32 func ReadClientHello(data []byte, h *SniffHeader) error { 33 if len(data) < 42 { 34 return common.ErrNoClue 35 } 36 sessionIDLen := int(data[38]) 37 if sessionIDLen > 32 || len(data) < 39+sessionIDLen { 38 return common.ErrNoClue 39 } 40 data = data[39+sessionIDLen:] 41 if len(data) < 2 { 42 return common.ErrNoClue 43 } 44 // cipherSuiteLen is the number of bytes of cipher suite numbers. Since 45 // they are uint16s, the number must be even. 46 cipherSuiteLen := int(data[0])<<8 | int(data[1]) 47 if cipherSuiteLen%2 == 1 || len(data) < 2+cipherSuiteLen { 48 return errNotClientHello 49 } 50 data = data[2+cipherSuiteLen:] 51 if len(data) < 1 { 52 return common.ErrNoClue 53 } 54 compressionMethodsLen := int(data[0]) 55 if len(data) < 1+compressionMethodsLen { 56 return common.ErrNoClue 57 } 58 data = data[1+compressionMethodsLen:] 59 60 if len(data) == 0 { 61 return errNotClientHello 62 } 63 if len(data) < 2 { 64 return errNotClientHello 65 } 66 67 extensionsLength := int(data[0])<<8 | int(data[1]) 68 data = data[2:] 69 if extensionsLength != len(data) { 70 return errNotClientHello 71 } 72 73 for len(data) != 0 { 74 if len(data) < 4 { 75 return errNotClientHello 76 } 77 extension := uint16(data[0])<<8 | uint16(data[1]) 78 length := int(data[2])<<8 | int(data[3]) 79 data = data[4:] 80 if len(data) < length { 81 return errNotClientHello 82 } 83 84 if extension == 0x00 { /* extensionServerName */ 85 d := data[:length] 86 if len(d) < 2 { 87 return errNotClientHello 88 } 89 namesLen := int(d[0])<<8 | int(d[1]) 90 d = d[2:] 91 if len(d) != namesLen { 92 return errNotClientHello 93 } 94 for len(d) > 0 { 95 if len(d) < 3 { 96 return errNotClientHello 97 } 98 nameType := d[0] 99 nameLen := int(d[1])<<8 | int(d[2]) 100 d = d[3:] 101 if len(d) < nameLen { 102 return errNotClientHello 103 } 104 if nameType == 0 { 105 serverName := string(d[:nameLen]) 106 // An SNI value may not include a 107 // trailing dot. See 108 // https://tools.ietf.org/html/rfc6066#section-3. 109 if strings.HasSuffix(serverName, ".") { 110 return errNotClientHello 111 } 112 h.domain = serverName 113 return nil 114 } 115 d = d[nameLen:] 116 } 117 } 118 data = data[length:] 119 } 120 121 return errNotTLS 122 } 123 124 func SniffTLS(b []byte) (*SniffHeader, error) { 125 if len(b) < 5 { 126 return nil, common.ErrNoClue 127 } 128 129 if b[0] != 0x16 /* TLS Handshake */ { 130 return nil, errNotTLS 131 } 132 if !IsValidTLSVersion(b[1], b[2]) { 133 return nil, errNotTLS 134 } 135 headerLen := int(binary.BigEndian.Uint16(b[3:5])) 136 if 5+headerLen > len(b) { 137 return nil, common.ErrNoClue 138 } 139 140 h := &SniffHeader{} 141 err := ReadClientHello(b[5:5+headerLen], h) 142 if err == nil { 143 return h, nil 144 } 145 return nil, err 146 }