github.com/sagernet/sing-box@v1.2.7/common/tls/utls_client.go (about)

     1  //go:build with_utls
     2  
     3  package tls
     4  
     5  import (
     6  	"context"
     7  	"crypto/tls"
     8  	"crypto/x509"
     9  	"math/rand"
    10  	"net"
    11  	"net/netip"
    12  	"os"
    13  
    14  	"github.com/sagernet/sing-box/adapter"
    15  	"github.com/sagernet/sing-box/option"
    16  	E "github.com/sagernet/sing/common/exceptions"
    17  	utls "github.com/sagernet/utls"
    18  
    19  	"golang.org/x/net/http2"
    20  )
    21  
    22  type UTLSClientConfig struct {
    23  	config *utls.Config
    24  	id     utls.ClientHelloID
    25  }
    26  
    27  func (e *UTLSClientConfig) ServerName() string {
    28  	return e.config.ServerName
    29  }
    30  
    31  func (e *UTLSClientConfig) SetServerName(serverName string) {
    32  	e.config.ServerName = serverName
    33  }
    34  
    35  func (e *UTLSClientConfig) NextProtos() []string {
    36  	return e.config.NextProtos
    37  }
    38  
    39  func (e *UTLSClientConfig) SetNextProtos(nextProto []string) {
    40  	if len(nextProto) == 1 && nextProto[0] == http2.NextProtoTLS {
    41  		nextProto = append(nextProto, "http/1.1")
    42  	}
    43  	e.config.NextProtos = nextProto
    44  }
    45  
    46  func (e *UTLSClientConfig) Config() (*STDConfig, error) {
    47  	return nil, E.New("unsupported usage for uTLS")
    48  }
    49  
    50  func (e *UTLSClientConfig) Client(conn net.Conn) (Conn, error) {
    51  	return &utlsALPNWrapper{utlsConnWrapper{utls.UClient(conn, e.config.Clone(), e.id)}, e.config.NextProtos}, nil
    52  }
    53  
    54  func (e *UTLSClientConfig) SetSessionIDGenerator(generator func(clientHello []byte, sessionID []byte) error) {
    55  	e.config.SessionIDGenerator = generator
    56  }
    57  
    58  func (e *UTLSClientConfig) Clone() Config {
    59  	return &UTLSClientConfig{
    60  		config: e.config.Clone(),
    61  		id:     e.id,
    62  	}
    63  }
    64  
    65  type utlsConnWrapper struct {
    66  	*utls.UConn
    67  }
    68  
    69  func (c *utlsConnWrapper) ConnectionState() tls.ConnectionState {
    70  	state := c.Conn.ConnectionState()
    71  	return tls.ConnectionState{
    72  		Version:                     state.Version,
    73  		HandshakeComplete:           state.HandshakeComplete,
    74  		DidResume:                   state.DidResume,
    75  		CipherSuite:                 state.CipherSuite,
    76  		NegotiatedProtocol:          state.NegotiatedProtocol,
    77  		NegotiatedProtocolIsMutual:  state.NegotiatedProtocolIsMutual,
    78  		ServerName:                  state.ServerName,
    79  		PeerCertificates:            state.PeerCertificates,
    80  		VerifiedChains:              state.VerifiedChains,
    81  		SignedCertificateTimestamps: state.SignedCertificateTimestamps,
    82  		OCSPResponse:                state.OCSPResponse,
    83  		TLSUnique:                   state.TLSUnique,
    84  	}
    85  }
    86  
    87  func (c *utlsConnWrapper) Upstream() any {
    88  	return c.UConn
    89  }
    90  
    91  type utlsALPNWrapper struct {
    92  	utlsConnWrapper
    93  	nextProtocols []string
    94  }
    95  
    96  func (c *utlsALPNWrapper) HandshakeContext(ctx context.Context) error {
    97  	if len(c.nextProtocols) > 0 {
    98  		err := c.BuildHandshakeState()
    99  		if err != nil {
   100  			return err
   101  		}
   102  		for _, extension := range c.Extensions {
   103  			if alpnExtension, isALPN := extension.(*utls.ALPNExtension); isALPN {
   104  				alpnExtension.AlpnProtocols = c.nextProtocols
   105  				err = c.BuildHandshakeState()
   106  				if err != nil {
   107  					return err
   108  				}
   109  				break
   110  			}
   111  		}
   112  	}
   113  	return c.UConn.HandshakeContext(ctx)
   114  }
   115  
   116  func NewUTLSClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (*UTLSClientConfig, error) {
   117  	var serverName string
   118  	if options.ServerName != "" {
   119  		serverName = options.ServerName
   120  	} else if serverAddress != "" {
   121  		if _, err := netip.ParseAddr(serverName); err != nil {
   122  			serverName = serverAddress
   123  		}
   124  	}
   125  	if serverName == "" && !options.Insecure {
   126  		return nil, E.New("missing server_name or insecure=true")
   127  	}
   128  
   129  	var tlsConfig utls.Config
   130  	tlsConfig.Time = router.TimeFunc()
   131  	if options.DisableSNI {
   132  		tlsConfig.ServerName = "127.0.0.1"
   133  	} else {
   134  		tlsConfig.ServerName = serverName
   135  	}
   136  	if options.Insecure {
   137  		tlsConfig.InsecureSkipVerify = options.Insecure
   138  	} else if options.DisableSNI {
   139  		return nil, E.New("disable_sni is unsupported in uTLS")
   140  	}
   141  	if len(options.ALPN) > 0 {
   142  		tlsConfig.NextProtos = options.ALPN
   143  	}
   144  	if options.MinVersion != "" {
   145  		minVersion, err := ParseTLSVersion(options.MinVersion)
   146  		if err != nil {
   147  			return nil, E.Cause(err, "parse min_version")
   148  		}
   149  		tlsConfig.MinVersion = minVersion
   150  	}
   151  	if options.MaxVersion != "" {
   152  		maxVersion, err := ParseTLSVersion(options.MaxVersion)
   153  		if err != nil {
   154  			return nil, E.Cause(err, "parse max_version")
   155  		}
   156  		tlsConfig.MaxVersion = maxVersion
   157  	}
   158  	if options.CipherSuites != nil {
   159  	find:
   160  		for _, cipherSuite := range options.CipherSuites {
   161  			for _, tlsCipherSuite := range tls.CipherSuites() {
   162  				if cipherSuite == tlsCipherSuite.Name {
   163  					tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, tlsCipherSuite.ID)
   164  					continue find
   165  				}
   166  			}
   167  			return nil, E.New("unknown cipher_suite: ", cipherSuite)
   168  		}
   169  	}
   170  	var certificate []byte
   171  	if options.Certificate != "" {
   172  		certificate = []byte(options.Certificate)
   173  	} else if options.CertificatePath != "" {
   174  		content, err := os.ReadFile(options.CertificatePath)
   175  		if err != nil {
   176  			return nil, E.Cause(err, "read certificate")
   177  		}
   178  		certificate = content
   179  	}
   180  	if len(certificate) > 0 {
   181  		certPool := x509.NewCertPool()
   182  		if !certPool.AppendCertsFromPEM(certificate) {
   183  			return nil, E.New("failed to parse certificate:\n\n", certificate)
   184  		}
   185  		tlsConfig.RootCAs = certPool
   186  	}
   187  	id, err := uTLSClientHelloID(options.UTLS.Fingerprint)
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  	return &UTLSClientConfig{&tlsConfig, id}, nil
   192  }
   193  
   194  var (
   195  	randomFingerprint     utls.ClientHelloID
   196  	randomizedFingerprint utls.ClientHelloID
   197  )
   198  
   199  func init() {
   200  	modernFingerprints := []utls.ClientHelloID{
   201  		utls.HelloChrome_Auto,
   202  		utls.HelloFirefox_Auto,
   203  		utls.HelloEdge_Auto,
   204  		utls.HelloSafari_Auto,
   205  		utls.HelloIOS_Auto,
   206  	}
   207  	randomFingerprint = modernFingerprints[rand.Intn(len(modernFingerprints))]
   208  
   209  	weights := utls.DefaultWeights
   210  	weights.TLSVersMax_Set_VersionTLS13 = 1
   211  	weights.FirstKeyShare_Set_CurveP256 = 0
   212  	randomizedFingerprint = utls.HelloRandomized
   213  	randomizedFingerprint.Seed, _ = utls.NewPRNGSeed()
   214  	randomizedFingerprint.Weights = &weights
   215  }
   216  
   217  func uTLSClientHelloID(name string) (utls.ClientHelloID, error) {
   218  	switch name {
   219  	case "chrome", "":
   220  		return utls.HelloChrome_Auto, nil
   221  	case "firefox":
   222  		return utls.HelloFirefox_Auto, nil
   223  	case "edge":
   224  		return utls.HelloEdge_Auto, nil
   225  	case "safari":
   226  		return utls.HelloSafari_Auto, nil
   227  	case "360":
   228  		return utls.Hello360_Auto, nil
   229  	case "qq":
   230  		return utls.HelloQQ_Auto, nil
   231  	case "ios":
   232  		return utls.HelloIOS_Auto, nil
   233  	case "android":
   234  		return utls.HelloAndroid_11_OkHttp, nil
   235  	case "random":
   236  		return randomFingerprint, nil
   237  	case "randomized":
   238  		return randomizedFingerprint, nil
   239  	default:
   240  		return utls.ClientHelloID{}, E.New("unknown uTLS fingerprint: ", name)
   241  	}
   242  }