client.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. package tls
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "errors"
  6. "net"
  7. "os"
  8. "strings"
  9. "github.com/sagernet/sing-box/common/badtls"
  10. "github.com/sagernet/sing-box/common/tlsspoof"
  11. C "github.com/sagernet/sing-box/constant"
  12. "github.com/sagernet/sing-box/option"
  13. E "github.com/sagernet/sing/common/exceptions"
  14. "github.com/sagernet/sing/common/logger"
  15. M "github.com/sagernet/sing/common/metadata"
  16. N "github.com/sagernet/sing/common/network"
  17. aTLS "github.com/sagernet/sing/common/tls"
  18. )
  19. var errMissingServerName = E.New("missing server_name or insecure=true")
  20. func parseTLSSpoofOptions(serverName string, options option.OutboundTLSOptions) (string, tlsspoof.Method, error) {
  21. if options.Spoof == "" {
  22. if options.SpoofMethod != "" {
  23. return "", 0, E.New("`spoof_method` requires `spoof`")
  24. }
  25. return "", 0, nil
  26. }
  27. if !tlsspoof.PlatformSupported {
  28. return "", 0, E.New("`spoof` is not supported on this platform")
  29. }
  30. if options.DisableSNI || serverName == "" || M.ParseAddr(serverName).IsValid() {
  31. return "", 0, E.New("`spoof` requires TLS ClientHello with SNI")
  32. }
  33. if strings.EqualFold(options.Spoof, serverName) {
  34. return "", 0, E.New("`spoof` must differ from `server_name`")
  35. }
  36. method, err := tlsspoof.ParseMethod(options.SpoofMethod)
  37. if err != nil {
  38. return "", 0, err
  39. }
  40. return options.Spoof, method, nil
  41. }
  42. func applyTLSSpoof(conn net.Conn, spoof string, method tlsspoof.Method) (net.Conn, error) {
  43. if spoof == "" {
  44. return conn, nil
  45. }
  46. return tlsspoof.NewConn(conn, method, spoof)
  47. }
  48. func NewDialerFromOptions(ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) {
  49. if !options.Enabled {
  50. return dialer, nil
  51. }
  52. config, err := NewClientWithOptions(ClientOptions{
  53. Context: ctx,
  54. Logger: logger,
  55. ServerAddress: serverAddress,
  56. Options: options,
  57. })
  58. if err != nil {
  59. return nil, err
  60. }
  61. return NewDialer(dialer, config), nil
  62. }
  63. func NewClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
  64. return NewClientWithOptions(ClientOptions{
  65. Context: ctx,
  66. Logger: logger,
  67. ServerAddress: serverAddress,
  68. Options: options,
  69. })
  70. }
  71. type ClientOptions struct {
  72. Context context.Context
  73. Logger logger.ContextLogger
  74. ServerAddress string
  75. Options option.OutboundTLSOptions
  76. AllowEmptyServerName bool
  77. KTLSCompatible bool
  78. }
  79. func NewClientWithOptions(options ClientOptions) (Config, error) {
  80. if !options.Options.Enabled {
  81. return nil, nil
  82. }
  83. if !options.KTLSCompatible {
  84. if options.Options.KernelTx {
  85. options.Logger.Warn("enabling kTLS TX in current scenarios will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_tx")
  86. }
  87. }
  88. if options.Options.KernelRx {
  89. options.Logger.Warn("enabling kTLS RX will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_rx")
  90. }
  91. switch options.Options.Engine {
  92. case C.TLSEngineDefault, "go":
  93. case C.TLSEngineApple:
  94. return newAppleClient(options.Context, options.Logger, options.ServerAddress, options.Options, options.AllowEmptyServerName)
  95. default:
  96. return nil, E.New("unknown tls engine: ", options.Options.Engine)
  97. }
  98. if options.Options.Reality != nil && options.Options.Reality.Enabled {
  99. return newRealityClient(options.Context, options.Logger, options.ServerAddress, options.Options, options.AllowEmptyServerName)
  100. } else if options.Options.UTLS != nil && options.Options.UTLS.Enabled {
  101. return newUTLSClient(options.Context, options.Logger, options.ServerAddress, options.Options, options.AllowEmptyServerName)
  102. }
  103. return newSTDClient(options.Context, options.Logger, options.ServerAddress, options.Options, options.AllowEmptyServerName)
  104. }
  105. func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) {
  106. tlsConn, err := aTLS.ClientHandshake(ctx, conn, config)
  107. if err != nil {
  108. return nil, err
  109. }
  110. readWaitConn, err := badtls.NewReadWaitConn(tlsConn)
  111. if err == nil {
  112. return readWaitConn, nil
  113. } else if err != os.ErrInvalid {
  114. return nil, err
  115. }
  116. return tlsConn, nil
  117. }
  118. type Dialer interface {
  119. N.Dialer
  120. DialTLSContext(ctx context.Context, destination M.Socksaddr) (Conn, error)
  121. }
  122. type defaultDialer struct {
  123. dialer N.Dialer
  124. config Config
  125. }
  126. func NewDialer(dialer N.Dialer, config Config) Dialer {
  127. return &defaultDialer{dialer, config}
  128. }
  129. func (d *defaultDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  130. if N.NetworkName(network) != N.NetworkTCP {
  131. return nil, os.ErrInvalid
  132. }
  133. return d.DialTLSContext(ctx, destination)
  134. }
  135. func (d *defaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  136. return nil, os.ErrInvalid
  137. }
  138. func (d *defaultDialer) DialTLSContext(ctx context.Context, destination M.Socksaddr) (Conn, error) {
  139. return d.dialContext(ctx, destination, true)
  140. }
  141. func (d *defaultDialer) dialContext(ctx context.Context, destination M.Socksaddr, echRetry bool) (Conn, error) {
  142. conn, err := d.dialer.DialContext(ctx, N.NetworkTCP, destination)
  143. if err != nil {
  144. return nil, err
  145. }
  146. tlsConn, err := aTLS.ClientHandshake(ctx, conn, d.config)
  147. if err != nil {
  148. conn.Close()
  149. var echErr *tls.ECHRejectionError
  150. if echRetry && errors.As(err, &echErr) && len(echErr.RetryConfigList) > 0 {
  151. if echConfig, isECH := d.config.(ECHCapableConfig); isECH {
  152. echConfig.SetECHConfigList(echErr.RetryConfigList)
  153. return d.dialContext(ctx, destination, false)
  154. }
  155. }
  156. return nil, err
  157. }
  158. return tlsConn, nil
  159. }
  160. func (d *defaultDialer) Upstream() any {
  161. return d.dialer
  162. }