From 5b07d7b776d13cb91de7efafc648d51c73649218 Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Fri, 18 Nov 2022 22:57:33 +0800 Subject: [PATCH 1/5] Feature: add tunnels --- config/config.go | 69 ++++++++++++++++++++++ constant/metadata.go | 20 ++++--- go.mod | 3 +- go.sum | 11 ++-- hub/executor/executor.go | 27 +++++---- listener/listener.go | 117 ++++++++++++++++++++++++++++++++++---- listener/tunnel/packet.go | 31 ++++++++++ listener/tunnel/tcp.go | 75 ++++++++++++++++++++++++ listener/tunnel/udp.go | 85 +++++++++++++++++++++++++++ tunnel/tunnel.go | 13 +++++ 10 files changed, 416 insertions(+), 35 deletions(-) create mode 100644 listener/tunnel/packet.go create mode 100644 listener/tunnel/tcp.go create mode 100644 listener/tunnel/udp.go diff --git a/config/config.go b/config/config.go index 8b1ed89c..d9063415 100644 --- a/config/config.go +++ b/config/config.go @@ -22,6 +22,7 @@ import ( R "github.com/Dreamacro/clash/rule" T "github.com/Dreamacro/clash/tunnel" + "github.com/samber/lo" "gopkg.in/yaml.v3" ) @@ -98,6 +99,7 @@ type Config struct { Users []auth.AuthUser Proxies map[string]C.Proxy Providers map[string]providerTypes.ProxyProvider + Tunnels []Tunnel } type RawDNS struct { @@ -122,6 +124,64 @@ type RawFallbackFilter struct { Domain []string `yaml:"domain"` } +type tunnel struct { + Network []string `yaml:"network"` + Address string `yaml:"address"` + Target string `yaml:"target"` + Proxy string `yaml:"proxy"` +} + +type Tunnel tunnel + +// UnmarshalYAML implements yaml.Unmarshaler +func (t *Tunnel) UnmarshalYAML(unmarshal func(any) error) error { + var tp string + if err := unmarshal(&tp); err != nil { + var inner tunnel + if err := unmarshal(&inner); err != nil { + return err + } + + *t = Tunnel(inner) + return nil + } + + // parse udp/tcp,address,target,proxy + parts := lo.Map(strings.Split(tp, ","), func(s string, _ int) string { + return strings.TrimSpace(s) + }) + if len(parts) != 4 { + return fmt.Errorf("invalid tunnel config %s", tp) + } + network := strings.Split(parts[0], "/") + + // validate network + for _, n := range network { + switch n { + case "tcp", "udp": + default: + return fmt.Errorf("invalid tunnel network %s", n) + } + } + + // validate address and target + address := parts[1] + target := parts[2] + for _, addr := range []string{address, target} { + if _, _, err := net.SplitHostPort(addr); err != nil { + return fmt.Errorf("invalid tunnel target or address %s", addr) + } + } + + *t = Tunnel(tunnel{ + Network: network, + Address: address, + Target: target, + Proxy: parts[3], + }) + return nil +} + type RawConfig struct { Port int `yaml:"port"` SocksPort int `yaml:"socks-port"` @@ -139,6 +199,7 @@ type RawConfig struct { Secret string `yaml:"secret"` Interface string `yaml:"interface-name"` RoutingMark int `yaml:"routing-mark"` + Tunnels []Tunnel `yaml:"tunnels"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` Hosts map[string]string `yaml:"hosts"` @@ -237,6 +298,14 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { config.Users = parseAuthentication(rawCfg.Authentication) + config.Tunnels = rawCfg.Tunnels + // verify tunnels + for _, t := range config.Tunnels { + if _, ok := config.Proxies[t.Proxy]; !ok { + return nil, fmt.Errorf("tunnel proxy %s not found", t.Proxy) + } + } + return config, nil } diff --git a/constant/metadata.go b/constant/metadata.go index b829b7b0..cab6e37d 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -19,6 +19,7 @@ const ( SOCKS5 REDIR TPROXY + TUNNEL ) type NetWork int @@ -61,15 +62,16 @@ func (t Type) MarshalJSON() ([]byte, error) { // Metadata is used to store connection address type Metadata struct { - NetWork NetWork `json:"network"` - Type Type `json:"type"` - SrcIP net.IP `json:"sourceIP"` - DstIP net.IP `json:"destinationIP"` - SrcPort string `json:"sourcePort"` - DstPort string `json:"destinationPort"` - Host string `json:"host"` - DNSMode DNSMode `json:"dnsMode"` - ProcessPath string `json:"processPath"` + NetWork NetWork `json:"network"` + Type Type `json:"type"` + SrcIP net.IP `json:"sourceIP"` + DstIP net.IP `json:"destinationIP"` + SrcPort string `json:"sourcePort"` + DstPort string `json:"destinationPort"` + Host string `json:"host"` + DNSMode DNSMode `json:"dnsMode"` + ProcessPath string `json:"processPath"` + SpecialProxy string `json:"specialProxy"` } func (m *Metadata) RemoteAddress() string { diff --git a/go.mod b/go.mod index 25b2e1bd..66eef6b1 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/mdlayher/netlink v1.6.2 github.com/miekg/dns v1.1.50 github.com/oschwald/geoip2-golang v1.8.0 + github.com/samber/lo v1.35.0 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.1 go.etcd.io/bbolt v1.3.6 @@ -29,11 +30,11 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/josharian/native v1.0.0 // indirect - github.com/kr/text v0.2.0 // indirect github.com/mdlayher/socket v0.2.3 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/text v0.4.0 // indirect golang.org/x/tools v0.1.12 // indirect diff --git a/go.sum b/go.sum index aac680fc..d92a0615 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,5 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -34,9 +33,7 @@ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGu github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= @@ -50,6 +47,7 @@ github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6SLNcKTs= github.com/oschwald/geoip2-golang v1.8.0/go.mod h1:R7bRvYjOeaoenAp9sKRS8GX5bJWcZ0laWO5+DauEktw= github.com/oschwald/maxminddb-golang v1.10.0 h1:Xp1u0ZhqkSuopaKmk1WwHtjF0H9Hd9181uj2MQ5Vndg= @@ -57,6 +55,8 @@ github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYx 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/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/samber/lo v1.35.0 h1:GlT8CV1GE+v97Y7MLF1wXvX6mjoxZ+hi61tj/ZcQwY0= +github.com/samber/lo v1.35.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= @@ -70,6 +70,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -84,6 +85,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077 h1:t5bjOfJPQfaG9NV1imLZM5E2uzaLGs5/NtyMtRNVjQ4= golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= @@ -152,7 +155,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/hub/executor/executor.go b/hub/executor/executor.go index dc1f8601..a131f4b1 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -18,7 +18,7 @@ import ( C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/dns" - P "github.com/Dreamacro/clash/listener" + "github.com/Dreamacro/clash/listener" authStore "github.com/Dreamacro/clash/listener/auth" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/tunnel" @@ -75,10 +75,11 @@ func ApplyConfig(cfg *config.Config, force bool) { updateGeneral(cfg.General, force) updateDNS(cfg.DNS) updateExperimental(cfg) + updateTunnels(cfg.Tunnels) } func GetGeneral() *config.General { - ports := P.GetPorts() + ports := listener.GetPorts() authenticator := []string{} if auth := authStore.Authenticator(); auth != nil { authenticator = auth.Users() @@ -92,8 +93,8 @@ func GetGeneral() *config.General { TProxyPort: ports.TProxyPort, MixedPort: ports.MixedPort, Authentication: authenticator, - AllowLan: P.AllowLan(), - BindAddress: P.BindAddress(), + AllowLan: listener.AllowLan(), + BindAddress: listener.BindAddress(), }, Mode: tunnel.Mode(), LogLevel: log.Level(), @@ -161,6 +162,10 @@ func updateRules(rules []C.Rule) { tunnel.UpdateRules(rules) } +func updateTunnels(tunnels []config.Tunnel) { + listener.PatchTunnel(tunnels, tunnel.TCPIn(), tunnel.UDPIn()) +} + func updateGeneral(general *config.General, force bool) { log.SetLevel(general.LogLevel) tunnel.SetMode(general.Mode) @@ -176,19 +181,19 @@ func updateGeneral(general *config.General, force bool) { } allowLan := general.AllowLan - P.SetAllowLan(allowLan) + listener.SetAllowLan(allowLan) bindAddress := general.BindAddress - P.SetBindAddress(bindAddress) + listener.SetBindAddress(bindAddress) tcpIn := tunnel.TCPIn() udpIn := tunnel.UDPIn() - P.ReCreateHTTP(general.Port, tcpIn) - P.ReCreateSocks(general.SocksPort, tcpIn, udpIn) - P.ReCreateRedir(general.RedirPort, tcpIn, udpIn) - P.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn) - P.ReCreateMixed(general.MixedPort, tcpIn, udpIn) + listener.ReCreateHTTP(general.Port, tcpIn) + listener.ReCreateSocks(general.SocksPort, tcpIn, udpIn) + listener.ReCreateRedir(general.RedirPort, tcpIn, udpIn) + listener.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn) + listener.ReCreateMixed(general.MixedPort, tcpIn, udpIn) } func updateUsers(users []auth.AuthUser) { diff --git a/listener/listener.go b/listener/listener.go index b8e54b95..b5372327 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -1,34 +1,41 @@ -package proxy +package listener import ( "fmt" "net" "strconv" + "strings" "sync" "github.com/Dreamacro/clash/adapter/inbound" + "github.com/Dreamacro/clash/config" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/listener/http" "github.com/Dreamacro/clash/listener/mixed" "github.com/Dreamacro/clash/listener/redir" "github.com/Dreamacro/clash/listener/socks" "github.com/Dreamacro/clash/listener/tproxy" + "github.com/Dreamacro/clash/listener/tunnel" "github.com/Dreamacro/clash/log" + + "github.com/samber/lo" ) var ( allowLan = false bindAddress = "*" - socksListener *socks.Listener - socksUDPListener *socks.UDPListener - httpListener *http.Listener - redirListener *redir.Listener - redirUDPListener *tproxy.UDPListener - tproxyListener *tproxy.Listener - tproxyUDPListener *tproxy.UDPListener - mixedListener *mixed.Listener - mixedUDPLister *socks.UDPListener + socksListener *socks.Listener + socksUDPListener *socks.UDPListener + httpListener *http.Listener + redirListener *redir.Listener + redirUDPListener *tproxy.UDPListener + tproxyListener *tproxy.Listener + tproxyUDPListener *tproxy.UDPListener + mixedListener *mixed.Listener + mixedUDPLister *socks.UDPListener + tunnelTCPListeners = map[string]*tunnel.Listener{} + tunnelUDPListeners = map[string]*tunnel.PacketConn{} // lock for recreate function socksMux sync.Mutex @@ -36,6 +43,7 @@ var ( redirMux sync.Mutex tproxyMux sync.Mutex mixedMux sync.Mutex + tunnelMux sync.Mutex ) type Ports struct { @@ -301,6 +309,95 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.P log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address()) } +func PatchTunnel(tunnels []config.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- *inbound.PacketAdapter) { + tunnelMux.Lock() + defer tunnelMux.Unlock() + + type addrProxy struct { + network string + addr string + target string + proxy string + } + + tcpOld := lo.Map( + lo.Keys(tunnelTCPListeners), + func(key string, _ int) addrProxy { + parts := strings.Split(key, "/") + return addrProxy{ + network: "tcp", + addr: parts[0], + target: parts[1], + proxy: parts[2], + } + }, + ) + udpOld := lo.Map( + lo.Keys(tunnelUDPListeners), + func(key string, _ int) addrProxy { + parts := strings.Split(key, "/") + return addrProxy{ + network: "udp", + addr: parts[0], + target: parts[1], + proxy: parts[2], + } + }, + ) + oldElm := lo.Union(tcpOld, udpOld) + + newElm := lo.FlatMap( + tunnels, + func(tunnel config.Tunnel, _ int) []addrProxy { + return lo.Map( + tunnel.Network, + func(network string, _ int) addrProxy { + return addrProxy{ + network: network, + addr: tunnel.Address, + target: tunnel.Target, + proxy: tunnel.Proxy, + } + }, + ) + }, + ) + + needClose, needCreate := lo.Difference(oldElm, newElm) + + for _, elm := range needClose { + key := fmt.Sprintf("%s/%s/%s", elm.addr, elm.target, elm.proxy) + if elm.network == "tcp" { + tunnelTCPListeners[key].Close() + delete(tunnelTCPListeners, key) + } else { + tunnelUDPListeners[key].Close() + delete(tunnelUDPListeners, key) + } + } + + for _, elm := range needCreate { + key := fmt.Sprintf("%s/%s/%s", elm.addr, elm.target, elm.proxy) + if elm.network == "tcp" { + l, err := tunnel.New(elm.addr, elm.target, elm.proxy, tcpIn) + if err != nil { + log.Errorln("Start tunnel %s error: %w", elm.target, err) + continue + } + tunnelTCPListeners[key] = l + log.Infoln("Tunnel(tcp/%s) proxy %s listening at: %s", elm.target, elm.proxy, tunnelTCPListeners[key].Address()) + } else { + l, err := tunnel.NewUDP(elm.addr, elm.target, elm.proxy, udpIn) + if err != nil { + log.Errorln("Start tunnel %s error: %w", elm.target, err) + continue + } + tunnelUDPListeners[key] = l + log.Infoln("Tunnel(udp/%s) proxy %s listening at: %s", elm.target, elm.proxy, tunnelUDPListeners[key].Address()) + } + } +} + // GetPorts return the ports of proxy servers func GetPorts() *Ports { ports := &Ports{} diff --git a/listener/tunnel/packet.go b/listener/tunnel/packet.go new file mode 100644 index 00000000..0ade9726 --- /dev/null +++ b/listener/tunnel/packet.go @@ -0,0 +1,31 @@ +package tunnel + +import ( + "net" + + "github.com/Dreamacro/clash/common/pool" +) + +type packet struct { + pc net.PacketConn + rAddr net.Addr + payload []byte +} + +func (c *packet) Data() []byte { + return c.payload +} + +// WriteBack write UDP packet with source(ip, port) = `addr` +func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { + return c.pc.WriteTo(b, c.rAddr) +} + +// LocalAddr returns the source IP/Port of UDP Packet +func (c *packet) LocalAddr() net.Addr { + return c.rAddr +} + +func (c *packet) Drop() { + pool.Put(c.payload) +} diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go new file mode 100644 index 00000000..4ae5865c --- /dev/null +++ b/listener/tunnel/tcp.go @@ -0,0 +1,75 @@ +package tunnel + +import ( + "fmt" + "net" + + "github.com/Dreamacro/clash/adapter/inbound" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/transport/socks5" +) + +type Listener struct { + listener net.Listener + addr string + target socks5.Addr + proxy string + closed bool +} + +// RawAddress implements C.Listener +func (l *Listener) RawAddress() string { + return l.addr +} + +// Address implements C.Listener +func (l *Listener) Address() string { + return l.listener.Addr().String() +} + +// Close implements C.Listener +func (l *Listener) Close() error { + l.closed = true + return l.listener.Close() +} + +func (l *Listener) handleTCP(conn net.Conn, in chan<- C.ConnContext) { + conn.(*net.TCPConn).SetKeepAlive(true) + ctx := inbound.NewSocket(l.target, conn, C.TUNNEL) + ctx.Metadata().SpecialProxy = l.proxy + in <- ctx +} + +func New(addr, target, proxy string, in chan<- C.ConnContext) (*Listener, error) { + l, err := net.Listen("tcp", addr) + if err != nil { + return nil, err + } + + targetAddr := socks5.ParseAddr(target) + if targetAddr == nil { + return nil, fmt.Errorf("invalid target address %s", target) + } + + rl := &Listener{ + listener: l, + target: targetAddr, + proxy: proxy, + addr: addr, + } + + go func() { + for { + c, err := l.Accept() + if err != nil { + if rl.closed { + break + } + continue + } + go rl.handleTCP(c, in) + } + }() + + return rl, nil +} diff --git a/listener/tunnel/udp.go b/listener/tunnel/udp.go new file mode 100644 index 00000000..ee0ecbaf --- /dev/null +++ b/listener/tunnel/udp.go @@ -0,0 +1,85 @@ +package tunnel + +import ( + "fmt" + "net" + + "github.com/Dreamacro/clash/adapter/inbound" + "github.com/Dreamacro/clash/common/pool" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/transport/socks5" +) + +type PacketConn struct { + conn net.PacketConn + addr string + target socks5.Addr + proxy string + closed bool +} + +// RawAddress implements C.Listener +func (l *PacketConn) RawAddress() string { + return l.addr +} + +// Address implements C.Listener +func (l *PacketConn) Address() string { + return l.conn.LocalAddr().String() +} + +// Close implements C.Listener +func (l *PacketConn) Close() error { + l.closed = true + return l.conn.Close() +} + +func NewUDP(addr, target, proxy string, in chan<- *inbound.PacketAdapter) (*PacketConn, error) { + l, err := net.ListenPacket("udp", addr) + if err != nil { + return nil, err + } + + targetAddr := socks5.ParseAddr(target) + if targetAddr == nil { + return nil, fmt.Errorf("invalid target address %s", target) + } + + sl := &PacketConn{ + conn: l, + target: targetAddr, + proxy: proxy, + addr: addr, + } + go func() { + for { + buf := pool.Get(pool.UDPBufferSize) + n, remoteAddr, err := l.ReadFrom(buf) + if err != nil { + pool.Put(buf) + if sl.closed { + break + } + continue + } + sl.handleUDP(l, in, buf[:n], remoteAddr) + } + }() + + return sl, nil +} + +func (l *PacketConn) handleUDP(pc net.PacketConn, in chan<- *inbound.PacketAdapter, buf []byte, addr net.Addr) { + packet := &packet{ + pc: pc, + rAddr: addr, + payload: buf, + } + + ctx := inbound.NewPacket(l.target, packet, C.TUNNEL) + ctx.Metadata().SpecialProxy = l.proxy + select { + case in <- ctx: + default: + } +} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 0936056a..d659dd02 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -147,6 +147,15 @@ func preHandleMetadata(metadata *C.Metadata) error { } func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) { + if metadata.SpecialProxy != "" { + var exist bool + proxy, exist = proxies[metadata.SpecialProxy] + if !exist { + err = fmt.Errorf("proxy %s not found", metadata.SpecialProxy) + return + } + } + switch mode { case Direct: proxy = proxies["DIRECT"] @@ -249,6 +258,8 @@ func handleUDPConn(packet *inbound.PacketAdapter) { pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule) switch true { + case metadata.SpecialProxy != "": + log.Infoln("[UDP] %s --> %s using %s", metadata.SourceAddress(), metadata.RemoteAddress(), metadata.SpecialProxy) case rule != nil: log.Infoln( "[UDP] %s --> %s match %s(%s) using %s", @@ -320,6 +331,8 @@ func handleTCPConn(connCtx C.ConnContext) { defer remoteConn.Close() switch true { + case metadata.SpecialProxy != "": + log.Infoln("[TCP] %s --> %s using %s", metadata.SourceAddress(), metadata.RemoteAddress(), metadata.SpecialProxy) case rule != nil: log.Infoln( "[TCP] %s --> %s match %s(%s) using %s", From 8c6e205c5a560f6179f3efdc05b17f984c077932 Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Tue, 22 Nov 2022 19:16:08 +0800 Subject: [PATCH 2/5] Fix: tunnel proxy match --- tunnel/tunnel.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index d659dd02..bf09f23a 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -152,8 +152,8 @@ func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, r proxy, exist = proxies[metadata.SpecialProxy] if !exist { err = fmt.Errorf("proxy %s not found", metadata.SpecialProxy) - return } + return } switch mode { From efa4b9e0b8ac8aaf1c97bcfd48224d0ce8869139 Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Tue, 22 Nov 2022 21:01:51 +0800 Subject: [PATCH 3/5] Fix: lint warning --- listener/listener.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/listener/listener.go b/listener/listener.go index b5372327..972ca2d2 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -381,7 +381,7 @@ func PatchTunnel(tunnels []config.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan if elm.network == "tcp" { l, err := tunnel.New(elm.addr, elm.target, elm.proxy, tcpIn) if err != nil { - log.Errorln("Start tunnel %s error: %w", elm.target, err) + log.Errorln("Start tunnel %s error: %s", elm.target, err.Error()) continue } tunnelTCPListeners[key] = l @@ -389,7 +389,7 @@ func PatchTunnel(tunnels []config.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan } else { l, err := tunnel.NewUDP(elm.addr, elm.target, elm.proxy, udpIn) if err != nil { - log.Errorln("Start tunnel %s error: %w", elm.target, err) + log.Errorln("Start tunnel %s error: %s", elm.target, err.Error()) continue } tunnelUDPListeners[key] = l From ed988dcdc55fb5aa0b76e9fdf4ded38dc5b422bc Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+Dreamacro@users.noreply.github.com> Date: Fri, 25 Nov 2022 20:42:28 +0800 Subject: [PATCH 4/5] Chore: update dependencies --- go.mod | 10 +++++----- go.sum | 29 ++++++++++------------------- test/go.mod | 16 +++++++++------- test/go.sum | 38 +++++++++++++++++--------------------- 4 files changed, 41 insertions(+), 52 deletions(-) diff --git a/go.mod b/go.mod index 66eef6b1..52c0f472 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/gofrs/uuid v4.3.1+incompatible github.com/gorilla/websocket v1.5.0 github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c - github.com/mdlayher/netlink v1.6.2 + github.com/mdlayher/netlink v1.7.0 github.com/miekg/dns v1.1.50 github.com/oschwald/geoip2-golang v1.8.0 github.com/samber/lo v1.35.0 @@ -18,10 +18,10 @@ require ( go.etcd.io/bbolt v1.3.6 go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 - golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077 - golang.org/x/net v0.1.1-0.20221102181756-a1278a7f7ee0 + golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a + golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e golang.org/x/sync v0.1.0 - golang.org/x/sys v0.1.1-0.20221102194838-fc697a31fa06 + golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 gopkg.in/yaml.v3 v3.0.1 ) @@ -30,7 +30,7 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/josharian/native v1.0.0 // indirect - github.com/mdlayher/socket v0.2.3 // indirect + github.com/mdlayher/socket v0.4.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect diff --git a/go.sum b/go.sum index d92a0615..db742e0e 100644 --- a/go.sum +++ b/go.sum @@ -17,7 +17,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -39,12 +38,12 @@ github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= -github.com/mdlayher/netlink v1.6.2 h1:D2zGSkvYsJ6NreeED3JiVTu1lj2sIYATqSaZlhPzUgQ= -github.com/mdlayher/netlink v1.6.2/go.mod h1:O1HXX2sIWSMJ3Qn1BYZk1yZM+7iMki/uYGGiwGyq/iU= +github.com/mdlayher/netlink v1.7.0 h1:ZNGI4V7i1fJ94DPYtWhI/R85i/Q7ZxnuhUJQcJMoodI= +github.com/mdlayher/netlink v1.7.0/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= -github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= +github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= +github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= @@ -83,8 +82,8 @@ go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077 h1:t5bjOfJPQfaG9NV1imLZM5E2uzaLGs5/NtyMtRNVjQ4= -golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -93,7 +92,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -103,12 +101,10 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.1-0.20221102181756-a1278a7f7ee0 h1:vZ44Ys50wUISbPd+jC8cRLSvhyfX9Ii/ZmDnn/aiJtM= -golang.org/x/net v0.1.1-0.20221102181756-a1278a7f7ee0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e h1:IVOjWZQH/57UDcpX19vSmMz8w3ohroOMWohn8qWpRkg= +golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -129,19 +125,14 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.1-0.20221102194838-fc697a31fa06 h1:E1pm64FqQa4v8dHd/bAneyMkR4hk8LTJhoSlc5mc1cM= -golang.org/x/sys v0.1.1-0.20221102194838-fc697a31fa06/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 h1:pvmSpBoSG0gD2LLPAX15QHPig8xsbU0tu1sSAmResqk= +golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 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= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/test/go.mod b/test/go.mod index cad844ec..b9ec5387 100644 --- a/test/go.mod +++ b/test/go.mod @@ -3,12 +3,12 @@ module clash-test go 1.19 require ( - github.com/Dreamacro/clash v1.11.4 - github.com/docker/docker v20.10.17+incompatible + github.com/Dreamacro/clash v1.11.12 + github.com/docker/docker v20.10.21+incompatible github.com/docker/go-connections v0.4.0 github.com/miekg/dns v1.1.50 github.com/stretchr/testify v1.8.1 - golang.org/x/net v0.1.1-0.20221102181756-a1278a7f7ee0 + golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e ) replace github.com/Dreamacro/clash => ../ @@ -24,8 +24,8 @@ require ( github.com/gorilla/websocket v1.5.0 // indirect github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c // indirect github.com/josharian/native v1.0.0 // indirect - github.com/mdlayher/netlink v1.6.2 // indirect - github.com/mdlayher/socket v0.2.3 // indirect + github.com/mdlayher/netlink v1.7.0 // indirect + github.com/mdlayher/socket v0.4.0 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -34,14 +34,16 @@ require ( github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/samber/lo v1.35.0 // indirect github.com/sirupsen/logrus v1.9.0 // indirect github.com/u-root/uio v0.0.0-20210528114334-82958018845c // indirect go.etcd.io/bbolt v1.3.6 // indirect go.uber.org/atomic v1.10.0 // indirect - golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077 // indirect + golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a // indirect + golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 // indirect golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.1.1-0.20221102194838-fc697a31fa06 // indirect + golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 // indirect golang.org/x/text v0.4.0 // indirect golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 // indirect golang.org/x/tools v0.1.12 // indirect diff --git a/test/go.sum b/test/go.sum index d1ddf83f..69db4f48 100644 --- a/test/go.sum +++ b/test/go.sum @@ -8,8 +8,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE= -github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v20.10.21+incompatible h1:UTLdBmHk3bEY+w8qeO5KttOhy6OmXWsl/FEet9Uswog= +github.com/docker/docker v20.10.21+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= @@ -25,7 +25,6 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= @@ -53,12 +52,12 @@ github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= -github.com/mdlayher/netlink v1.6.2 h1:D2zGSkvYsJ6NreeED3JiVTu1lj2sIYATqSaZlhPzUgQ= -github.com/mdlayher/netlink v1.6.2/go.mod h1:O1HXX2sIWSMJ3Qn1BYZk1yZM+7iMki/uYGGiwGyq/iU= +github.com/mdlayher/netlink v1.7.0 h1:ZNGI4V7i1fJ94DPYtWhI/R85i/Q7ZxnuhUJQcJMoodI= +github.com/mdlayher/netlink v1.7.0/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/socket v0.2.3 h1:XZA2X2TjdOwNoNPVPclRCURoX/hokBY8nkTmRZFEheM= -github.com/mdlayher/socket v0.2.3/go.mod h1:bz12/FozYNH/VbvC3q7TRIK/Y6dH1kCKsXaUeXi/FmY= +github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= +github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc= @@ -78,6 +77,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 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/samber/lo v1.35.0 h1:GlT8CV1GE+v97Y7MLF1wXvX6mjoxZ+hi61tj/ZcQwY0= +github.com/samber/lo v1.35.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= @@ -94,6 +95,7 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -106,8 +108,10 @@ go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077 h1:t5bjOfJPQfaG9NV1imLZM5E2uzaLGs5/NtyMtRNVjQ4= -golang.org/x/crypto v0.1.1-0.20221024173537-a3485e174077/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U= +golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17 h1:3MTrJm4PyNL9NBqvYDSj3DHl46qQakyfqfWo4jgfaEM= +golang.org/x/exp v0.0.0-20220303212507-bbda1eaf7a17/go.mod h1:lgLbSvA5ygNOMpwM/9anMpWVlVJ7Z+cHWq/eFuinpGE= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -116,7 +120,6 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -128,14 +131,12 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20220923203811-8be639271d50/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk= -golang.org/x/net v0.1.1-0.20221102181756-a1278a7f7ee0 h1:vZ44Ys50wUISbPd+jC8cRLSvhyfX9Ii/ZmDnn/aiJtM= -golang.org/x/net v0.1.1-0.20221102181756-a1278a7f7ee0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= +golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e h1:IVOjWZQH/57UDcpX19vSmMz8w3ohroOMWohn8qWpRkg= +golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220923202941-7f9b1623fab7/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -159,20 +160,15 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.1-0.20221102194838-fc697a31fa06 h1:E1pm64FqQa4v8dHd/bAneyMkR4hk8LTJhoSlc5mc1cM= -golang.org/x/sys v0.1.1-0.20221102194838-fc697a31fa06/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 h1:pvmSpBoSG0gD2LLPAX15QHPig8xsbU0tu1sSAmResqk= +golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 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= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= From 90b40a8e5a81a6bf0d07985d6f037c7ed66721a9 Mon Sep 17 00:00:00 2001 From: Sizhe Sun Date: Sat, 26 Nov 2022 11:27:24 +0800 Subject: [PATCH 5/5] Fix: drop UDP packet which mismatched destination for VMess (#2410) Co-authored-by: SUN Sizhe --- adapter/outbound/vmess.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 31d0a2cf..aaa9105d 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -20,6 +20,8 @@ import ( "golang.org/x/net/http2" ) +var ErrUDPRemoteAddrMismatch = errors.New("udp packet dropped due to mismatched remote address") + type Vmess struct { *Base client *vmess.Client @@ -358,7 +360,14 @@ type vmessPacketConn struct { rAddr net.Addr } +// WriteTo implments C.PacketConn.WriteTo +// Since VMess doesn't support full cone NAT by design, we verify if addr matches uc.rAddr, and drop the packet if not. func (uc *vmessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { + allowedAddr := uc.rAddr.(*net.UDPAddr) + destAddr := addr.(*net.UDPAddr) + if !(allowedAddr.IP.Equal(destAddr.IP) && allowedAddr.Port == destAddr.Port) { + return 0, ErrUDPRemoteAddrMismatch + } return uc.Conn.Write(b) }