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  }