package vless import ( "bytes" "encoding/binary" "github.com/Dreamacro/clash/log" ) var ( tls13SupportedVersions = []byte{0x00, 0x2b, 0x00, 0x02, 0x03, 0x04} tlsClientHandshakeStart = []byte{0x16, 0x03} tlsServerHandshakeStart = []byte{0x16, 0x03, 0x03} tlsApplicationDataStart = []byte{0x17, 0x03, 0x03} tls13CipherSuiteMap = map[uint16]string{ 0x1301: "TLS_AES_128_GCM_SHA256", 0x1302: "TLS_AES_256_GCM_SHA384", 0x1303: "TLS_CHACHA20_POLY1305_SHA256", 0x1304: "TLS_AES_128_CCM_SHA256", 0x1305: "TLS_AES_128_CCM_8_SHA256", } ) const ( tlsHandshakeTypeClientHello byte = 0x01 tlsHandshakeTypeServerHello byte = 0x02 ) func (vc *Conn) FilterTLS(buffer []byte) (index int) { if vc.packetsToFilter <= 0 { return 0 } lenP := len(buffer) vc.packetsToFilter-- if index = bytes.Index(buffer, tlsServerHandshakeStart); index != -1 { if lenP > index+5 { if buffer[0] == 22 && buffer[1] == 3 && buffer[2] == 3 { vc.isTLS = true if buffer[5] == tlsHandshakeTypeServerHello { //log.Debugln("isTLS12orAbove") vc.remainingServerHello = binary.BigEndian.Uint16(buffer[index+3:]) + 5 vc.isTLS12orAbove = true if lenP-index >= 79 && vc.remainingServerHello >= 79 { sessionIDLen := int(buffer[index+43]) vc.cipher = binary.BigEndian.Uint16(buffer[index+43+sessionIDLen+1:]) } } } } } else if index = bytes.Index(buffer, tlsClientHandshakeStart); index != -1 { if lenP > index+5 && buffer[index+5] == tlsHandshakeTypeClientHello { vc.isTLS = true } } if vc.remainingServerHello > 0 { end := int(vc.remainingServerHello) i := index if i < 0 { i = 0 } if i+end > lenP { end = lenP vc.remainingServerHello -= uint16(end - i) } else { vc.remainingServerHello -= uint16(end) end += i } if bytes.Contains(buffer[i:end], tls13SupportedVersions) { // TLS 1.3 Client Hello cs, ok := tls13CipherSuiteMap[vc.cipher] if ok && cs != "TLS_AES_128_CCM_8_SHA256" { vc.enableXTLS = true } log.Debugln("XTLS Vision found TLS 1.3, packetLength=%d, CipherSuite=%s", lenP, cs) vc.packetsToFilter = 0 return } else if vc.remainingServerHello <= 0 { log.Debugln("XTLS Vision found TLS 1.2, packetLength=%d", lenP) vc.packetsToFilter = 0 return } log.Debugln("XTLS Vision found inconclusive server hello, packetLength=%d, remainingServerHelloBytes=%d", lenP, vc.remainingServerHello) } if vc.packetsToFilter <= 0 { log.Debugln("XTLS Vision stop filtering") } return }