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

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