github.com/xtls/xray-core@v1.8.12-0.20240518155711-3168d27b0bdb/transport/internet/tls/tls.go (about)

     1  package tls
     2  
     3  import (
     4  	"context"
     5  	"crypto/rand"
     6  	"crypto/tls"
     7  	"math/big"
     8  	"time"
     9  
    10  	utls "github.com/refraction-networking/utls"
    11  	"github.com/xtls/xray-core/common/buf"
    12  	"github.com/xtls/xray-core/common/net"
    13  )
    14  
    15  //go:generate go run github.com/xtls/xray-core/common/errors/errorgen
    16  
    17  type Interface interface {
    18  	net.Conn
    19  	HandshakeContext(ctx context.Context) error
    20  	VerifyHostname(host string) error
    21  	NegotiatedProtocol() string
    22  }
    23  
    24  var _ buf.Writer = (*Conn)(nil)
    25  var _ Interface = (*Conn)(nil)
    26  
    27  type Conn struct {
    28  	*tls.Conn
    29  }
    30  
    31  const tlsCloseTimeout = 250 * time.Millisecond
    32  
    33  func (c *Conn) Close() error {
    34  	timer := time.AfterFunc(tlsCloseTimeout, func() {
    35  		c.Conn.NetConn().Close()
    36  	})
    37  	defer timer.Stop()
    38  	return c.Conn.Close()
    39  }
    40  
    41  func (c *Conn) WriteMultiBuffer(mb buf.MultiBuffer) error {
    42  	mb = buf.Compact(mb)
    43  	mb, err := buf.WriteMultiBuffer(c, mb)
    44  	buf.ReleaseMulti(mb)
    45  	return err
    46  }
    47  
    48  func (c *Conn) HandshakeAddressContext(ctx context.Context) net.Address {
    49  	if err := c.HandshakeContext(ctx); err != nil {
    50  		return nil
    51  	}
    52  	state := c.ConnectionState()
    53  	if state.ServerName == "" {
    54  		return nil
    55  	}
    56  	return net.ParseAddress(state.ServerName)
    57  }
    58  
    59  func (c *Conn) NegotiatedProtocol() string {
    60  	state := c.ConnectionState()
    61  	return state.NegotiatedProtocol
    62  }
    63  
    64  // Client initiates a TLS client handshake on the given connection.
    65  func Client(c net.Conn, config *tls.Config) net.Conn {
    66  	tlsConn := tls.Client(c, config)
    67  	return &Conn{Conn: tlsConn}
    68  }
    69  
    70  // Server initiates a TLS server handshake on the given connection.
    71  func Server(c net.Conn, config *tls.Config) net.Conn {
    72  	tlsConn := tls.Server(c, config)
    73  	return &Conn{Conn: tlsConn}
    74  }
    75  
    76  type UConn struct {
    77  	*utls.UConn
    78  }
    79  
    80  var _ Interface = (*UConn)(nil)
    81  
    82  func (c *UConn) Close() error {
    83  	timer := time.AfterFunc(tlsCloseTimeout, func() {
    84  		c.Conn.NetConn().Close()
    85  	})
    86  	defer timer.Stop()
    87  	return c.Conn.Close()
    88  }
    89  
    90  func (c *UConn) HandshakeAddressContext(ctx context.Context) net.Address {
    91  	if err := c.HandshakeContext(ctx); err != nil {
    92  		return nil
    93  	}
    94  	state := c.ConnectionState()
    95  	if state.ServerName == "" {
    96  		return nil
    97  	}
    98  	return net.ParseAddress(state.ServerName)
    99  }
   100  
   101  // WebsocketHandshake basically calls UConn.Handshake inside it but it will only send
   102  // http/1.1 in its ALPN.
   103  func (c *UConn) WebsocketHandshakeContext(ctx context.Context) error {
   104  	// Build the handshake state. This will apply every variable of the TLS of the
   105  	// fingerprint in the UConn
   106  	if err := c.BuildHandshakeState(); err != nil {
   107  		return err
   108  	}
   109  	// Iterate over extensions and check for utls.ALPNExtension
   110  	hasALPNExtension := false
   111  	for _, extension := range c.Extensions {
   112  		if alpn, ok := extension.(*utls.ALPNExtension); ok {
   113  			hasALPNExtension = true
   114  			alpn.AlpnProtocols = []string{"http/1.1"}
   115  			break
   116  		}
   117  	}
   118  	if !hasALPNExtension { // Append extension if doesn't exists
   119  		c.Extensions = append(c.Extensions, &utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}})
   120  	}
   121  	// Rebuild the client hello and do the handshake
   122  	if err := c.BuildHandshakeState(); err != nil {
   123  		return err
   124  	}
   125  	return c.HandshakeContext(ctx)
   126  }
   127  
   128  func (c *UConn) NegotiatedProtocol() string {
   129  	state := c.ConnectionState()
   130  	return state.NegotiatedProtocol
   131  }
   132  
   133  func UClient(c net.Conn, config *tls.Config, fingerprint *utls.ClientHelloID) net.Conn {
   134  	utlsConn := utls.UClient(c, copyConfig(config), *fingerprint)
   135  	return &UConn{UConn: utlsConn}
   136  }
   137  
   138  func copyConfig(c *tls.Config) *utls.Config {
   139  	return &utls.Config{
   140  		RootCAs:               c.RootCAs,
   141  		ServerName:            c.ServerName,
   142  		InsecureSkipVerify:    c.InsecureSkipVerify,
   143  		VerifyPeerCertificate: c.VerifyPeerCertificate,
   144  		KeyLogWriter:          c.KeyLogWriter,
   145  	}
   146  }
   147  
   148  func init() {
   149  	bigInt, _ := rand.Int(rand.Reader, big.NewInt(int64(len(ModernFingerprints))))
   150  	stopAt := int(bigInt.Int64())
   151  	i := 0
   152  	for _, v := range ModernFingerprints {
   153  		if i == stopAt {
   154  			PresetFingerprints["random"] = v
   155  			break
   156  		}
   157  		i++
   158  	}
   159  	weights := utls.DefaultWeights
   160  	weights.TLSVersMax_Set_VersionTLS13 = 1
   161  	weights.FirstKeyShare_Set_CurveP256 = 0
   162  	randomized := utls.HelloRandomized
   163  	randomized.Seed, _ = utls.NewPRNGSeed()
   164  	randomized.Weights = &weights
   165  	PresetFingerprints["randomized"] = &randomized
   166  }
   167  
   168  func GetFingerprint(name string) (fingerprint *utls.ClientHelloID) {
   169  	if name == "" {
   170  		return
   171  	}
   172  	if fingerprint = PresetFingerprints[name]; fingerprint != nil {
   173  		return
   174  	}
   175  	if fingerprint = ModernFingerprints[name]; fingerprint != nil {
   176  		return
   177  	}
   178  	if fingerprint = OtherFingerprints[name]; fingerprint != nil {
   179  		return
   180  	}
   181  	return
   182  }
   183  
   184  var PresetFingerprints = map[string]*utls.ClientHelloID{
   185  	// Recommended preset options in GUI clients
   186  	"chrome":     &utls.HelloChrome_Auto,
   187  	"firefox":    &utls.HelloFirefox_Auto,
   188  	"safari":     &utls.HelloSafari_Auto,
   189  	"ios":        &utls.HelloIOS_Auto,
   190  	"android":    &utls.HelloAndroid_11_OkHttp,
   191  	"edge":       &utls.HelloEdge_Auto,
   192  	"360":        &utls.Hello360_Auto,
   193  	"qq":         &utls.HelloQQ_Auto,
   194  	"random":     nil,
   195  	"randomized": nil,
   196  }
   197  
   198  var ModernFingerprints = map[string]*utls.ClientHelloID{
   199  	// One of these will be chosen as `random` at startup
   200  	"hellofirefox_99":         &utls.HelloFirefox_99,
   201  	"hellofirefox_102":        &utls.HelloFirefox_102,
   202  	"hellofirefox_105":        &utls.HelloFirefox_105,
   203  	"hellochrome_83":          &utls.HelloChrome_83,
   204  	"hellochrome_87":          &utls.HelloChrome_87,
   205  	"hellochrome_96":          &utls.HelloChrome_96,
   206  	"hellochrome_100":         &utls.HelloChrome_100,
   207  	"hellochrome_102":         &utls.HelloChrome_102,
   208  	"hellochrome_106_shuffle": &utls.HelloChrome_106_Shuffle,
   209  	"helloios_13":             &utls.HelloIOS_13,
   210  	"helloios_14":             &utls.HelloIOS_14,
   211  	"helloedge_85":            &utls.HelloEdge_85,
   212  	"helloedge_106":           &utls.HelloEdge_106,
   213  	"hellosafari_16_0":        &utls.HelloSafari_16_0,
   214  	"hello360_11_0":           &utls.Hello360_11_0,
   215  	"helloqq_11_1":            &utls.HelloQQ_11_1,
   216  }
   217  
   218  var OtherFingerprints = map[string]*utls.ClientHelloID{
   219  	// Golang, randomized, auto, and fingerprints that are too old
   220  	"hellogolang":            &utls.HelloGolang,
   221  	"hellorandomized":        &utls.HelloRandomized,
   222  	"hellorandomizedalpn":    &utls.HelloRandomizedALPN,
   223  	"hellorandomizednoalpn":  &utls.HelloRandomizedNoALPN,
   224  	"hellofirefox_auto":      &utls.HelloFirefox_Auto,
   225  	"hellofirefox_55":        &utls.HelloFirefox_55,
   226  	"hellofirefox_56":        &utls.HelloFirefox_56,
   227  	"hellofirefox_63":        &utls.HelloFirefox_63,
   228  	"hellofirefox_65":        &utls.HelloFirefox_65,
   229  	"hellochrome_auto":       &utls.HelloChrome_Auto,
   230  	"hellochrome_58":         &utls.HelloChrome_58,
   231  	"hellochrome_62":         &utls.HelloChrome_62,
   232  	"hellochrome_70":         &utls.HelloChrome_70,
   233  	"hellochrome_72":         &utls.HelloChrome_72,
   234  	"helloios_auto":          &utls.HelloIOS_Auto,
   235  	"helloios_11_1":          &utls.HelloIOS_11_1,
   236  	"helloios_12_1":          &utls.HelloIOS_12_1,
   237  	"helloandroid_11_okhttp": &utls.HelloAndroid_11_OkHttp,
   238  	"helloedge_auto":         &utls.HelloEdge_Auto,
   239  	"hellosafari_auto":       &utls.HelloSafari_Auto,
   240  	"hello360_auto":          &utls.Hello360_Auto,
   241  	"hello360_7_5":           &utls.Hello360_7_5,
   242  	"helloqq_auto":           &utls.HelloQQ_Auto,
   243  }