From c3ef05b257a8310adf31b06eb21126e6a6626ad7 Mon Sep 17 00:00:00 2001 From: H1JK Date: Wed, 7 Jun 2023 23:03:36 +0800 Subject: [PATCH] feat: Add XUDP migration support --- adapter/outbound/vless.go | 5 ++++- adapter/outbound/vmess.go | 27 +++++++++++++++++++-------- common/utils/global_id.go | 13 +++++++++++++ go.mod | 2 +- go.sum | 4 ++-- transport/vless/conn.go | 29 ++++++++++++++++------------- 6 files changed, 55 insertions(+), 25 deletions(-) create mode 100644 common/utils/global_id.go diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index e3aff5fb..558342d5 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -14,6 +14,7 @@ import ( "github.com/Dreamacro/clash/common/convert" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" @@ -374,7 +375,9 @@ func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada if v.option.XUDP { return newPacketConn(N.NewThreadSafePacketConn( - vmessSing.NewXUDPConn(c, M.SocksaddrFromNet(metadata.UDPAddr())), + vmessSing.NewXUDPConn(c, + utils.GlobalID(metadata.SourceAddress()), + M.SocksaddrFromNet(metadata.UDPAddr())), ), v), nil } else if v.option.PacketAddr { return newPacketConn(N.NewThreadSafePacketConn( diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 058ce49d..0a75aa1a 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -12,6 +12,7 @@ import ( "sync" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" @@ -224,29 +225,39 @@ func (v *Vmess) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err if metadata.NetWork == C.UDP { if v.option.XUDP { if N.NeedHandshake(c) { - conn = v.client.DialEarlyXUDPPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) + conn = v.client.DialEarlyXUDPPacketConn(c, + utils.GlobalID(metadata.SourceAddress()), + M.SocksaddrFromNet(metadata.UDPAddr())) } else { - conn, err = v.client.DialXUDPPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) + conn, err = v.client.DialXUDPPacketConn(c, + utils.GlobalID(metadata.SourceAddress()), + M.SocksaddrFromNet(metadata.UDPAddr())) } } else if v.option.PacketAddr { if N.NeedHandshake(c) { - conn = v.client.DialEarlyPacketConn(c, M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443)) + conn = v.client.DialEarlyPacketConn(c, + M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443)) } else { - conn, err = v.client.DialPacketConn(c, M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443)) + conn, err = v.client.DialPacketConn(c, + M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443)) } conn = packetaddr.NewBindConn(conn) } else { if N.NeedHandshake(c) { - conn = v.client.DialEarlyPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) + conn = v.client.DialEarlyPacketConn(c, + M.SocksaddrFromNet(metadata.UDPAddr())) } else { - conn, err = v.client.DialPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) + conn, err = v.client.DialPacketConn(c, + M.SocksaddrFromNet(metadata.UDPAddr())) } } } else { if N.NeedHandshake(c) { - conn = v.client.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + conn = v.client.DialEarlyConn(c, + M.ParseSocksaddr(metadata.RemoteAddress())) } else { - conn, err = v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + conn, err = v.client.DialConn(c, + M.ParseSocksaddr(metadata.RemoteAddress())) } } if err != nil { diff --git a/common/utils/global_id.go b/common/utils/global_id.go new file mode 100644 index 00000000..e634116a --- /dev/null +++ b/common/utils/global_id.go @@ -0,0 +1,13 @@ +package utils + +import ( + "hash/maphash" + "unsafe" +) + +var globalSeed = maphash.MakeSeed() + +func GlobalID(material string) (id [8]byte) { + *(*uint64)(unsafe.Pointer(&id[0])) = maphash.String(globalSeed, material) + return +} diff --git a/go.mod b/go.mod index 89071513..7c3d56f2 100644 --- a/go.mod +++ b/go.mod @@ -108,4 +108,4 @@ require ( replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b -replace github.com/sagernet/sing-vmess => github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899 +replace github.com/sagernet/sing-vmess => github.com/metacubex/sing-vmess v0.1.5-0.20230607134851-17f84aec22a1 diff --git a/go.sum b/go.sum index d4c2e2f4..0d3eebbf 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,8 @@ github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca h1:10q github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca/go.mod h1:jVDD4N22bDPPKA73NvB7aqdlLWiAwv8D+jx7HwhcWak= github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e h1:7QlJQl4S3F3YXn48fYxjymMw8HkXg9bl++hLi4ZRyCY= github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e/go.mod h1:u9onX49LZPYuIPQ7SdM64Gnins8y5wg4Cn6ZYRSxWHU= -github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899 h1:iRfcuztp7REfmOyasSlCL/pqNWfUDMTJ2CwbGpxpeks= -github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899/go.mod h1:RSt9rxGHllLdc5JUebkQwaqyWLx09Lqya37DlBe8CP8= +github.com/metacubex/sing-vmess v0.1.5-0.20230607134851-17f84aec22a1 h1:ARhfmDKWzOsDEX5oUiC8bnz7FxQFukLV6fBiNM73r/M= +github.com/metacubex/sing-vmess v0.1.5-0.20230607134851-17f84aec22a1/go.mod h1:RSt9rxGHllLdc5JUebkQwaqyWLx09Lqya37DlBe8CP8= github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco= github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY= github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 9e2e5e89..fb514367 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -203,24 +203,27 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { needHandshake: true, } - if !dst.UDP && client.Addons != nil { + if client.Addons != nil { switch client.Addons.Flow { case XRO, XRD, XRS: - if xtlsConn, ok := conn.(*xtls.Conn); ok { - xtlsConn.RPRX = true - xtlsConn.SHOW = client.XTLSShow - xtlsConn.MARK = "XTLS" - if client.Addons.Flow == XRS { - client.Addons.Flow = XRD - } + if !dst.UDP { + if xtlsConn, ok := conn.(*xtls.Conn); ok { + xtlsConn.RPRX = true + xtlsConn.SHOW = client.XTLSShow + xtlsConn.MARK = "XTLS" + if client.Addons.Flow == XRS { + client.Addons.Flow = XRD + } - if client.Addons.Flow == XRD { - xtlsConn.DirectMode = true + if client.Addons.Flow == XRD { + xtlsConn.DirectMode = true + } + c.addons = client.Addons + } else { + return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow) } - c.addons = client.Addons - } else { - return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow) } + case XRV: visionConn, err := vision.NewConn(c, c.id) if err != nil {