outbound.go 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. package socks
  2. import (
  3. "context"
  4. "net"
  5. "github.com/sagernet/sing-box/adapter"
  6. "github.com/sagernet/sing-box/adapter/outbound"
  7. "github.com/sagernet/sing-box/common/dialer"
  8. C "github.com/sagernet/sing-box/constant"
  9. "github.com/sagernet/sing-box/log"
  10. "github.com/sagernet/sing-box/option"
  11. "github.com/sagernet/sing/common"
  12. E "github.com/sagernet/sing/common/exceptions"
  13. "github.com/sagernet/sing/common/logger"
  14. M "github.com/sagernet/sing/common/metadata"
  15. N "github.com/sagernet/sing/common/network"
  16. "github.com/sagernet/sing/common/uot"
  17. "github.com/sagernet/sing/protocol/socks"
  18. )
  19. func RegisterOutbound(registry *outbound.Registry) {
  20. outbound.Register[option.SOCKSOutboundOptions](registry, C.TypeSOCKS, NewOutbound)
  21. }
  22. var _ adapter.Outbound = (*Outbound)(nil)
  23. type Outbound struct {
  24. outbound.Adapter
  25. router adapter.Router
  26. logger logger.ContextLogger
  27. client *socks.Client
  28. resolve bool
  29. uotClient *uot.Client
  30. }
  31. func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SOCKSOutboundOptions) (adapter.Outbound, error) {
  32. var version socks.Version
  33. var err error
  34. if options.Version != "" {
  35. version, err = socks.ParseVersion(options.Version)
  36. } else {
  37. version = socks.Version5
  38. }
  39. if err != nil {
  40. return nil, err
  41. }
  42. outboundDialer, err := dialer.New(ctx, options.DialerOptions)
  43. if err != nil {
  44. return nil, err
  45. }
  46. outbound := &Outbound{
  47. Adapter: outbound.NewAdapterWithDialerOptions(C.TypeSOCKS, options.Network.Build(), tag, options.DialerOptions),
  48. router: router,
  49. logger: logger,
  50. client: socks.NewClient(outboundDialer, options.ServerOptions.Build(), version, options.Username, options.Password),
  51. resolve: version == socks.Version4,
  52. }
  53. uotOptions := common.PtrValueOrDefault(options.UDPOverTCP)
  54. if uotOptions.Enabled {
  55. outbound.uotClient = &uot.Client{
  56. Dialer: outbound.client,
  57. Version: uotOptions.Version,
  58. }
  59. }
  60. return outbound, nil
  61. }
  62. func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
  63. ctx, metadata := adapter.ExtendContext(ctx)
  64. metadata.Outbound = h.Tag()
  65. metadata.Destination = destination
  66. switch N.NetworkName(network) {
  67. case N.NetworkTCP:
  68. h.logger.InfoContext(ctx, "outbound connection to ", destination)
  69. case N.NetworkUDP:
  70. if h.uotClient != nil {
  71. h.logger.InfoContext(ctx, "outbound UoT connect packet connection to ", destination)
  72. return h.uotClient.DialContext(ctx, network, destination)
  73. }
  74. h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  75. default:
  76. return nil, E.Extend(N.ErrUnknownNetwork, network)
  77. }
  78. if h.resolve && destination.IsFqdn() {
  79. destinationAddresses, err := h.router.LookupDefault(ctx, destination.Fqdn)
  80. if err != nil {
  81. return nil, err
  82. }
  83. return N.DialSerial(ctx, h.client, network, destination, destinationAddresses)
  84. }
  85. return h.client.DialContext(ctx, network, destination)
  86. }
  87. func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
  88. ctx, metadata := adapter.ExtendContext(ctx)
  89. metadata.Outbound = h.Tag()
  90. metadata.Destination = destination
  91. if h.uotClient != nil {
  92. h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
  93. return h.uotClient.ListenPacket(ctx, destination)
  94. }
  95. if h.resolve && destination.IsFqdn() {
  96. destinationAddresses, err := h.router.LookupDefault(ctx, destination.Fqdn)
  97. if err != nil {
  98. return nil, err
  99. }
  100. packetConn, _, err := N.ListenSerial(ctx, h.client, destination, destinationAddresses)
  101. if err != nil {
  102. return nil, err
  103. }
  104. return packetConn, nil
  105. }
  106. h.logger.InfoContext(ctx, "outbound packet connection to ", destination)
  107. return h.client.ListenPacket(ctx, destination)
  108. }