github.com/moqsien/xraycore@v1.8.5/transport/internet/tls/tls.go (about)

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