diff --git a/docs/changelog.md b/docs/changelog.md index 00297c92..0299de61 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,6 +1,11 @@ +#### 2022/08/12 + +* Performance improvements +* Add UoT option for [Socks](/configuration/outbound/socks) outbound + #### 2022/08/11 -* Add UoT option for [Shadowsocks](/configuration/outbound/shadowsocks) outbound, UoT support for all inbounds. +* Add UoT option for [Shadowsocks](/configuration/outbound/shadowsocks) outbound, UoT support for all inbounds #### 2022/08/10 diff --git a/docs/configuration/outbound/shadowsocks.md b/docs/configuration/outbound/shadowsocks.md index 2f5f33a4..20672090 100644 --- a/docs/configuration/outbound/shadowsocks.md +++ b/docs/configuration/outbound/shadowsocks.md @@ -88,7 +88,7 @@ Both is enabled by default. #### udp_over_tcp -Enable UDP over TCP protocol. +Enable the UDP over TCP protocol. Conflict with `multiplex`. diff --git a/docs/configuration/outbound/socks.md b/docs/configuration/outbound/socks.md index 275135e6..e23a1c98 100644 --- a/docs/configuration/outbound/socks.md +++ b/docs/configuration/outbound/socks.md @@ -15,7 +15,8 @@ "username": "sekai", "password": "admin", "network": "udp", - + "udp_over_tcp": false, + "detour": "upstream-out", "bind_interface": "en0", "routing_mark": 1234, @@ -65,6 +66,10 @@ One of `tcp` `udp`. Both is enabled by default. +#### udp_over_tcp + +Enable the UDP over TCP protocol. + ### Dial Fields #### detour diff --git a/option/simple.go b/option/simple.go index eac9c34f..e262c3b3 100644 --- a/option/simple.go +++ b/option/simple.go @@ -21,6 +21,7 @@ type SocksOutboundOptions struct { Username string `json:"username,omitempty"` Password string `json:"password,omitempty"` Network NetworkList `json:"network,omitempty"` + UoT bool `json:"udp_over_tcp,omitempty"` } type HTTPOutboundOptions struct { diff --git a/outbound/shadowsocks.go b/outbound/shadowsocks.go index ba82a26e..cba3ef3a 100644 --- a/outbound/shadowsocks.go +++ b/outbound/shadowsocks.go @@ -59,6 +59,9 @@ func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte } func (h *Shadowsocks) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + ctx, metadata := adapter.AppendContext(ctx) + metadata.Outbound = h.tag + metadata.Destination = destination if h.multiplexDialer == nil { switch N.NetworkName(network) { case N.NetworkTCP: @@ -90,6 +93,9 @@ func (h *Shadowsocks) DialContext(ctx context.Context, network string, destinati } func (h *Shadowsocks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + ctx, metadata := adapter.AppendContext(ctx) + metadata.Outbound = h.tag + metadata.Destination = destination if h.multiplexDialer == nil { if h.uot { h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination) @@ -127,9 +133,6 @@ var _ N.Dialer = (*shadowsocksDialer)(nil) type shadowsocksDialer Shadowsocks func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - ctx, metadata := adapter.AppendContext(ctx) - metadata.Outbound = h.tag - metadata.Destination = destination switch N.NetworkName(network) { case N.NetworkTCP: outConn, err := h.dialer.DialContext(ctx, N.NetworkTCP, h.serverAddr) @@ -149,9 +152,6 @@ func (h *shadowsocksDialer) DialContext(ctx context.Context, network string, des } func (h *shadowsocksDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - ctx, metadata := adapter.AppendContext(ctx) - metadata.Outbound = h.tag - metadata.Destination = destination outConn, err := h.dialer.DialContext(ctx, N.NetworkUDP, h.serverAddr) if err != nil { return nil, err diff --git a/outbound/socks.go b/outbound/socks.go index c115366c..d51bc9e5 100644 --- a/outbound/socks.go +++ b/outbound/socks.go @@ -12,6 +12,7 @@ import ( E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/uot" "github.com/sagernet/sing/protocol/socks" ) @@ -20,6 +21,7 @@ var _ adapter.Outbound = (*Socks)(nil) type Socks struct { myOutboundAdapter client *socks.Client + uot bool } func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, options option.SocksOutboundOptions) (*Socks, error) { @@ -43,6 +45,7 @@ func NewSocks(router adapter.Router, logger log.ContextLogger, tag string, optio tag: tag, }, socks.NewClient(detour, options.ServerOptions.Build(), version, options.Username, options.Password), + options.UoT, }, nil } @@ -54,6 +57,17 @@ func (h *Socks) DialContext(ctx context.Context, network string, destination M.S case N.NetworkTCP: h.logger.InfoContext(ctx, "outbound connection to ", destination) case N.NetworkUDP: + if h.uot { + h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination) + tcpConn, err := h.client.DialContext(ctx, N.NetworkTCP, M.Socksaddr{ + Fqdn: uot.UOTMagicAddress, + Port: destination.Port, + }) + if err != nil { + return nil, err + } + return uot.NewClientConn(tcpConn), nil + } h.logger.InfoContext(ctx, "outbound packet connection to ", destination) default: return nil, E.Extend(N.ErrUnknownNetwork, network) @@ -65,6 +79,17 @@ func (h *Socks) ListenPacket(ctx context.Context, destination M.Socksaddr) (net. ctx, metadata := adapter.AppendContext(ctx) metadata.Outbound = h.tag metadata.Destination = destination + if h.uot { + h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination) + tcpConn, err := h.client.DialContext(ctx, N.NetworkTCP, M.Socksaddr{ + Fqdn: uot.UOTMagicAddress, + Port: destination.Port, + }) + if err != nil { + return nil, err + } + return uot.NewClientConn(tcpConn), nil + } h.logger.InfoContext(ctx, "outbound packet connection to ", destination) return h.client.ListenPacket(ctx, destination) }