client.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. package tls
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "errors"
  6. "net"
  7. "os"
  8. "github.com/sagernet/sing-box/common/badtls"
  9. C "github.com/sagernet/sing-box/constant"
  10. "github.com/sagernet/sing-box/option"
  11. "github.com/sagernet/sing/common/logger"
  12. M "github.com/sagernet/sing/common/metadata"
  13. N "github.com/sagernet/sing/common/network"
  14. aTLS "github.com/sagernet/sing/common/tls"
  15. )
  16. func NewDialerFromOptions(ctx context.Context, logger logger.ContextLogger, dialer N.Dialer, serverAddress string, options option.OutboundTLSOptions) (N.Dialer, error) {
  17. if !options.Enabled {
  18. return dialer, nil
  19. }
  20. config, err := NewClientWithOptions(ClientOptions{
  21. Context: ctx,
  22. Logger: logger,
  23. ServerAddress: serverAddress,
  24. Options: options,
  25. })
  26. if err != nil {
  27. return nil, err
  28. }
  29. return NewDialer(dialer, config), nil
  30. }
  31. func NewClient(ctx context.Context, logger logger.ContextLogger, serverAddress string, options option.OutboundTLSOptions) (Config, error) {
  32. return NewClientWithOptions(ClientOptions{
  33. Context: ctx,
  34. Logger: logger,
  35. ServerAddress: serverAddress,
  36. Options: options,
  37. })
  38. }
  39. type ClientOptions struct {
  40. Context context.Context
  41. Logger logger.ContextLogger
  42. ServerAddress string
  43. Options option.OutboundTLSOptions
  44. KTLSCompatible bool
  45. }
  46. func NewClientWithOptions(options ClientOptions) (Config, error) {
  47. if !options.Options.Enabled {
  48. return nil, nil
  49. }
  50. if !options.KTLSCompatible {
  51. if options.Options.KernelTx {
  52. 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")
  53. }
  54. }
  55. if options.Options.KernelRx {
  56. options.Logger.Warn("enabling kTLS RX will definitely reduce performance, please checkout https://sing-box.sagernet.org/configuration/shared/tls/#kernel_rx")
  57. }
  58. if options.Options.Reality != nil && options.Options.Reality.Enabled {
  59. return NewRealityClient(options.Context, options.Logger, options.ServerAddress, options.Options)
  60. } else if options.Options.UTLS != nil && options.Options.UTLS.Enabled {
  61. return NewUTLSClient(options.Context, options.Logger, options.ServerAddress, options.Options)
  62. }
  63. return NewSTDClient(options.Context, options.Logger, options.ServerAddress, options.Options)
  64. }
  65. func ClientHandshake(ctx context.Context, conn net.Conn, config Config) (Conn, error) {
  66. ctx, cancel := context.WithTimeout(ctx, C.TCPTimeout)
  67. defer cancel()
  68. tlsConn, err := aTLS.ClientHandshake(ctx, conn, config)
  69. if err != nil {
  70. return nil, err
  71. }
  72. readWaitConn, err := badtls.NewReadWaitConn(tlsConn)
  73. if err == nil {
  74. return readWaitConn, nil
  75. } else if err != os.ErrInvalid {
  76. return nil, err
  77. }
  78. return tlsConn, nil
  79. }
  80. type Dialer interface {
  81. N.Dialer
  82. DialTLSContext(ctx context.Context, destination M.Socksaddr) (Conn, error)
  83. }
  84. type defaultDialer struct {
  85. dialer N.Dialer
  86. config Config
  87. }
  88. func NewDialer(dialer N.Dialer, config Config) Dialer {
  89. return &defaultDialer{dialer, config}
  90. }
  91. func (d *defaultDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  92. if N.NetworkName(network) != N.NetworkTCP {
  93. return nil, os.ErrInvalid
  94. }
  95. return d.DialTLSContext(ctx, destination)
  96. }
  97. func (d *defaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  98. return nil, os.ErrInvalid
  99. }
  100. func (d *defaultDialer) DialTLSContext(ctx context.Context, destination M.Socksaddr) (Conn, error) {
  101. return d.dialContext(ctx, destination, true)
  102. }
  103. func (d *defaultDialer) dialContext(ctx context.Context, destination M.Socksaddr, echRetry bool) (Conn, error) {
  104. conn, err := d.dialer.DialContext(ctx, N.NetworkTCP, destination)
  105. if err != nil {
  106. return nil, err
  107. }
  108. tlsConn, err := ClientHandshake(ctx, conn, d.config)
  109. if err == nil {
  110. return tlsConn, nil
  111. }
  112. conn.Close()
  113. if echRetry {
  114. var echErr *tls.ECHRejectionError
  115. if errors.As(err, &echErr) && len(echErr.RetryConfigList) > 0 {
  116. if echConfig, isECH := d.config.(ECHCapableConfig); isECH {
  117. echConfig.SetECHConfigList(echErr.RetryConfigList)
  118. }
  119. }
  120. return d.dialContext(ctx, destination, false)
  121. }
  122. return nil, err
  123. }
  124. func (d *defaultDialer) Upstream() any {
  125. return d.dialer
  126. }