outbound.go 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. //go:build with_naive_outbound
  2. package naive
  3. import (
  4. "context"
  5. "encoding/pem"
  6. "net"
  7. "os"
  8. "strings"
  9. "github.com/sagernet/cronet-go"
  10. _ "github.com/sagernet/cronet-go/all"
  11. "github.com/sagernet/sing-box/adapter"
  12. "github.com/sagernet/sing-box/adapter/outbound"
  13. "github.com/sagernet/sing-box/common/dialer"
  14. C "github.com/sagernet/sing-box/constant"
  15. "github.com/sagernet/sing-box/dns"
  16. "github.com/sagernet/sing-box/log"
  17. "github.com/sagernet/sing-box/option"
  18. "github.com/sagernet/sing/common"
  19. E "github.com/sagernet/sing/common/exceptions"
  20. "github.com/sagernet/sing/common/logger"
  21. M "github.com/sagernet/sing/common/metadata"
  22. N "github.com/sagernet/sing/common/network"
  23. "github.com/sagernet/sing/common/uot"
  24. "github.com/sagernet/sing/service"
  25. mDNS "github.com/miekg/dns"
  26. )
  27. func RegisterOutbound(registry *outbound.Registry) {
  28. outbound.Register[option.NaiveOutboundOptions](registry, C.TypeNaive, NewOutbound)
  29. }
  30. type Outbound struct {
  31. outbound.Adapter
  32. ctx context.Context
  33. logger logger.ContextLogger
  34. client *cronet.NaiveClient
  35. uotClient *uot.Client
  36. }
  37. func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NaiveOutboundOptions) (adapter.Outbound, error) {
  38. if options.TLS == nil || !options.TLS.Enabled {
  39. return nil, C.ErrTLSRequired
  40. }
  41. if options.TLS.DisableSNI {
  42. return nil, E.New("disable_sni is not supported on naive outbound")
  43. }
  44. if options.TLS.Insecure {
  45. return nil, E.New("insecure is not supported on naive outbound")
  46. }
  47. if len(options.TLS.ALPN) > 0 {
  48. return nil, E.New("alpn is not supported on naive outbound")
  49. }
  50. if options.TLS.MinVersion != "" {
  51. return nil, E.New("min_version is not supported on naive outbound")
  52. }
  53. if options.TLS.MaxVersion != "" {
  54. return nil, E.New("max_version is not supported on naive outbound")
  55. }
  56. if len(options.TLS.CipherSuites) > 0 {
  57. return nil, E.New("cipher_suites is not supported on naive outbound")
  58. }
  59. if len(options.TLS.CurvePreferences) > 0 {
  60. return nil, E.New("curve_preferences is not supported on naive outbound")
  61. }
  62. if len(options.TLS.ClientCertificate) > 0 || options.TLS.ClientCertificatePath != "" {
  63. return nil, E.New("client_certificate is not supported on naive outbound")
  64. }
  65. if len(options.TLS.ClientKey) > 0 || options.TLS.ClientKeyPath != "" {
  66. return nil, E.New("client_key is not supported on naive outbound")
  67. }
  68. if options.TLS.Fragment || options.TLS.RecordFragment {
  69. return nil, E.New("fragment is not supported on naive outbound")
  70. }
  71. if options.TLS.KernelTx || options.TLS.KernelRx {
  72. return nil, E.New("kernel TLS is not supported on naive outbound")
  73. }
  74. if options.TLS.UTLS != nil && options.TLS.UTLS.Enabled {
  75. return nil, E.New("uTLS is not supported on naive outbound")
  76. }
  77. if options.TLS.Reality != nil && options.TLS.Reality.Enabled {
  78. return nil, E.New("reality is not supported on naive outbound")
  79. }
  80. serverAddress := options.ServerOptions.Build()
  81. var serverName string
  82. if options.TLS.ServerName != "" {
  83. serverName = options.TLS.ServerName
  84. } else {
  85. serverName = serverAddress.AddrString()
  86. }
  87. outboundDialer, err := dialer.NewWithOptions(dialer.Options{
  88. Context: ctx,
  89. Options: options.DialerOptions,
  90. RemoteIsDomain: true,
  91. ResolverOnDetour: true,
  92. NewDialer: true,
  93. })
  94. if err != nil {
  95. return nil, err
  96. }
  97. var trustedRootCertificates string
  98. if len(options.TLS.Certificate) > 0 {
  99. trustedRootCertificates = strings.Join(options.TLS.Certificate, "\n")
  100. } else if options.TLS.CertificatePath != "" {
  101. content, err := os.ReadFile(options.TLS.CertificatePath)
  102. if err != nil {
  103. return nil, E.Cause(err, "read certificate")
  104. }
  105. trustedRootCertificates = string(content)
  106. }
  107. extraHeaders := make(map[string]string)
  108. for key, values := range options.ExtraHeaders.Build() {
  109. if len(values) > 0 {
  110. extraHeaders[key] = values[0]
  111. }
  112. }
  113. dnsRouter := service.FromContext[adapter.DNSRouter](ctx)
  114. var dnsResolver cronet.DNSResolverFunc
  115. if dnsRouter != nil {
  116. dnsResolver = func(dnsContext context.Context, request *mDNS.Msg) *mDNS.Msg {
  117. response, err := dnsRouter.Exchange(dnsContext, request, adapter.DNSQueryOptions{})
  118. if err != nil {
  119. logger.Error("DNS exchange failed: ", err)
  120. return dns.FixedResponseStatus(request, mDNS.RcodeServerFailure)
  121. }
  122. return response
  123. }
  124. }
  125. var echEnabled bool
  126. var echConfigList []byte
  127. var echQueryServerName string
  128. if options.TLS.ECH != nil && options.TLS.ECH.Enabled {
  129. echEnabled = true
  130. echQueryServerName = options.TLS.ECH.QueryServerName
  131. var echConfig []byte
  132. if len(options.TLS.ECH.Config) > 0 {
  133. echConfig = []byte(strings.Join(options.TLS.ECH.Config, "\n"))
  134. } else if options.TLS.ECH.ConfigPath != "" {
  135. content, err := os.ReadFile(options.TLS.ECH.ConfigPath)
  136. if err != nil {
  137. return nil, E.Cause(err, "read ECH config")
  138. }
  139. echConfig = content
  140. }
  141. if len(echConfig) > 0 {
  142. block, rest := pem.Decode(echConfig)
  143. if block == nil || block.Type != "ECH CONFIGS" || len(rest) > 0 {
  144. return nil, E.New("invalid ECH configs pem")
  145. }
  146. echConfigList = block.Bytes
  147. }
  148. }
  149. var quicCongestionControl cronet.QUICCongestionControl
  150. switch options.QUICCongestionControl {
  151. case "":
  152. quicCongestionControl = cronet.QUICCongestionControlDefault
  153. case "bbr":
  154. quicCongestionControl = cronet.QUICCongestionControlBBR
  155. case "bbr2":
  156. quicCongestionControl = cronet.QUICCongestionControlBBRv2
  157. case "cubic":
  158. quicCongestionControl = cronet.QUICCongestionControlCubic
  159. case "reno":
  160. quicCongestionControl = cronet.QUICCongestionControlReno
  161. default:
  162. return nil, E.New("unknown quic congestion control: ", options.QUICCongestionControl)
  163. }
  164. client, err := cronet.NewNaiveClient(cronet.NaiveClientOptions{
  165. Context: ctx,
  166. ServerAddress: serverAddress,
  167. ServerName: serverName,
  168. Username: options.Username,
  169. Password: options.Password,
  170. InsecureConcurrency: options.InsecureConcurrency,
  171. ExtraHeaders: extraHeaders,
  172. TrustedRootCertificates: trustedRootCertificates,
  173. Dialer: outboundDialer,
  174. DNSResolver: dnsResolver,
  175. ECHEnabled: echEnabled,
  176. ECHConfigList: echConfigList,
  177. ECHQueryServerName: echQueryServerName,
  178. QUIC: options.QUIC,
  179. QUICCongestionControl: quicCongestionControl,
  180. })
  181. if err != nil {
  182. return nil, err
  183. }
  184. var uotClient *uot.Client
  185. uotOptions := common.PtrValueOrDefault(options.UDPOverTCP)
  186. if uotOptions.Enabled {
  187. uotClient = &uot.Client{
  188. Dialer: &naiveDialer{client},
  189. Version: uotOptions.Version,
  190. }
  191. }
  192. var networks []string
  193. if uotClient != nil {
  194. networks = []string{N.NetworkTCP, N.NetworkUDP}
  195. } else {
  196. networks = []string{N.NetworkTCP}
  197. }
  198. return &Outbound{
  199. Adapter: outbound.NewAdapterWithDialerOptions(C.TypeNaive, tag, networks, options.DialerOptions),
  200. ctx: ctx,
  201. logger: logger,
  202. client: client,
  203. uotClient: uotClient,
  204. }, nil
  205. }
  206. func (h *Outbound) Start(stage adapter.StartStage) error {
  207. if stage != adapter.StartStateStart {
  208. return nil
  209. }
  210. err := h.client.Start()
  211. if err != nil {
  212. return err
  213. }
  214. h.logger.Info("NaiveProxy started, version: ", h.client.Engine().Version())
  215. return nil
  216. }
  217. func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  218. switch N.NetworkName(network) {
  219. case N.NetworkTCP:
  220. h.logger.InfoContext(ctx, "outbound connection to ", destination)
  221. return h.client.DialEarly(destination)
  222. case N.NetworkUDP:
  223. if h.uotClient == nil {
  224. return nil, E.New("UDP is not supported unless UDP over TCP is enabled")
  225. }
  226. h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
  227. return h.uotClient.DialContext(ctx, network, destination)
  228. default:
  229. return nil, E.Extend(N.ErrUnknownNetwork, network)
  230. }
  231. }
  232. func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  233. if h.uotClient == nil {
  234. return nil, E.New("UDP is not supported unless UDP over TCP is enabled")
  235. }
  236. return h.uotClient.ListenPacket(ctx, destination)
  237. }
  238. func (h *Outbound) Close() error {
  239. return h.client.Close()
  240. }
  241. func (h *Outbound) Client() *cronet.NaiveClient {
  242. return h.client
  243. }
  244. type naiveDialer struct {
  245. *cronet.NaiveClient
  246. }
  247. func (d *naiveDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  248. return d.NaiveClient.DialEarly(destination)
  249. }