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