outbound.go 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. //go:build with_naive_outbound
  2. package naive
  3. import (
  4. "context"
  5. "net"
  6. "os"
  7. "strings"
  8. "github.com/sagernet/cronet-go"
  9. _ "github.com/sagernet/cronet-go/all"
  10. "github.com/sagernet/sing-box/adapter"
  11. "github.com/sagernet/sing-box/adapter/outbound"
  12. "github.com/sagernet/sing-box/common/dialer"
  13. C "github.com/sagernet/sing-box/constant"
  14. "github.com/sagernet/sing-box/log"
  15. "github.com/sagernet/sing-box/option"
  16. E "github.com/sagernet/sing/common/exceptions"
  17. "github.com/sagernet/sing/common/logger"
  18. M "github.com/sagernet/sing/common/metadata"
  19. N "github.com/sagernet/sing/common/network"
  20. )
  21. func RegisterOutbound(registry *outbound.Registry) {
  22. outbound.Register[option.NaiveOutboundOptions](registry, C.TypeNaive, NewOutbound)
  23. }
  24. type Outbound struct {
  25. outbound.Adapter
  26. ctx context.Context
  27. logger logger.ContextLogger
  28. client *cronet.NaiveClient
  29. }
  30. func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NaiveOutboundOptions) (adapter.Outbound, error) {
  31. if options.TLS == nil || !options.TLS.Enabled {
  32. return nil, C.ErrTLSRequired
  33. }
  34. if options.TLS.DisableSNI {
  35. return nil, E.New("disable_sni is not supported on naive outbound")
  36. }
  37. if options.TLS.Insecure {
  38. return nil, E.New("insecure is not supported on naive outbound")
  39. }
  40. if len(options.TLS.ALPN) > 0 {
  41. return nil, E.New("alpn is not supported on naive outbound")
  42. }
  43. if options.TLS.MinVersion != "" {
  44. return nil, E.New("min_version is not supported on naive outbound")
  45. }
  46. if options.TLS.MaxVersion != "" {
  47. return nil, E.New("max_version is not supported on naive outbound")
  48. }
  49. if len(options.TLS.CipherSuites) > 0 {
  50. return nil, E.New("cipher_suites is not supported on naive outbound")
  51. }
  52. if len(options.TLS.CurvePreferences) > 0 {
  53. return nil, E.New("curve_preferences is not supported on naive outbound")
  54. }
  55. if len(options.TLS.ClientCertificate) > 0 || options.TLS.ClientCertificatePath != "" {
  56. return nil, E.New("client_certificate is not supported on naive outbound")
  57. }
  58. if len(options.TLS.ClientKey) > 0 || options.TLS.ClientKeyPath != "" {
  59. return nil, E.New("client_key is not supported on naive outbound")
  60. }
  61. if options.TLS.Fragment || options.TLS.RecordFragment {
  62. return nil, E.New("fragment is not supported on naive outbound")
  63. }
  64. if options.TLS.KernelTx || options.TLS.KernelRx {
  65. return nil, E.New("kernel TLS is not supported on naive outbound")
  66. }
  67. if options.TLS.ECH != nil && options.TLS.ECH.Enabled {
  68. return nil, E.New("ECH is not currently supported on naive outbound")
  69. }
  70. if options.TLS.UTLS != nil && options.TLS.UTLS.Enabled {
  71. return nil, E.New("uTLS is not supported on naive outbound")
  72. }
  73. if options.TLS.Reality != nil && options.TLS.Reality.Enabled {
  74. return nil, E.New("reality is not supported on naive outbound")
  75. }
  76. serverAddress := options.ServerOptions.Build()
  77. var serverName string
  78. if options.TLS.ServerName != "" {
  79. serverName = options.TLS.ServerName
  80. } else {
  81. serverName = serverAddress.AddrString()
  82. }
  83. outboundDialer, err := dialer.NewWithOptions(dialer.Options{
  84. Context: ctx,
  85. Options: options.DialerOptions,
  86. RemoteIsDomain: true,
  87. ResolverOnDetour: true,
  88. NewDialer: true,
  89. })
  90. if err != nil {
  91. return nil, err
  92. }
  93. var trustedRootCertificates string
  94. if len(options.TLS.Certificate) > 0 {
  95. trustedRootCertificates = strings.Join(options.TLS.Certificate, "\n")
  96. } else if options.TLS.CertificatePath != "" {
  97. content, err := os.ReadFile(options.TLS.CertificatePath)
  98. if err != nil {
  99. return nil, E.Cause(err, "read certificate")
  100. }
  101. trustedRootCertificates = string(content)
  102. }
  103. extraHeaders := make(map[string]string)
  104. for key, values := range options.ExtraHeaders.Build() {
  105. if len(values) > 0 {
  106. extraHeaders[key] = values[0]
  107. }
  108. }
  109. client, err := cronet.NewNaiveClient(cronet.NaiveClientConfig{
  110. Context: ctx,
  111. ServerAddress: serverAddress,
  112. ServerName: serverName,
  113. Username: options.Username,
  114. Password: options.Password,
  115. Concurrency: options.InsecureConcurrency,
  116. ExtraHeaders: extraHeaders,
  117. TrustedRootCertificates: trustedRootCertificates,
  118. CertificatePublicKeySHA256: options.TLS.CertificatePublicKeySHA256,
  119. Dialer: outboundDialer,
  120. })
  121. if err != nil {
  122. return nil, err
  123. }
  124. return &Outbound{
  125. Adapter: outbound.NewAdapterWithDialerOptions(C.TypeNaive, tag, []string{N.NetworkTCP}, options.DialerOptions),
  126. ctx: ctx,
  127. logger: logger,
  128. client: client,
  129. }, nil
  130. }
  131. func (o *Outbound) Start(stage adapter.StartStage) error {
  132. if stage != adapter.StartStateStart {
  133. return nil
  134. }
  135. err := o.client.Start()
  136. if err != nil {
  137. return err
  138. }
  139. o.logger.Info("NaiveProxy started, version: ", o.client.Engine().Version())
  140. return nil
  141. }
  142. func (o *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  143. ctx, metadata := adapter.ExtendContext(ctx)
  144. metadata.Outbound = o.Tag()
  145. metadata.Destination = destination
  146. o.logger.InfoContext(ctx, "outbound connection to ", destination)
  147. return o.client.DialContext(ctx, destination)
  148. }
  149. func (o *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  150. return nil, os.ErrInvalid
  151. }
  152. func (o *Outbound) Close() error {
  153. return o.client.Close()
  154. }
  155. func (o *Outbound) StartNetLogToFile(fileName string, logAll bool) bool {
  156. return o.client.Engine().StartNetLogToFile(fileName, logAll)
  157. }
  158. func (o *Outbound) StopNetLog() {
  159. o.client.Engine().StopNetLog()
  160. }