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 }