github.com/sagernet/sing-box@v1.9.0-rc.20/outbound/socks.go (about) 1 package outbound 2 3 import ( 4 "context" 5 "net" 6 7 "github.com/sagernet/sing-box/adapter" 8 "github.com/sagernet/sing-box/common/dialer" 9 C "github.com/sagernet/sing-box/constant" 10 "github.com/sagernet/sing-box/log" 11 "github.com/sagernet/sing-box/option" 12 "github.com/sagernet/sing-dns" 13 "github.com/sagernet/sing/common" 14 E "github.com/sagernet/sing/common/exceptions" 15 M "github.com/sagernet/sing/common/metadata" 16 N "github.com/sagernet/sing/common/network" 17 "github.com/sagernet/sing/common/uot" 18 "github.com/sagernet/sing/protocol/socks" 19 ) 20 21 var _ adapter.Outbound = (*Socks)(nil) 22 23 type Socks struct { 24 myOutboundAdapter 25 client *socks.Client 26 resolve bool 27 uotClient *uot.Client 28 } 29 30 func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) { 31 var version socks.Version 32 var err error 33 if options.Version != "" { 34 version, err = socks.ParseVersion(options.Version) 35 } else { 36 version = socks.Version5 37 } 38 if err != nil { 39 return nil, err 40 } 41 outboundDialer, err := dialer.New(router, options.DialerOptions) 42 if err != nil { 43 return nil, err 44 } 45 outbound := &Socks{ 46 myOutboundAdapter: myOutboundAdapter{ 47 protocol: C.TypeSOCKS, 48 network: options.Network.Build(), 49 router: router, 50 logger: logger, 51 tag: tag, 52 dependencies: withDialerDependency(options.DialerOptions), 53 }, 54 client: socks.NewClient(outboundDialer, options.ServerOptions.Build(), version, options.Username, options.Password), 55 resolve: version == socks.Version4, 56 } 57 uotOptions := common.PtrValueOrDefault(options.UDPOverTCP) 58 if uotOptions.Enabled { 59 outbound.uotClient = &uot.Client{ 60 Dialer: outbound.client, 61 Version: uotOptions.Version, 62 } 63 } 64 return outbound, nil 65 } 66 67 func (h *Socks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { 68 ctx, metadata := adapter.AppendContext(ctx) 69 metadata.Outbound = h.tag 70 metadata.Destination = destination 71 switch N.NetworkName(network) { 72 case N.NetworkTCP: 73 h.logger.InfoContext(ctx, "outbound connection to ", destination) 74 case N.NetworkUDP: 75 if h.uotClient != nil { 76 h.logger.InfoContext(ctx, "outbound UoT connect packet connection to ", destination) 77 return h.uotClient.DialContext(ctx, network, destination) 78 } 79 h.logger.InfoContext(ctx, "outbound packet connection to ", destination) 80 default: 81 return nil, E.Extend(N.ErrUnknownNetwork, network) 82 } 83 if h.resolve && destination.IsFqdn() { 84 destinationAddresses, err := h.router.LookupDefault(ctx, destination.Fqdn) 85 if err != nil { 86 return nil, err 87 } 88 return N.DialSerial(ctx, h.client, network, destination, destinationAddresses) 89 } 90 return h.client.DialContext(ctx, network, destination) 91 } 92 93 func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { 94 ctx, metadata := adapter.AppendContext(ctx) 95 metadata.Outbound = h.tag 96 metadata.Destination = destination 97 if h.uotClient != nil { 98 h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination) 99 return h.uotClient.ListenPacket(ctx, destination) 100 } 101 if h.resolve && destination.IsFqdn() { 102 destinationAddresses, err := h.router.LookupDefault(ctx, destination.Fqdn) 103 if err != nil { 104 return nil, err 105 } 106 packetConn, _, err := N.ListenSerial(ctx, h.client, destination, destinationAddresses) 107 if err != nil { 108 return nil, err 109 } 110 return packetConn, nil 111 } 112 h.logger.InfoContext(ctx, "outbound packet connection to ", destination) 113 return h.client.ListenPacket(ctx, destination) 114 } 115 116 func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error { 117 if h.resolve { 118 return NewDirectConnection(ctx, h.router, h, conn, metadata, dns.DomainStrategyUseIPv4) 119 } else { 120 return NewConnection(ctx, h, conn, metadata) 121 } 122 } 123 124 func (h *Socks) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error { 125 if h.resolve { 126 return NewDirectPacketConnection(ctx, h.router, h, conn, metadata, dns.DomainStrategyUseIPv4) 127 } else { 128 return NewPacketConnection(ctx, h, conn, metadata) 129 } 130 }