From e8d4f8ae7b59473fe4db2c951baa2cd4627ec06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 15 Mar 2023 14:08:52 +0800 Subject: [PATCH] Update UoT protocol --- adapter/outbound/shadowsocks.go | 34 ++++++++++++++++++++++++++++----- go.mod | 4 ++-- go.sum | 10 ++++++---- listener/sing/sing.go | 14 +++++++++++--- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index af034472..c3097d09 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -50,6 +50,7 @@ type ShadowSocksOption struct { Plugin string `proxy:"plugin,omitempty"` PluginOpts map[string]any `proxy:"plugin-opts,omitempty"` UDPOverTCP bool `proxy:"udp-over-tcp,omitempty"` + UDPOverTCPVersion int `proxy:"udp-over-tcp-version,omitempty"` ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } @@ -123,10 +124,16 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada } useEarly = useEarly || N.NeedHandshake(c) if metadata.NetWork == C.UDP && ss.option.UDPOverTCP { - if useEarly { - return ss.method.DialEarlyConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")), nil + var uotDestination M.Socksaddr + if ss.option.UDPOverTCPVersion == 1 { + uotDestination.Fqdn = uot.LegacyMagicAddress } else { - return ss.method.DialConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")) + uotDestination.Fqdn = uot.MagicAddress + } + if useEarly { + return ss.method.DialEarlyConn(c, uotDestination), nil + } else { + return ss.method.DialConn(c, uotDestination) } } if useEarly { @@ -169,7 +176,12 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - return newPacketConn(uot.NewClientConn(tcpConn), ss), nil + destination := M.ParseSocksaddr(metadata.RemoteAddress()) + if ss.option.UDPOverTCPVersion == 1 { + return newPacketConn(uot.NewConn(tcpConn, false, destination), ss), nil + } else { + return newPacketConn(uot.NewLazyConn(tcpConn, uot.Request{Destination: destination}), ss), nil + } } addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer) if err != nil { @@ -192,7 +204,12 @@ func (ss *ShadowSocks) SupportWithDialer() bool { // ListenPacketOnStreamConn implements C.ProxyAdapter func (ss *ShadowSocks) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { if ss.option.UDPOverTCP { - return newPacketConn(uot.NewClientConn(c), ss), nil + destination := M.ParseSocksaddr(metadata.RemoteAddress()) + if ss.option.UDPOverTCPVersion == 1 { + return newPacketConn(uot.NewConn(c, false, destination), ss), nil + } else { + return newPacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination}), ss), nil + } } return nil, errors.New("no support") } @@ -279,6 +296,13 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } } + switch option.UDPOverTCPVersion { + case uot.Version, uot.LegacyVersion: + case 0: + option.UDPOverTCPVersion = uot.Version + default: + return nil, fmt.Errorf("ss %s unknown udp over tcp protocol version: %d", addr, option.UDPOverTCPVersion) + } return &ShadowSocks{ Base: &Base{ diff --git a/go.mod b/go.mod index 28760b44..c9080f7d 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.8 + github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d @@ -44,7 +44,7 @@ require ( golang.org/x/exp v0.0.0-20221205204356-47842c84f3db golang.org/x/net v0.7.0 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.5.0 + golang.org/x/sys v0.6.0 google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.1.7 diff --git a/go.sum b/go.sum index f9e584a2..5fc1b7e0 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,10 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.8 h1:6DKo2FkSHn0nUcjO7bAext/ai7y7pCusK/+fScBJ5Jk= -github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.1.9-0.20230315055814-2f422b53b06f h1:bCx4+svKuZyw8CxxFXmrmhAERFf5BAAiNb1aYXj4hwk= +github.com/sagernet/sing v0.1.9-0.20230315055814-2f422b53b06f/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= +github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b h1:1iKGftQ59+shDSx2RaLaxXJcMK/B+IU9WqUPwyBW+E0= +github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc h1:vqlYWupvVDRpvv2F+RtECJN+VbuKjLtmQculQvOecls= @@ -222,8 +224,8 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index a3e15154..fa9e02f1 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -5,6 +5,7 @@ import ( "errors" "golang.org/x/exp/slices" "net" + "net/netip" "sync" "time" @@ -61,9 +62,16 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta switch metadata.Destination.Fqdn { case vmess.MuxDestination.Fqdn: return vmess.HandleMuxConnection(ctx, conn, h) - case uot.UOTMagicAddress: - metadata.Destination = M.Socksaddr{} - return h.NewPacketConnection(ctx, uot.NewClientConn(conn), metadata) + case uot.MagicAddress: + request, err := uot.ReadRequest(conn) + if err != nil { + return E.Cause(err, "read UoT request") + } + metadata.Destination = request.Destination + return h.NewPacketConnection(ctx, uot.NewConn(conn, request.IsConnect, metadata.Destination), metadata) + case uot.LegacyMagicAddress: + metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()} + return h.NewPacketConnection(ctx, uot.NewConn(conn, false, metadata.Destination), metadata) } target := socks5.ParseAddr(metadata.Destination.String()) wg := &sync.WaitGroup{}