github.com/xraypb/xray-core@v1.6.6/transport/internet/tls/tls.go (about) 1 package tls 2 3 import ( 4 "crypto/tls" 5 6 utls "github.com/refraction-networking/utls" 7 "github.com/xraypb/xray-core/common/buf" 8 "github.com/xraypb/xray-core/common/net" 9 ) 10 11 //go:generate go run github.com/xraypb/xray-core/common/errors/errorgen 12 13 var _ buf.Writer = (*Conn)(nil) 14 15 type Conn struct { 16 *tls.Conn 17 } 18 19 func (c *Conn) WriteMultiBuffer(mb buf.MultiBuffer) error { 20 mb = buf.Compact(mb) 21 mb, err := buf.WriteMultiBuffer(c, mb) 22 buf.ReleaseMulti(mb) 23 return err 24 } 25 26 func (c *Conn) HandshakeAddress() net.Address { 27 if err := c.Handshake(); err != nil { 28 return nil 29 } 30 state := c.ConnectionState() 31 if state.ServerName == "" { 32 return nil 33 } 34 return net.ParseAddress(state.ServerName) 35 } 36 37 func (c *Conn) NegotiatedProtocol() (name string, mutual bool) { 38 state := c.ConnectionState() 39 return state.NegotiatedProtocol, state.NegotiatedProtocolIsMutual 40 } 41 42 // Client initiates a TLS client handshake on the given connection. 43 func Client(c net.Conn, config *tls.Config) net.Conn { 44 tlsConn := tls.Client(c, config) 45 return &Conn{Conn: tlsConn} 46 } 47 48 // Server initiates a TLS server handshake on the given connection. 49 func Server(c net.Conn, config *tls.Config) net.Conn { 50 tlsConn := tls.Server(c, config) 51 return &Conn{Conn: tlsConn} 52 } 53 54 type UConn struct { 55 *utls.UConn 56 } 57 58 func (c *UConn) HandshakeAddress() net.Address { 59 if err := c.Handshake(); err != nil { 60 return nil 61 } 62 state := c.ConnectionState() 63 if state.ServerName == "" { 64 return nil 65 } 66 return net.ParseAddress(state.ServerName) 67 } 68 69 // WebsocketHandshake basically calls UConn.Handshake inside it but it will only send 70 // http/1.1 in its ALPN. 71 func (c *UConn) WebsocketHandshake() error { 72 // Build the handshake state. This will apply every variable of the TLS of the 73 // fingerprint in the UConn 74 if err := c.BuildHandshakeState(); err != nil { 75 return err 76 } 77 // Iterate over extensions and check for utls.ALPNExtension 78 hasALPNExtension := false 79 for _, extension := range c.Extensions { 80 if alpn, ok := extension.(*utls.ALPNExtension); ok { 81 hasALPNExtension = true 82 alpn.AlpnProtocols = []string{"http/1.1"} 83 break 84 } 85 } 86 if !hasALPNExtension { // Append extension if doesn't exists 87 c.Extensions = append(c.Extensions, &utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}}) 88 } 89 // Rebuild the client hello and do the handshake 90 if err := c.BuildHandshakeState(); err != nil { 91 return err 92 } 93 return c.Handshake() 94 } 95 96 func (c *UConn) NegotiatedProtocol() (name string, mutual bool) { 97 state := c.ConnectionState() 98 return state.NegotiatedProtocol, state.NegotiatedProtocolIsMutual 99 } 100 101 func UClient(c net.Conn, config *tls.Config, fingerprint *utls.ClientHelloID) net.Conn { 102 utlsConn := utls.UClient(c, copyConfig(config), *fingerprint) 103 return &UConn{UConn: utlsConn} 104 } 105 106 func copyConfig(c *tls.Config) *utls.Config { 107 return &utls.Config{ 108 RootCAs: c.RootCAs, 109 ServerName: c.ServerName, 110 InsecureSkipVerify: c.InsecureSkipVerify, 111 } 112 } 113 114 var Fingerprints = map[string]*utls.ClientHelloID{ 115 "chrome": &utls.HelloChrome_Auto, 116 "firefox": &utls.HelloFirefox_Auto, 117 "safari": &utls.HelloIOS_Auto, 118 "randomized": &utls.HelloRandomized, 119 } 120 121 type Interface interface { 122 net.Conn 123 Handshake() error 124 VerifyHostname(host string) error 125 NegotiatedProtocol() (name string, mutual bool) 126 }