outbound.go 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. package direct
  2. import (
  3. "context"
  4. "net"
  5. "net/netip"
  6. "reflect"
  7. "time"
  8. "github.com/sagernet/sing-box/adapter"
  9. "github.com/sagernet/sing-box/adapter/outbound"
  10. "github.com/sagernet/sing-box/common/dialer"
  11. C "github.com/sagernet/sing-box/constant"
  12. "github.com/sagernet/sing-box/log"
  13. "github.com/sagernet/sing-box/option"
  14. "github.com/sagernet/sing/common"
  15. "github.com/sagernet/sing/common/bufio"
  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.DirectOutboundOptions](registry, C.TypeDirect, NewOutbound)
  23. }
  24. var (
  25. _ N.ParallelDialer = (*Outbound)(nil)
  26. _ dialer.ParallelNetworkDialer = (*Outbound)(nil)
  27. _ dialer.DirectDialer = (*Outbound)(nil)
  28. )
  29. type Outbound struct {
  30. outbound.Adapter
  31. logger logger.ContextLogger
  32. dialer dialer.ParallelInterfaceDialer
  33. domainStrategy C.DomainStrategy
  34. fallbackDelay time.Duration
  35. overrideOption int
  36. overrideDestination M.Socksaddr
  37. isEmpty bool
  38. // loopBack *loopBackDetector
  39. }
  40. func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.DirectOutboundOptions) (adapter.Outbound, error) {
  41. options.UDPFragmentDefault = true
  42. if options.Detour != "" {
  43. return nil, E.New("`detour` is not supported in direct context")
  44. }
  45. outboundDialer, err := dialer.NewWithOptions(dialer.Options{
  46. Context: ctx,
  47. Options: options.DialerOptions,
  48. RemoteIsDomain: true,
  49. DirectOutbound: true,
  50. })
  51. if err != nil {
  52. return nil, err
  53. }
  54. outbound := &Outbound{
  55. Adapter: outbound.NewAdapterWithDialerOptions(C.TypeDirect, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
  56. logger: logger,
  57. //nolint:staticcheck
  58. domainStrategy: C.DomainStrategy(options.DomainStrategy),
  59. fallbackDelay: time.Duration(options.FallbackDelay),
  60. dialer: outboundDialer.(dialer.ParallelInterfaceDialer),
  61. //nolint:staticcheck
  62. isEmpty: reflect.DeepEqual(options.DialerOptions, option.DialerOptions{UDPFragmentDefault: true}) && options.OverrideAddress == "" && options.OverridePort == 0,
  63. // loopBack: newLoopBackDetector(router),
  64. }
  65. //nolint:staticcheck
  66. if options.ProxyProtocol != 0 {
  67. return nil, E.New("Proxy Protocol is deprecated and removed in sing-box 1.6.0")
  68. }
  69. //nolint:staticcheck
  70. if options.OverrideAddress != "" && options.OverridePort != 0 {
  71. outbound.overrideOption = 1
  72. outbound.overrideDestination = M.ParseSocksaddrHostPort(options.OverrideAddress, options.OverridePort)
  73. } else if options.OverrideAddress != "" {
  74. outbound.overrideOption = 2
  75. outbound.overrideDestination = M.ParseSocksaddrHostPort(options.OverrideAddress, options.OverridePort)
  76. } else if options.OverridePort != 0 {
  77. outbound.overrideOption = 3
  78. outbound.overrideDestination = M.Socksaddr{Port: options.OverridePort}
  79. }
  80. return outbound, nil
  81. }
  82. func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  83. ctx, metadata := adapter.ExtendContext(ctx)
  84. metadata.Outbound = h.Tag()
  85. metadata.Destination = destination
  86. switch h.overrideOption {
  87. case 1:
  88. destination = h.overrideDestination
  89. case 2:
  90. newDestination := h.overrideDestination
  91. newDestination.Port = destination.Port
  92. destination = newDestination
  93. case 3:
  94. destination.Port = h.overrideDestination.Port
  95. }
  96. network = N.NetworkName(network)
  97. switch network {
  98. case N.NetworkTCP:
  99. h.logger.InfoContext(ctx, "outbound connection to ", destination)
  100. case N.NetworkUDP:
  101. h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  102. }
  103. /*conn, err := h.dialer.DialContext(ctx, network, destination)
  104. if err != nil {
  105. return nil, err
  106. }
  107. return h.loopBack.NewConn(conn), nil*/
  108. return h.dialer.DialContext(ctx, network, destination)
  109. }
  110. func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  111. ctx, metadata := adapter.ExtendContext(ctx)
  112. metadata.Outbound = h.Tag()
  113. metadata.Destination = destination
  114. originDestination := destination
  115. switch h.overrideOption {
  116. case 1:
  117. destination = h.overrideDestination
  118. case 2:
  119. newDestination := h.overrideDestination
  120. newDestination.Port = destination.Port
  121. destination = newDestination
  122. case 3:
  123. destination.Port = h.overrideDestination.Port
  124. }
  125. if h.overrideOption == 0 {
  126. h.logger.InfoContext(ctx, "outbound packet connection")
  127. } else {
  128. h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  129. }
  130. conn, err := h.dialer.ListenPacket(ctx, destination)
  131. if err != nil {
  132. return nil, err
  133. }
  134. // conn = h.loopBack.NewPacketConn(bufio.NewPacketConn(conn), destination)
  135. if originDestination != destination {
  136. conn = bufio.NewNATPacketConn(bufio.NewPacketConn(conn), destination, originDestination)
  137. }
  138. return conn, nil
  139. }
  140. func (h *Outbound) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
  141. ctx, metadata := adapter.ExtendContext(ctx)
  142. metadata.Outbound = h.Tag()
  143. metadata.Destination = destination
  144. switch h.overrideOption {
  145. case 1, 2:
  146. // override address
  147. return h.DialContext(ctx, network, destination)
  148. case 3:
  149. destination.Port = h.overrideDestination.Port
  150. }
  151. network = N.NetworkName(network)
  152. switch network {
  153. case N.NetworkTCP:
  154. h.logger.InfoContext(ctx, "outbound connection to ", destination)
  155. case N.NetworkUDP:
  156. h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  157. }
  158. var domainStrategy C.DomainStrategy
  159. if h.domainStrategy != C.DomainStrategyAsIS {
  160. domainStrategy = h.domainStrategy
  161. } else {
  162. //nolint:staticcheck
  163. domainStrategy = C.DomainStrategy(metadata.InboundOptions.DomainStrategy)
  164. }
  165. switch domainStrategy {
  166. case C.DomainStrategyIPv4Only:
  167. destinationAddresses = common.Filter(destinationAddresses, netip.Addr.Is4)
  168. if len(destinationAddresses) == 0 {
  169. return nil, E.New("no IPv4 address available for ", destination)
  170. }
  171. case C.DomainStrategyIPv6Only:
  172. destinationAddresses = common.Filter(destinationAddresses, netip.Addr.Is6)
  173. if len(destinationAddresses) == 0 {
  174. return nil, E.New("no IPv6 address available for ", destination)
  175. }
  176. }
  177. return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == C.DomainStrategyPreferIPv6, nil, nil, nil, h.fallbackDelay)
  178. }
  179. func (h *Outbound) DialParallelNetwork(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.Conn, error) {
  180. ctx, metadata := adapter.ExtendContext(ctx)
  181. metadata.Outbound = h.Tag()
  182. metadata.Destination = destination
  183. switch h.overrideOption {
  184. case 1, 2:
  185. // override address
  186. return h.DialContext(ctx, network, destination)
  187. case 3:
  188. destination.Port = h.overrideDestination.Port
  189. }
  190. network = N.NetworkName(network)
  191. switch network {
  192. case N.NetworkTCP:
  193. h.logger.InfoContext(ctx, "outbound connection to ", destination)
  194. case N.NetworkUDP:
  195. h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  196. }
  197. var domainStrategy C.DomainStrategy
  198. if h.domainStrategy != C.DomainStrategyAsIS {
  199. domainStrategy = h.domainStrategy
  200. } else {
  201. //nolint:staticcheck
  202. domainStrategy = C.DomainStrategy(metadata.InboundOptions.DomainStrategy)
  203. }
  204. switch domainStrategy {
  205. case C.DomainStrategyIPv4Only:
  206. destinationAddresses = common.Filter(destinationAddresses, netip.Addr.Is4)
  207. if len(destinationAddresses) == 0 {
  208. return nil, E.New("no IPv4 address available for ", destination)
  209. }
  210. case C.DomainStrategyIPv6Only:
  211. destinationAddresses = common.Filter(destinationAddresses, netip.Addr.Is6)
  212. if len(destinationAddresses) == 0 {
  213. return nil, E.New("no IPv6 address available for ", destination)
  214. }
  215. }
  216. return dialer.DialParallelNetwork(ctx, h.dialer, network, destination, destinationAddresses, domainStrategy == C.DomainStrategyPreferIPv6, networkStrategy, networkType, fallbackNetworkType, fallbackDelay)
  217. }
  218. func (h *Outbound) ListenSerialNetworkPacket(ctx context.Context, destination M.Socksaddr, destinationAddresses []netip.Addr, networkStrategy *C.NetworkStrategy, networkType []C.InterfaceType, fallbackNetworkType []C.InterfaceType, fallbackDelay time.Duration) (net.PacketConn, netip.Addr, error) {
  219. ctx, metadata := adapter.ExtendContext(ctx)
  220. metadata.Outbound = h.Tag()
  221. metadata.Destination = destination
  222. switch h.overrideOption {
  223. case 1:
  224. destination = h.overrideDestination
  225. case 2:
  226. newDestination := h.overrideDestination
  227. newDestination.Port = destination.Port
  228. destination = newDestination
  229. case 3:
  230. destination.Port = h.overrideDestination.Port
  231. }
  232. if h.overrideOption == 0 {
  233. h.logger.InfoContext(ctx, "outbound packet connection")
  234. } else {
  235. h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  236. }
  237. conn, newDestination, err := dialer.ListenSerialNetworkPacket(ctx, h.dialer, destination, destinationAddresses, networkStrategy, networkType, fallbackNetworkType, fallbackDelay)
  238. if err != nil {
  239. return nil, netip.Addr{}, err
  240. }
  241. return conn, newDestination, nil
  242. }
  243. func (h *Outbound) IsEmpty() bool {
  244. return h.isEmpty
  245. }
  246. /*func (h *Outbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
  247. if h.loopBack.CheckConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
  248. return E.New("reject loopback connection to ", metadata.Destination)
  249. }
  250. return NewConnection(ctx, h, conn, metadata)
  251. }
  252. func (h *Outbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
  253. if h.loopBack.CheckPacketConn(metadata.Source.AddrPort(), M.AddrPortFromNet(conn.LocalAddr())) {
  254. return E.New("reject loopback packet connection to ", metadata.Destination)
  255. }
  256. return NewPacketConnection(ctx, h, conn, metadata)
  257. }
  258. */