github.com/inazumav/sing-box@v0.0.0-20230926072359-ab51429a14f1/common/tls/std_client.go (about) 1 package tls 2 3 import ( 4 "context" 5 "crypto/tls" 6 "crypto/x509" 7 "net" 8 "net/netip" 9 "os" 10 11 "github.com/inazumav/sing-box/option" 12 E "github.com/sagernet/sing/common/exceptions" 13 "github.com/sagernet/sing/common/ntp" 14 ) 15 16 type STDClientConfig struct { 17 config *tls.Config 18 } 19 20 func (s *STDClientConfig) ServerName() string { 21 return s.config.ServerName 22 } 23 24 func (s *STDClientConfig) SetServerName(serverName string) { 25 s.config.ServerName = serverName 26 } 27 28 func (s *STDClientConfig) NextProtos() []string { 29 return s.config.NextProtos 30 } 31 32 func (s *STDClientConfig) SetNextProtos(nextProto []string) { 33 s.config.NextProtos = nextProto 34 } 35 36 func (s *STDClientConfig) Config() (*STDConfig, error) { 37 return s.config, nil 38 } 39 40 func (s *STDClientConfig) Client(conn net.Conn) (Conn, error) { 41 return tls.Client(conn, s.config), nil 42 } 43 44 func (s *STDClientConfig) Clone() Config { 45 return &STDClientConfig{s.config.Clone()} 46 } 47 48 func NewSTDClient(ctx context.Context, serverAddress string, options option.OutboundTLSOptions) (Config, error) { 49 var serverName string 50 if options.ServerName != "" { 51 serverName = options.ServerName 52 } else if serverAddress != "" { 53 if _, err := netip.ParseAddr(serverName); err != nil { 54 serverName = serverAddress 55 } 56 } 57 if serverName == "" && !options.Insecure { 58 return nil, E.New("missing server_name or insecure=true") 59 } 60 61 var tlsConfig tls.Config 62 tlsConfig.Time = ntp.TimeFuncFromContext(ctx) 63 if options.DisableSNI { 64 tlsConfig.ServerName = "127.0.0.1" 65 } else { 66 tlsConfig.ServerName = serverName 67 } 68 if options.Insecure { 69 tlsConfig.InsecureSkipVerify = options.Insecure 70 } else if options.DisableSNI { 71 tlsConfig.InsecureSkipVerify = true 72 tlsConfig.VerifyConnection = func(state tls.ConnectionState) error { 73 verifyOptions := x509.VerifyOptions{ 74 DNSName: serverName, 75 Intermediates: x509.NewCertPool(), 76 } 77 for _, cert := range state.PeerCertificates[1:] { 78 verifyOptions.Intermediates.AddCert(cert) 79 } 80 _, err := state.PeerCertificates[0].Verify(verifyOptions) 81 return err 82 } 83 } 84 if len(options.ALPN) > 0 { 85 tlsConfig.NextProtos = options.ALPN 86 } 87 if options.MinVersion != "" { 88 minVersion, err := ParseTLSVersion(options.MinVersion) 89 if err != nil { 90 return nil, E.Cause(err, "parse min_version") 91 } 92 tlsConfig.MinVersion = minVersion 93 } 94 if options.MaxVersion != "" { 95 maxVersion, err := ParseTLSVersion(options.MaxVersion) 96 if err != nil { 97 return nil, E.Cause(err, "parse max_version") 98 } 99 tlsConfig.MaxVersion = maxVersion 100 } 101 if options.CipherSuites != nil { 102 find: 103 for _, cipherSuite := range options.CipherSuites { 104 for _, tlsCipherSuite := range tls.CipherSuites() { 105 if cipherSuite == tlsCipherSuite.Name { 106 tlsConfig.CipherSuites = append(tlsConfig.CipherSuites, tlsCipherSuite.ID) 107 continue find 108 } 109 } 110 return nil, E.New("unknown cipher_suite: ", cipherSuite) 111 } 112 } 113 var certificate []byte 114 if options.Certificate != "" { 115 certificate = []byte(options.Certificate) 116 } else if options.CertificatePath != "" { 117 content, err := os.ReadFile(options.CertificatePath) 118 if err != nil { 119 return nil, E.Cause(err, "read certificate") 120 } 121 certificate = content 122 } 123 if len(certificate) > 0 { 124 certPool := x509.NewCertPool() 125 if !certPool.AppendCertsFromPEM(certificate) { 126 return nil, E.New("failed to parse certificate:\n\n", certificate) 127 } 128 tlsConfig.RootCAs = certPool 129 } 130 return &STDClientConfig{&tlsConfig}, nil 131 }