Add socks outbound

This commit is contained in:
世界 2022-07-03 13:14:49 +08:00
parent ef5cfd59d4
commit 70c0812606
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
10 changed files with 122 additions and 28 deletions

View file

@ -181,6 +181,7 @@ func (a *myInboundAdapter) loopUDPInThreadSafe() {
buffer := buf.NewPacket() buffer := buf.NewPacket()
n, addr, err := a.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes()) n, addr, err := a.udpConn.ReadFromUDPAddrPort(buffer.FreeBytes())
if err != nil { if err != nil {
buffer.Release()
return return
} }
buffer.Truncate(n) buffer.Truncate(n)

View file

@ -11,7 +11,7 @@ import (
type Outbound interface { type Outbound interface {
Type() string Type() string
Tag() string Tag() string
N.Dialer
NewConnection(ctx context.Context, conn net.Conn, destination M.Socksaddr) error NewConnection(ctx context.Context, conn net.Conn, destination M.Socksaddr) error
NewPacketConnection(ctx context.Context, conn N.PacketConn, destination M.Socksaddr) error NewPacketConnection(ctx context.Context, conn N.PacketConn, destination M.Socksaddr) error
N.Dialer
} }

View file

@ -24,6 +24,8 @@ func New(router adapter.Router, logger log.Logger, index int, options option.Out
switch options.Type { switch options.Type {
case C.TypeDirect: case C.TypeDirect:
return NewDirect(router, outboundLogger, options.Tag, options.DirectOptions), nil return NewDirect(router, outboundLogger, options.Tag, options.DirectOptions), nil
case C.TypeSocks:
return NewSocks(router, outboundLogger, options.Tag, options.SocksOptions)
case C.TypeShadowsocks: case C.TypeShadowsocks:
return NewShadowsocks(router, outboundLogger, options.Tag, options.ShadowsocksOptions) return NewShadowsocks(router, outboundLogger, options.Tag, options.ShadowsocksOptions)
default: default:

View file

@ -44,7 +44,7 @@ func (d *defaultDialer) DialContext(ctx context.Context, network string, address
return d.Dialer.DialContext(ctx, network, address.String()) return d.Dialer.DialContext(ctx, network, address.String())
} }
func (d *defaultDialer) ListenPacket(ctx context.Context) (net.PacketConn, error) { func (d *defaultDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
return d.ListenConfig.ListenPacket(ctx, "udp", "") return d.ListenConfig.ListenPacket(ctx, "udp", "")
} }
@ -105,12 +105,12 @@ func (d *lazyDialer) DialContext(ctx context.Context, network string, destinatio
return dialer.DialContext(ctx, network, destination) return dialer.DialContext(ctx, network, destination)
} }
func (d *lazyDialer) ListenPacket(ctx context.Context) (net.PacketConn, error) { func (d *lazyDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
dialer, err := d.Dialer() dialer, err := d.Dialer()
if err != nil { if err != nil {
return nil, err return nil, err
} }
return dialer.ListenPacket(ctx) return dialer.ListenPacket(ctx, destination)
} }
func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) error { func CopyEarlyConn(ctx context.Context, conn net.Conn, serverConn net.Conn) error {

View file

@ -63,9 +63,9 @@ func (d *Direct) DialContext(ctx context.Context, network string, destination M.
return d.dialer.DialContext(ctx, network, destination) return d.dialer.DialContext(ctx, network, destination)
} }
func (d *Direct) ListenPacket(ctx context.Context) (net.PacketConn, error) { func (d *Direct) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
d.logger.WithContext(ctx).Info("outbound packet connection") d.logger.WithContext(ctx).Info("outbound packet connection")
return d.dialer.ListenPacket(ctx) return d.dialer.ListenPacket(ctx, destination)
} }
func (d *Direct) NewConnection(ctx context.Context, conn net.Conn, destination M.Socksaddr) error { func (d *Direct) NewConnection(ctx context.Context, conn net.Conn, destination M.Socksaddr) error {
@ -77,7 +77,7 @@ func (d *Direct) NewConnection(ctx context.Context, conn net.Conn, destination M
} }
func (d *Direct) NewPacketConnection(ctx context.Context, conn N.PacketConn, destination M.Socksaddr) error { func (d *Direct) NewPacketConnection(ctx context.Context, conn N.PacketConn, destination M.Socksaddr) error {
outConn, err := d.ListenPacket(ctx) outConn, err := d.ListenPacket(ctx, destination)
if err != nil { if err != nil {
return err return err
} }

View file

@ -47,22 +47,6 @@ func NewShadowsocks(router adapter.Router, logger log.Logger, tag string, option
return outbound, nil return outbound, nil
} }
func (o *Shadowsocks) NewConnection(ctx context.Context, conn net.Conn, destination M.Socksaddr) error {
serverConn, err := o.DialContext(ctx, "tcp", destination)
if err != nil {
return err
}
return CopyEarlyConn(ctx, conn, serverConn)
}
func (o *Shadowsocks) NewPacketConnection(ctx context.Context, conn N.PacketConn, destination M.Socksaddr) error {
serverConn, err := o.ListenPacket(ctx)
if err != nil {
return err
}
return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(serverConn))
}
func (o *Shadowsocks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { func (o *Shadowsocks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
switch network { switch network {
case C.NetworkTCP: case C.NetworkTCP:
@ -84,11 +68,27 @@ func (o *Shadowsocks) DialContext(ctx context.Context, network string, destinati
} }
} }
func (o *Shadowsocks) ListenPacket(ctx context.Context) (net.PacketConn, error) { func (o *Shadowsocks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
o.logger.WithContext(ctx).Info("outbound packet connection to ", o.serverAddr) o.logger.WithContext(ctx).Info("outbound packet connection to ", o.serverAddr)
outConn, err := o.dialer.ListenPacket(ctx) outConn, err := o.dialer.ListenPacket(ctx, destination)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return o.method.DialPacketConn(&bufio.BindPacketConn{PacketConn: outConn, Addr: o.serverAddr.UDPAddr()}), nil return o.method.DialPacketConn(&bufio.BindPacketConn{PacketConn: outConn, Addr: o.serverAddr.UDPAddr()}), nil
} }
func (o *Shadowsocks) NewConnection(ctx context.Context, conn net.Conn, destination M.Socksaddr) error {
serverConn, err := o.DialContext(ctx, "tcp", destination)
if err != nil {
return err
}
return CopyEarlyConn(ctx, conn, serverConn)
}
func (o *Shadowsocks) NewPacketConnection(ctx context.Context, conn N.PacketConn, destination M.Socksaddr) error {
serverConn, err := o.ListenPacket(ctx, destination)
if err != nil {
return err
}
return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(serverConn))
}

78
adapter/outbound/socks.go Normal file
View file

@ -0,0 +1,78 @@
package outbound
import (
"context"
"net"
"github.com/sagernet/sing-box/adapter"
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/bufio"
M "github.com/sagernet/sing/common/metadata"
N "github.com/sagernet/sing/common/network"
"github.com/sagernet/sing/protocol/socks"
)
var _ adapter.Outbound = (*Socks)(nil)
type Socks struct {
myOutboundAdapter
client *socks.Client
}
func NewSocks(router adapter.Router, logger log.Logger, tag string, options option.SocksOutboundOptions) (*Socks, error) {
dialer := NewDialer(router, options.DialerOptions)
var version socks.Version
var err error
if options.Version != "" {
version, err = socks.ParseVersion(options.Version)
} else {
version = socks.Version5
}
if err != nil {
return nil, err
}
return &Socks{
myOutboundAdapter{
protocol: C.TypeSocks,
logger: logger,
tag: tag,
dialer: dialer,
},
socks.NewClient(dialer, M.ParseSocksaddrHostPort(options.Server, options.ServerPort), version, options.Username, options.Password),
}, nil
}
func (h *Socks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
switch network {
case C.NetworkTCP:
h.logger.WithContext(ctx).Info("outbound connection to ", destination)
case C.NetworkUDP:
h.logger.WithContext(ctx).Info("outbound packet connection to ", destination)
default:
panic("unknown network " + network)
}
return h.client.DialContext(ctx, network, destination)
}
func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
h.logger.WithContext(ctx).Info("outbound packet connection to ", destination)
return h.client.ListenPacket(ctx, destination)
}
func (h *Socks) NewConnection(ctx context.Context, conn net.Conn, destination M.Socksaddr) error {
outConn, err := h.DialContext(ctx, "tcp", destination)
if err != nil {
return err
}
return bufio.CopyConn(ctx, conn, outConn)
}
func (h *Socks) NewPacketConnection(ctx context.Context, conn N.PacketConn, destination M.Socksaddr) error {
outConn, err := h.ListenPacket(ctx, destination)
if err != nil {
return err
}
return bufio.CopyPacketConn(ctx, conn, bufio.NewPacketConn(outConn))
}

2
go.mod
View file

@ -7,7 +7,7 @@ require (
github.com/goccy/go-json v0.9.8 github.com/goccy/go-json v0.9.8
github.com/logrusorgru/aurora v2.0.3+incompatible github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/oschwald/geoip2-golang v1.7.0 github.com/oschwald/geoip2-golang v1.7.0
github.com/sagernet/sing v0.0.0-20220703025722-d002d5ba3ba5 github.com/sagernet/sing v0.0.0-20220703051339-f128942ffe12
github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
github.com/spf13/cobra v1.5.0 github.com/spf13/cobra v1.5.0

4
go.sum
View file

@ -20,8 +20,8 @@ github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sagernet/sing v0.0.0-20220703025722-d002d5ba3ba5 h1:0oNnpN43Z6TXDdea5tbKIXXJ62yJqTpOW4IyQSgN3KY= github.com/sagernet/sing v0.0.0-20220703051339-f128942ffe12 h1:HN3IoHyR2tpI4WwBVSDo5VJ0tKrQKqltkjlHTG9vbdo=
github.com/sagernet/sing v0.0.0-20220703025722-d002d5ba3ba5/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c= github.com/sagernet/sing v0.0.0-20220703051339-f128942ffe12/go.mod h1:3ZmoGNg/nNJTyHAZFNRSPaXpNIwpDvyIiAUd0KIWV5c=
github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k= github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649 h1:whNDUGOAX5GPZkSy4G3Gv9QyIgk5SXRyjkRuP7ohF8k=
github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw= github.com/sagernet/sing-shadowsocks v0.0.0-20220701084835-2208da1d8649/go.mod h1:MuyT+9fEPjvauAv0fSE0a6Q+l0Tv2ZrAafTkYfnxBFw=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=

View file

@ -10,6 +10,7 @@ type _Outbound struct {
Tag string `json:"tag,omitempty"` Tag string `json:"tag,omitempty"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
DirectOptions DirectOutboundOptions `json:"-"` DirectOptions DirectOutboundOptions `json:"-"`
SocksOptions SocksOutboundOptions `json:"-"`
ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"` ShadowsocksOptions ShadowsocksOutboundOptions `json:"-"`
} }
@ -20,6 +21,8 @@ func (h Outbound) MarshalJSON() ([]byte, error) {
switch h.Type { switch h.Type {
case "direct": case "direct":
v = h.DirectOptions v = h.DirectOptions
case "socks":
v = h.SocksOptions
case "shadowsocks": case "shadowsocks":
v = h.ShadowsocksOptions v = h.ShadowsocksOptions
default: default:
@ -37,6 +40,8 @@ func (h *Outbound) UnmarshalJSON(bytes []byte) error {
switch h.Type { switch h.Type {
case "direct": case "direct":
v = &h.DirectOptions v = &h.DirectOptions
case "socks":
v = &h.SocksOptions
case "shadowsocks": case "shadowsocks":
v = &h.ShadowsocksOptions v = &h.ShadowsocksOptions
default: default:
@ -73,6 +78,14 @@ func (o ServerOptions) Build() M.Socksaddr {
return M.ParseSocksaddrHostPort(o.Server, o.ServerPort) return M.ParseSocksaddrHostPort(o.Server, o.ServerPort)
} }
type SocksOutboundOptions struct {
DialerOptions
ServerOptions
Version string `json:"version,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"`
}
type ShadowsocksOutboundOptions struct { type ShadowsocksOutboundOptions struct {
DialerOptions DialerOptions
ServerOptions ServerOptions