From 9b6e56a65e99c9636fea62dfb1b78d5521072b37 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 1 Jun 2023 16:25:02 +0800 Subject: [PATCH 01/79] chore: update quic-go to 0.34.0 --- go.mod | 6 +++--- go.sum | 12 ++++++------ transport/tuic/server.go | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index b79f8e70..b7b774cc 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/klauspost/cpuid/v2 v2.0.12 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 - github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 + github.com/metacubex/quic-go v0.34.1-0.20230601081651-513972f322ee github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e @@ -85,8 +85,8 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.2.1 // indirect - github.com/quic-go/qtls-go1-20 v0.1.1 // indirect + github.com/quic-go/qtls-go1-19 v0.3.2 // indirect + github.com/quic-go/qtls-go1-20 v0.2.2 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect diff --git a/go.sum b/go.sum index 11d98c03..053f0ced 100644 --- a/go.sum +++ b/go.sum @@ -94,8 +94,8 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= -github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 h1:E/sNW9tugFjoBjAkth89MHlKHRaMdo43tGQ3MOPVayQ= -github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= +github.com/metacubex/quic-go v0.34.1-0.20230601081651-513972f322ee h1:BcLrrY8wYQ/XdCVXdofXei2i8BDfWNn5ojbM8gQPJyw= +github.com/metacubex/quic-go v0.34.1-0.20230601081651-513972f322ee/go.mod h1:6pg8+Tje9KOltnj1whuvB2i5KFUMPp1TAF3oPhc5axM= github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b h1:Bw4j3ktf5vivi5qm/ZQGtyRAgybRKSGJaMV1t3rtC+I= github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c h1:LpVNvlW/xE+mR8z76xJeYZlYznZXEmU4TeWeuygYdJg= @@ -136,10 +136,10 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A= -github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk= -github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= +github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= +github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 00c33fcb..fa0537b9 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -93,7 +93,7 @@ func (s *serverHandler) handle() { _ = s.handleMessage() }() - <-s.quicConn.HandshakeComplete().Done() + <-s.quicConn.HandshakeComplete() time.AfterFunc(s.AuthenticationTimeout, func() { s.authOnce.Do(func() { _ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout") From 26acaee424372218e7b962b1e3f55189a5b4589b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 2 Jun 2023 18:26:51 +0800 Subject: [PATCH 02/79] fix: handle manually select in url-test --- adapter/outboundgroup/urltest.go | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 5b0d2a17..442494d9 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -96,25 +96,30 @@ func (u *URLTest) Unwrap(metadata *C.Metadata, touch bool) C.Proxy { } func (u *URLTest) fast(touch bool) C.Proxy { - elm, _, shared := u.fastSingle.Do(func() (C.Proxy, error) { - var s C.Proxy - proxies := u.GetProxies(touch) - fast := proxies[0] - if fast.Name() == u.selected { - s = fast + + proxies := u.GetProxies(touch) + if u.selected != "" { + for _, proxy := range proxies { + if !proxy.Alive() { + continue + } + if proxy.Name() == u.selected { + u.fastNode = proxy + return proxy + } } + } + + elm, _, shared := u.fastSingle.Do(func() (C.Proxy, error) { + fast := proxies[0] min := fast.LastDelay() fastNotExist := true for _, proxy := range proxies[1:] { - if u.fastNode != nil && proxy.Name() == u.fastNode.Name() { fastNotExist = false } - if proxy.Name() == u.selected { - s = proxy - } if !proxy.Alive() { continue } @@ -124,16 +129,12 @@ func (u *URLTest) fast(touch bool) C.Proxy { fast = proxy min = delay } + } // tolerance if u.fastNode == nil || fastNotExist || !u.fastNode.Alive() || u.fastNode.LastDelay() > fast.LastDelay()+u.tolerance { u.fastNode = fast } - if s != nil { - if s.Alive() && s.LastDelay() < fast.LastDelay()+u.tolerance { - u.fastNode = s - } - } return u.fastNode, nil }) if shared && touch { // a shared fastSingle.Do() may cause providers untouched, so we touch them again From 17565ec93b3f9aefd6abd13841f15d71d958e636 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 2 Jun 2023 22:58:33 +0800 Subject: [PATCH 03/79] chore: Reject packet conn implement wait read --- adapter/outbound/reject.go | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index a469ed2a..a72dc377 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -78,8 +78,11 @@ type nopPacketConn struct{} func (npc nopPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { return len(b), nil } func (npc nopPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return 0, nil, io.EOF } -func (npc nopPacketConn) Close() error { return nil } -func (npc nopPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified } -func (npc nopPacketConn) SetDeadline(time.Time) error { return nil } -func (npc nopPacketConn) SetReadDeadline(time.Time) error { return nil } -func (npc nopPacketConn) SetWriteDeadline(time.Time) error { return nil } +func (npc nopPacketConn) WaitReadFrom() ([]byte, func(), net.Addr, error) { + return nil, nil, nil, io.EOF +} +func (npc nopPacketConn) Close() error { return nil } +func (npc nopPacketConn) LocalAddr() net.Addr { return udpAddrIPv4Unspecified } +func (npc nopPacketConn) SetDeadline(time.Time) error { return nil } +func (npc nopPacketConn) SetReadDeadline(time.Time) error { return nil } +func (npc nopPacketConn) SetWriteDeadline(time.Time) error { return nil } From 7906fbfee65a020b1bd5c3b50c2582a0697321eb Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 3 Jun 2023 00:24:51 +0800 Subject: [PATCH 04/79] chore: Update dependencies --- go.mod | 28 +++++++++++++------------- go.sum | 63 +++++++++++++++++++++++++++++----------------------------- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/go.mod b/go.mod index b7b774cc..d7d6a9a8 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da github.com/cilium/ebpf v0.10.0 github.com/coreos/go-iptables v0.6.0 - github.com/dlclark/regexp2 v1.9.0 + github.com/dlclark/regexp2 v1.10.0 github.com/go-chi/chi/v5 v5.0.8 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.2 @@ -15,9 +15,9 @@ require ( github.com/google/gopacket v1.1.19 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/golang-lru v0.5.4 - github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 + github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb github.com/jpillora/backoff v1.0.0 - github.com/klauspost/cpuid/v2 v2.0.12 + github.com/klauspost/cpuid/v2 v2.2.5 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/quic-go v0.34.1-0.20230601081651-513972f322ee @@ -32,27 +32,27 @@ require ( github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 - github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b + github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3 github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 github.com/samber/lo v1.38.1 - github.com/shirou/gopsutil/v3 v3.23.4 - github.com/sirupsen/logrus v1.9.0 - github.com/stretchr/testify v1.8.2 + github.com/shirou/gopsutil/v3 v3.23.5 + github.com/sirupsen/logrus v1.9.2 + github.com/stretchr/testify v1.8.3 github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.9.0 - golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 + golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 golang.org/x/net v0.10.0 golang.org/x/sync v0.2.0 golang.org/x/sys v0.8.0 google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v3 v3.0.1 - lukechampine.com/blake3 v1.1.7 + lukechampine.com/blake3 v1.2.1 ) require ( @@ -69,7 +69,7 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/golang/mock v1.6.0 // indirect - github.com/google/btree v1.1.2 // indirect + github.com/google/btree v1.0.1 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -90,19 +90,19 @@ require ( github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect - github.com/shoenig/go-m1cpu v0.1.5 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect - github.com/vishvananda/netns v0.0.4 // indirect - github.com/yusufpapurcu/wmi v1.2.2 // indirect + github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.3.0 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.org/x/tools v0.6.0 // indirect ) diff --git a/go.sum b/go.sum index 053f0ced..a2c2e197 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,8 @@ github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFE 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= -github.com/dlclark/regexp2 v1.9.0 h1:pTK/l/3qYIKaRXuHnEnIf7Y5NxfRPfpb7dis6/gdlVI= -github.com/dlclark/regexp2 v1.9.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= +github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 h1:/5RkVc9Rc81XmMyVqawCiDyrBHZbLAZgTTCqou4mwj8= github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9/go.mod h1:hkIFzoiIPZYxdFOOLyDho59b7SrDfo+w3h+yWdlg45I= github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 h1:8j2RH289RJplhA6WfdaPqzg1MjH2K8wX5e0uhAxrw2g= @@ -52,8 +52,8 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= -github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= +github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= +github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= @@ -70,8 +70,8 @@ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 h1:+aAGyK41KRn8jbF2Q7PLL0Sxwg6dShGcQSeCC7nZQ8E= -github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI= +github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb h1:6fDKEAXwe3rsfS4khW3EZ8kEqmSiV9szhMPcDrD+Y7Q= +github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -79,9 +79,8 @@ github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2E github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= @@ -147,8 +146,8 @@ github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6E github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 h1:X3ADfMqeGns1Q1FlXc9kaL9FwW1UM6D6tEQo8jFstpc= github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= -github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4= -github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI= +github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3 h1:PNwJs1F+3e/iZguYQR7YzxsH8Sm0Eu7vVuHawD89r34= +github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= @@ -161,20 +160,20 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o= -github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8= -github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ= -github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= -github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c= -github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y= +github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b/go.mod h1:X7qrxNQViEaAN9LNZOPl9PfvQtp3V3c7LTo0dvGi0fM= github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6yjG3IxDaeAj3PCoRr+IsO+bzyT+Se2m2Hk= github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c/go.mod h1:NV/a66PhhWYVmUMaotlXJ8fIEFB98u+c8l/CQIEFLrU= github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIFG3i4Gi093BQITvwH9znsz2VUZmnmwHvpIo= github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -184,21 +183,21 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= -github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= -github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM= github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= @@ -211,8 +210,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o= -golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -232,6 +231,7 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -240,6 +240,7 @@ 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-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -248,8 +249,8 @@ 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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= -golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= +golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -269,5 +270,5 @@ gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= -lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= +lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= From 2c44b4e170e96d0383b78159bb56c201416e1537 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 3 Jun 2023 16:45:35 +0800 Subject: [PATCH 05/79] chore: update quic-go to 0.35.1 --- adapter/outbound/tuic.go | 13 ++++---- dns/doh.go | 12 +++++++- dns/doq.go | 23 +++++++++------ go.mod | 2 +- go.sum | 4 +-- listener/tuic/server.go | 4 +-- transport/hysteria/transport/client.go | 5 +++- transport/tuic/client.go | 9 +++--- transport/tuic/pool_client.go | 41 ++++++++++++++++---------- transport/tuic/server.go | 2 +- 10 files changed, 68 insertions(+), 47 deletions(-) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index f2452ae2..ab371757 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -90,11 +90,7 @@ func (t *Tuic) SupportWithDialer() C.NetWork { return C.ALLNet } -func (t *Tuic) dial(ctx context.Context, opts ...dialer.Option) (pc net.PacketConn, addr net.Addr, err error) { - return t.dialWithDialer(ctx, dialer.NewDialer(opts...)) -} - -func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (pc net.PacketConn, addr net.Addr, err error) { +func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) { if len(t.option.DialerProxy) > 0 { dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer) if err != nil { @@ -106,10 +102,14 @@ func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (pc net.Pack return nil, nil, err } addr = udpAddr + var pc net.PacketConn pc, err = dialer.ListenPacket(ctx, "udp", "", udpAddr.AddrPort()) if err != nil { return nil, nil, err } + transport = &quic.Transport{Conn: pc} + transport.SetCreatedConn(true) // auto close conn + transport.SetSingleUse(true) // auto close transport return } @@ -220,9 +220,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { if len(option.Ip) > 0 { addr = net.JoinHostPort(option.Ip, strconv.Itoa(option.Port)) } - host := option.Server if option.DisableSni { - host = "" tlsConfig.ServerName = "" } tkn := tuic.GenTKN(option.Token) @@ -254,7 +252,6 @@ func NewTuic(option TuicOption) (*Tuic, error) { clientOption := &tuic.ClientOption{ TlsConfig: tlsConfig, QuicConfig: quicConfig, - Host: host, Token: tkn, UdpRelayMode: option.UdpRelayMode, CongestionController: option.CongestionController, diff --git a/dns/doh.go b/dns/doh.go index dd8ba435..49e502fd 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -543,7 +543,17 @@ func (doh *dnsOverHTTPS) dialQuic(ctx context.Context, addr string, tlsCfg *tls. if err != nil { return nil, err } - return quic.DialEarlyContext(ctx, conn, &udpAddr, doh.url.Host, tlsCfg, cfg) + transport := quic.Transport{Conn: conn} + transport.SetCreatedConn(true) // auto close conn + transport.SetSingleUse(true) // auto close transport + tlsCfg = tlsCfg.Clone() + if host, _, err := net.SplitHostPort(doh.url.Host); err == nil { + tlsCfg.ServerName = host + } else { + // It's ok if net.SplitHostPort returns an error - it could be a hostname/IP address without a port. + tlsCfg.ServerName = doh.url.Host + } + return transport.DialEarly(ctx, &udpAddr, tlsCfg, cfg) } // probeH3 runs a test to check whether QUIC is faster than TLS for this diff --git a/dns/doq.go b/dns/doq.go index 73310340..f0016d79 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -302,14 +302,6 @@ func (doq *dnsOverQUIC) openStream(ctx context.Context, conn quic.Connection) (q // openConnection opens a new QUIC connection. func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connection, err error) { - tlsConfig := tlsC.GetGlobalTLSConfig( - &tls.Config{ - InsecureSkipVerify: false, - NextProtos: []string{ - NextProtoDQ, - }, - SessionTicketsDisabled: false, - }) // we're using bootstrapped address instead of what's passed to the function // it does not create an actual connection, but it helps us determine // what IP is actually reachable (when there're v4/v6 addresses). @@ -338,7 +330,20 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connectio return nil, err } - conn, err = quic.DialContext(ctx, udp, &udpAddr, host, tlsConfig, doq.getQUICConfig()) + tlsConfig := tlsC.GetGlobalTLSConfig( + &tls.Config{ + ServerName: host, + InsecureSkipVerify: false, + NextProtos: []string{ + NextProtoDQ, + }, + SessionTicketsDisabled: false, + }) + + transport := quic.Transport{Conn: udp} + transport.SetCreatedConn(true) // auto close conn + transport.SetSingleUse(true) // auto close transport + conn, err = transport.Dial(ctx, &udpAddr, tlsConfig, doq.getQUICConfig()) if err != nil { return nil, fmt.Errorf("opening quic connection to %s: %w", doq.addr, err) } diff --git a/go.mod b/go.mod index d7d6a9a8..89071513 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 - github.com/metacubex/quic-go v0.34.1-0.20230601081651-513972f322ee + github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e diff --git a/go.sum b/go.sum index a2c2e197..d4c2e2f4 100644 --- a/go.sum +++ b/go.sum @@ -93,8 +93,8 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= -github.com/metacubex/quic-go v0.34.1-0.20230601081651-513972f322ee h1:BcLrrY8wYQ/XdCVXdofXei2i8BDfWNn5ojbM8gQPJyw= -github.com/metacubex/quic-go v0.34.1-0.20230601081651-513972f322ee/go.mod h1:6pg8+Tje9KOltnj1whuvB2i5KFUMPp1TAF3oPhc5axM= +github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb h1:92YTNmYXCSycERjKn/zPbeK5DiW3dd80j3+oVTEWTE8= +github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb/go.mod h1:6pg8+Tje9KOltnj1whuvB2i5KFUMPp1TAF3oPhc5axM= github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b h1:Bw4j3ktf5vivi5qm/ZQGtyRAgybRKSGJaMV1t3rtC+I= github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c h1:LpVNvlW/xE+mR8z76xJeYZlYznZXEmU4TeWeuygYdJg= diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 92cc0b37..498708bf 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -52,9 +52,7 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet MaxIncomingStreams: ServerMaxIncomingStreams, MaxIncomingUniStreams: ServerMaxIncomingStreams, EnableDatagrams: true, - Allow0RTT: func(addr net.Addr) bool { - return true - }, + Allow0RTT: true, } quicConfig.InitialStreamReceiveWindow = tuic.DefaultStreamReceiveWindow / 10 quicConfig.MaxStreamReceiveWindow = tuic.DefaultStreamReceiveWindow diff --git a/transport/hysteria/transport/client.go b/transport/hysteria/transport/client.go index e65e5016..67568bc8 100644 --- a/transport/hysteria/transport/client.go +++ b/transport/hysteria/transport/client.go @@ -76,7 +76,10 @@ func (ct *ClientTransport) QUICDial(proto string, server string, serverPorts str return nil, err } - qs, err := quic.DialContext(dialer.Context(), pktConn, serverUDPAddr, server, tlsConfig, quicConfig) + transport := quic.Transport{Conn: pktConn} + transport.SetCreatedConn(true) // auto close conn + transport.SetSingleUse(true) // auto close transport + qs, err := transport.Dial(dialer.Context(), serverUDPAddr, tlsConfig, quicConfig) if err != nil { _ = pktConn.Close() return nil, err diff --git a/transport/tuic/client.go b/transport/tuic/client.go index c18a9049..6fd2a241 100644 --- a/transport/tuic/client.go +++ b/transport/tuic/client.go @@ -28,12 +28,11 @@ var ( TooManyOpenStreams = errors.New("tuic: too many open streams") ) -type DialFunc func(ctx context.Context, dialer C.Dialer) (pc net.PacketConn, addr net.Addr, err error) +type DialFunc func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) type ClientOption struct { TlsConfig *tls.Config QuicConfig *quic.Config - Host string Token [32]byte UdpRelayMode string CongestionController string @@ -67,15 +66,15 @@ func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn Di if t.quicConn != nil { return t.quicConn, nil } - pc, addr, err := dialFn(ctx, dialer) + transport, addr, err := dialFn(ctx, dialer) if err != nil { return nil, err } var quicConn quic.Connection if t.ReduceRtt { - quicConn, err = quic.DialEarlyContext(ctx, pc, addr, t.Host, t.TlsConfig, t.QuicConfig) + quicConn, err = transport.DialEarly(ctx, addr, t.TlsConfig, t.QuicConfig) } else { - quicConn, err = quic.DialContext(ctx, pc, addr, t.Host, t.TlsConfig, t.QuicConfig) + quicConn, err = transport.Dial(ctx, addr, t.TlsConfig, t.QuicConfig) } if err != nil { return nil, err diff --git a/transport/tuic/pool_client.go b/transport/tuic/pool_client.go index 04ada7c0..223436cd 100644 --- a/transport/tuic/pool_client.go +++ b/transport/tuic/pool_client.go @@ -12,12 +12,14 @@ import ( N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" + + "github.com/metacubex/quic-go" ) type dialResult struct { - pc net.PacketConn - addr net.Addr - err error + transport *quic.Transport + addr net.Addr + err error } type PoolClient struct { @@ -33,9 +35,12 @@ type PoolClient struct { } func (t *PoolClient) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.Conn, error) { - conn, err := t.getClient(false, dialer).DialContextWithDialer(ctx, metadata, dialer, dialFn) + newDialFn := func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) { + return t.dial(ctx, dialer, dialFn) + } + conn, err := t.getClient(false, dialer).DialContextWithDialer(ctx, metadata, dialer, newDialFn) if errors.Is(err, TooManyOpenStreams) { - conn, err = t.newClient(false, dialer).DialContextWithDialer(ctx, metadata, dialer, dialFn) + conn, err = t.newClient(false, dialer).DialContextWithDialer(ctx, metadata, dialer, newDialFn) } if err != nil { return nil, err @@ -44,9 +49,12 @@ func (t *PoolClient) DialContextWithDialer(ctx context.Context, metadata *C.Meta } func (t *PoolClient) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) { - pc, err := t.getClient(true, dialer).ListenPacketWithDialer(ctx, metadata, dialer, dialFn) + newDialFn := func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) { + return t.dial(ctx, dialer, dialFn) + } + pc, err := t.getClient(true, dialer).ListenPacketWithDialer(ctx, metadata, dialer, newDialFn) if errors.Is(err, TooManyOpenStreams) { - pc, err = t.newClient(true, dialer).ListenPacketWithDialer(ctx, metadata, dialer, dialFn) + pc, err = t.newClient(true, dialer).ListenPacketWithDialer(ctx, metadata, dialer, newDialFn) } if err != nil { return nil, err @@ -54,37 +62,38 @@ func (t *PoolClient) ListenPacketWithDialer(ctx context.Context, metadata *C.Met return N.NewRefPacketConn(pc, t), nil } -func (t *PoolClient) dial(ctx context.Context, dialer C.Dialer, dialFn DialFunc) (pc net.PacketConn, addr net.Addr, err error) { +func (t *PoolClient) dial(ctx context.Context, dialer C.Dialer, dialFn DialFunc) (transport *quic.Transport, addr net.Addr, err error) { t.dialResultMutex.Lock() dr, ok := t.dialResultMap[dialer] t.dialResultMutex.Unlock() if ok { - return dr.pc, dr.addr, dr.err + return dr.transport, dr.addr, dr.err } - pc, addr, err = dialFn(ctx, dialer) + transport, addr, err = dialFn(ctx, dialer) if err != nil { return nil, nil, err } - if _, ok := pc.(*net.UDPConn); ok { // only cache the system's UDPConn - dr.pc, dr.addr, dr.err = pc, addr, err + if _, ok := transport.Conn.(*net.UDPConn); ok { // only cache the system's UDPConn + transport.SetSingleUse(false) // don't close transport in each dial + dr.transport, dr.addr, dr.err = transport, addr, err t.dialResultMutex.Lock() t.dialResultMap[dialer] = dr t.dialResultMutex.Unlock() } - return pc, addr, err + return transport, addr, err } func (t *PoolClient) forceClose() { t.dialResultMutex.Lock() defer t.dialResultMutex.Unlock() for key := range t.dialResultMap { - pc := t.dialResultMap[key].pc - if pc != nil { - _ = pc.Close() + transport := t.dialResultMap[key].transport + if transport != nil { + _ = transport.Close() } delete(t.dialResultMap, key) } diff --git a/transport/tuic/server.go b/transport/tuic/server.go index fa0537b9..f8c4b20a 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -35,7 +35,7 @@ type ServerOption struct { type Server struct { *ServerOption - listener quic.EarlyListener + listener *quic.EarlyListener } func NewServer(option *ServerOption, pc net.PacketConn) (*Server, error) { From 2af758e5f1c0958f969ad2344c7acefeee3e196d Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 26 May 2023 15:00:54 +0000 Subject: [PATCH 06/79] chore: Random only if the certificate and private-key are empty --- common/net/tls.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/net/tls.go b/common/net/tls.go index 5e1c81f2..e51324f7 100644 --- a/common/net/tls.go +++ b/common/net/tls.go @@ -11,7 +11,7 @@ import ( ) func ParseCert(certificate, privateKey string) (tls.Certificate, error) { - if certificate == "" || privateKey == "" { + if certificate == "" && privateKey == "" { return newRandomTLSKeyPair() } cert, painTextErr := tls.X509KeyPair([]byte(certificate), []byte(privateKey)) From 63b53871645412289058f12f48c442612ba168be Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 3 Jun 2023 21:40:09 +0800 Subject: [PATCH 07/79] chore: update proxy's udpConn when received a new packet --- component/nat/proxy.go | 26 ++++++++++++++++++++++++++ component/nat/table.go | 10 ++++++---- constant/adapters.go | 17 +++++++++++++---- listener/shadowsocks/udp.go | 4 ++-- listener/shadowsocks/utils.go | 2 ++ listener/socks/udp.go | 20 ++++++++++++-------- listener/socks/utils.go | 9 ++++++--- listener/tproxy/packet.go | 3 ++- listener/tunnel/packet.go | 3 ++- tunnel/connection.go | 4 ++-- tunnel/tunnel.go | 10 +++++++--- 11 files changed, 80 insertions(+), 28 deletions(-) create mode 100644 component/nat/proxy.go diff --git a/component/nat/proxy.go b/component/nat/proxy.go new file mode 100644 index 00000000..29ff3c81 --- /dev/null +++ b/component/nat/proxy.go @@ -0,0 +1,26 @@ +package nat + +import ( + "net" + + "github.com/Dreamacro/clash/common/atomic" + C "github.com/Dreamacro/clash/constant" +) + +type writeBackProxy struct { + wb atomic.TypedValue[C.WriteBack] +} + +func (w *writeBackProxy) WriteBack(b []byte, addr net.Addr) (n int, err error) { + return w.wb.Load().WriteBack(b, addr) +} + +func (w *writeBackProxy) UpdateWriteBack(wb C.WriteBack) { + w.wb.Store(wb) +} + +func NewWriteBackProxy(wb C.WriteBack) C.WriteBackProxy { + w := &writeBackProxy{} + w.UpdateWriteBack(wb) + return w +} diff --git a/component/nat/table.go b/component/nat/table.go index 5dcd91ed..adc6eace 100644 --- a/component/nat/table.go +++ b/component/nat/table.go @@ -13,22 +13,24 @@ type Table struct { type Entry struct { PacketConn C.PacketConn + WriteBackProxy C.WriteBackProxy LocalUDPConnMap sync.Map } -func (t *Table) Set(key string, e C.PacketConn) { +func (t *Table) Set(key string, e C.PacketConn, w C.WriteBackProxy) { t.mapping.Store(key, &Entry{ PacketConn: e, + WriteBackProxy: w, LocalUDPConnMap: sync.Map{}, }) } -func (t *Table) Get(key string) C.PacketConn { +func (t *Table) Get(key string) (C.PacketConn, C.WriteBackProxy) { entry, exist := t.getEntry(key) if !exist { - return nil + return nil, nil } - return entry.PacketConn + return entry.PacketConn, entry.WriteBackProxy } func (t *Table) GetOrCreateLock(key string) (*sync.Cond, bool) { diff --git a/constant/adapters.go b/constant/adapters.go index 12579685..39b7d6eb 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -217,7 +217,7 @@ type UDPPacket interface { // - variable source IP/Port is important to STUN // - if addr is not provided, WriteBack will write out UDP packet with SourceIP/Port equals to original Target, // this is important when using Fake-IP. - WriteBack(b []byte, addr net.Addr) (n int, err error) + WriteBack // Drop call after packet is used, could recycle buffer in this function. Drop() @@ -236,10 +236,19 @@ type PacketAdapter interface { Metadata() *Metadata } -type NatTable interface { - Set(key string, e PacketConn) +type WriteBack interface { + WriteBack(b []byte, addr net.Addr) (n int, err error) +} - Get(key string) PacketConn +type WriteBackProxy interface { + WriteBack + UpdateWriteBack(wb WriteBack) +} + +type NatTable interface { + Set(key string, e PacketConn, w WriteBackProxy) + + Get(key string) (PacketConn, WriteBackProxy) GetOrCreateLock(key string) (*sync.Cond, bool) diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index 4efafa60..af610431 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -58,7 +58,7 @@ func (l *UDPListener) LocalAddr() net.Addr { return l.packetConn.LocalAddr() } -func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, put func(), addr net.Addr) { +func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, put func(), addr net.Addr, additions ...inbound.Addition) { tgtAddr := socks5.SplitAddr(buf) if tgtAddr == nil { // Unresolved UDP packet, return buffer to the pool @@ -77,7 +77,7 @@ func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, pu put: put, } select { - case in <- inbound.NewPacket(target, packet, C.SHADOWSOCKS): + case in <- inbound.NewPacket(target, packet, C.SHADOWSOCKS, additions...): default: } } diff --git a/listener/shadowsocks/utils.go b/listener/shadowsocks/utils.go index c34c5cd0..a732cbbe 100644 --- a/listener/shadowsocks/utils.go +++ b/listener/shadowsocks/utils.go @@ -38,7 +38,9 @@ func (c *packet) LocalAddr() net.Addr { func (c *packet) Drop() { if c.put != nil { c.put() + c.put = nil } + c.payload = nil } func (c *packet) InAddr() net.Addr { diff --git a/listener/socks/udp.go b/listener/socks/udp.go index f375dade..31858f74 100644 --- a/listener/socks/udp.go +++ b/listener/socks/udp.go @@ -4,7 +4,7 @@ import ( "net" "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/pool" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/sockopt" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" @@ -53,36 +53,40 @@ func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Additio packetConn: l, addr: addr, } + conn := N.NewEnhancePacketConn(l) go func() { for { - buf := pool.Get(pool.UDPBufferSize) - n, remoteAddr, err := l.ReadFrom(buf) + data, put, remoteAddr, err := conn.WaitReadFrom() if err != nil { - pool.Put(buf) + if put != nil { + put() + } if sl.closed { break } continue } - handleSocksUDP(l, in, buf[:n], remoteAddr, additions...) + handleSocksUDP(l, in, data, put, remoteAddr, additions...) } }() return sl, nil } -func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, addr net.Addr, additions ...inbound.Addition) { +func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, put func(), addr net.Addr, additions ...inbound.Addition) { target, payload, err := socks5.DecodeUDPPacket(buf) if err != nil { // Unresolved UDP packet, return buffer to the pool - pool.Put(buf) + if put != nil { + put() + } return } packet := &packet{ pc: pc, rAddr: addr, payload: payload, - bufRef: buf, + put: put, } select { case in <- inbound.NewPacket(target, packet, C.SOCKS5, additions...): diff --git a/listener/socks/utils.go b/listener/socks/utils.go index 4c53b9e5..3456b595 100644 --- a/listener/socks/utils.go +++ b/listener/socks/utils.go @@ -3,7 +3,6 @@ package socks import ( "net" - "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/transport/socks5" ) @@ -11,7 +10,7 @@ type packet struct { pc net.PacketConn rAddr net.Addr payload []byte - bufRef []byte + put func() } func (c *packet) Data() []byte { @@ -33,7 +32,11 @@ func (c *packet) LocalAddr() net.Addr { } func (c *packet) Drop() { - pool.Put(c.bufRef) + if c.put != nil { + c.put() + c.put = nil + } + c.payload = nil } func (c *packet) InAddr() net.Addr { diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index 4967adc6..2966fd2e 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -41,7 +41,8 @@ func (c *packet) LocalAddr() net.Addr { } func (c *packet) Drop() { - pool.Put(c.buf) + _ = pool.Put(c.buf) + c.buf = nil } func (c *packet) InAddr() net.Addr { diff --git a/listener/tunnel/packet.go b/listener/tunnel/packet.go index 602f7675..35601e38 100644 --- a/listener/tunnel/packet.go +++ b/listener/tunnel/packet.go @@ -27,7 +27,8 @@ func (c *packet) LocalAddr() net.Addr { } func (c *packet) Drop() { - pool.Put(c.payload) + _ = pool.Put(c.payload) + c.payload = nil } func (c *packet) InAddr() net.Addr { diff --git a/tunnel/connection.go b/tunnel/connection.go index b130f79a..38dbfa65 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -26,7 +26,7 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata return nil } -func handleUDPToLocal(packet C.UDPPacket, pc N.EnhancePacketConn, key string, oAddrPort netip.AddrPort, fAddr netip.Addr) { +func handleUDPToLocal(writeBack C.WriteBack, pc N.EnhancePacketConn, key string, oAddrPort netip.AddrPort, fAddr netip.Addr) { defer func() { _ = pc.Close() closeAllLocalCoon(key) @@ -59,7 +59,7 @@ func handleUDPToLocal(packet C.UDPPacket, pc N.EnhancePacketConn, key string, oA log.Warnln("server return a [%T](%s) which isn't a *net.UDPAddr, force replace to (%s), this may be caused by a wrongly implemented server", from, from, oAddrPort) } - _, err = packet.WriteBack(data, fromUDPAddr) + _, err = writeBack.WriteBack(data, fromUDPAddr) if put != nil { put() } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 4e00aca2..cbbcaa75 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -303,8 +303,11 @@ func handleUDPConn(packet C.PacketAdapter) { key := packet.LocalAddr().String() handle := func() bool { - pc := natTable.Get(key) + pc, proxy := natTable.Get(key) if pc != nil { + if proxy != nil { + proxy.UpdateWriteBack(packet) + } _ = handleUDPToRemote(packet, pc, metadata) return true } @@ -384,9 +387,10 @@ func handleUDPConn(packet C.PacketAdapter) { } oAddrPort := metadata.AddrPort() - natTable.Set(key, pc) + writeBackProxy := nat.NewWriteBackProxy(packet) + natTable.Set(key, pc, writeBackProxy) - go handleUDPToLocal(packet, pc, key, oAddrPort, fAddr) + go handleUDPToLocal(writeBackProxy, pc, key, oAddrPort, fAddr) handle() }() From 03d0c8620e9083f15aef831be467a2f3b2124063 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 3 Jun 2023 22:15:09 +0800 Subject: [PATCH 08/79] fix: hysteria faketcp loopback in tun mode --- component/dialer/bind.go | 51 +++++++++++++++++++ component/dialer/bind_others.go | 48 +---------------- transport/hysteria/conns/faketcp/tcp_linux.go | 18 ++++++- 3 files changed, 69 insertions(+), 48 deletions(-) create mode 100644 component/dialer/bind.go diff --git a/component/dialer/bind.go b/component/dialer/bind.go new file mode 100644 index 00000000..34d40ca2 --- /dev/null +++ b/component/dialer/bind.go @@ -0,0 +1,51 @@ +package dialer + +import ( + "net" + "net/netip" + "strings" + + "github.com/Dreamacro/clash/component/iface" +) + +func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) { + ifaceObj, err := iface.ResolveInterface(ifaceName) + if err != nil { + return nil, err + } + + var addr *netip.Prefix + switch network { + case "udp4", "tcp4": + addr, err = ifaceObj.PickIPv4Addr(destination) + case "tcp6", "udp6": + addr, err = ifaceObj.PickIPv6Addr(destination) + default: + if destination.IsValid() { + if destination.Is4() { + addr, err = ifaceObj.PickIPv4Addr(destination) + } else { + addr, err = ifaceObj.PickIPv6Addr(destination) + } + } else { + addr, err = ifaceObj.PickIPv4Addr(destination) + } + } + if err != nil { + return nil, err + } + + if strings.HasPrefix(network, "tcp") { + return &net.TCPAddr{ + IP: addr.Addr().AsSlice(), + Port: port, + }, nil + } else if strings.HasPrefix(network, "udp") { + return &net.UDPAddr{ + IP: addr.Addr().AsSlice(), + Port: port, + }, nil + } + + return nil, iface.ErrAddrNotFound +} diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go index 5cb2fd62..5fd02a66 100644 --- a/component/dialer/bind_others.go +++ b/component/dialer/bind_others.go @@ -7,52 +7,8 @@ import ( "net/netip" "strconv" "strings" - - "github.com/Dreamacro/clash/component/iface" ) -func lookupLocalAddr(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) { - ifaceObj, err := iface.ResolveInterface(ifaceName) - if err != nil { - return nil, err - } - - var addr *netip.Prefix - switch network { - case "udp4", "tcp4": - addr, err = ifaceObj.PickIPv4Addr(destination) - case "tcp6", "udp6": - addr, err = ifaceObj.PickIPv6Addr(destination) - default: - if destination.IsValid() { - if destination.Is4() { - addr, err = ifaceObj.PickIPv4Addr(destination) - } else { - addr, err = ifaceObj.PickIPv6Addr(destination) - } - } else { - addr, err = ifaceObj.PickIPv4Addr(destination) - } - } - if err != nil { - return nil, err - } - - if strings.HasPrefix(network, "tcp") { - return &net.TCPAddr{ - IP: addr.Addr().AsSlice(), - Port: port, - }, nil - } else if strings.HasPrefix(network, "udp") { - return &net.UDPAddr{ - IP: addr.Addr().AsSlice(), - Port: port, - }, nil - } - - return nil, iface.ErrAddrNotFound -} - func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error { if !destination.IsGlobalUnicast() { return nil @@ -66,7 +22,7 @@ func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, des } } - addr, err := lookupLocalAddr(ifaceName, network, destination, int(local)) + addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, destination, int(local)) if err != nil { return err } @@ -84,7 +40,7 @@ func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, add local, _ := strconv.ParseUint(port, 10, 16) - addr, err := lookupLocalAddr(ifaceName, network, netip.Addr{}, int(local)) + addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, netip.Addr{}, int(local)) if err != nil { return "", err } diff --git a/transport/hysteria/conns/faketcp/tcp_linux.go b/transport/hysteria/conns/faketcp/tcp_linux.go index cdee9fda..1d6f277c 100644 --- a/transport/hysteria/conns/faketcp/tcp_linux.go +++ b/transport/hysteria/conns/faketcp/tcp_linux.go @@ -19,6 +19,8 @@ import ( "github.com/coreos/go-iptables/iptables" "github.com/google/gopacket" "github.com/google/gopacket/layers" + + "github.com/Dreamacro/clash/component/dialer" ) var ( @@ -398,15 +400,27 @@ func Dial(network, address string) (*TCPConn, error) { return nil, err } + var lTcpAddr *net.TCPAddr + var lIpAddr *net.IPAddr + if ifaceName := dialer.DefaultInterface.Load(); len(ifaceName) > 0 { + rAddrPort := raddr.AddrPort() + addr, err := dialer.LookupLocalAddrFromIfaceName(ifaceName, network, rAddrPort.Addr(), int(rAddrPort.Port())) + if err != nil { + return nil, err + } + lTcpAddr = addr.(*net.TCPAddr) + lIpAddr = &net.IPAddr{IP: lTcpAddr.IP} + } + // AF_INET - handle, err := net.DialIP("ip:tcp", nil, &net.IPAddr{IP: raddr.IP}) + handle, err := net.DialIP("ip:tcp", lIpAddr, &net.IPAddr{IP: raddr.IP}) if err != nil { return nil, err } // create an established tcp connection // will hack this tcp connection for packet transmission - tcpconn, err := net.DialTCP(network, nil, raddr) + tcpconn, err := net.DialTCP(network, lTcpAddr, raddr) if err != nil { return nil, err } From 3ef81afc76eac7ce0e7489722b61f9fdea12c170 Mon Sep 17 00:00:00 2001 From: wzdnzd Date: Sun, 4 Jun 2023 11:51:30 +0800 Subject: [PATCH 09/79] [Feature] Proxy stores delay data of different URLs. And supports specifying different test URLs and expected statue by group (#588) Co-authored-by: Larvan2 <78135608+Larvan2@users.noreply.github.com> Co-authored-by: wwqgtxx --- adapter/adapter.go | 140 +++++++++++++++++++++++-- adapter/outboundgroup/fallback.go | 33 +++--- adapter/outboundgroup/groupbase.go | 5 +- adapter/outboundgroup/loadbalance.go | 42 +++++--- adapter/outboundgroup/parser.go | 82 +++++++++------ adapter/outboundgroup/urltest.go | 40 ++++--- adapter/provider/healthcheck.go | 150 +++++++++++++++++++++++++-- adapter/provider/provider.go | 11 ++ common/utils/range.go | 16 +-- common/utils/ranges.go | 77 ++++++++++++++ component/sniffer/base_sniffer.go | 13 +-- component/sniffer/http_sniffer.go | 8 +- component/sniffer/tls_sniffer.go | 8 +- component/tls/config.go | 4 +- config/config.go | 30 +----- constant/adapters.go | 16 ++- constant/provider/interface.go | 2 + hub/route/groups.go | 17 ++- hub/route/proxies.go | 16 ++- rules/common/port.go | 65 +++--------- rules/common/uid.go | 47 ++------- 21 files changed, 570 insertions(+), 252 deletions(-) create mode 100644 common/utils/ranges.go diff --git a/adapter/adapter.go b/adapter/adapter.go index 538ba271..d2c362bc 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -3,6 +3,7 @@ package adapter import ( "context" "encoding/json" + "errors" "fmt" "net" "net/http" @@ -12,16 +13,28 @@ import ( "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/queue" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" ) var UnifiedDelay = atomic.NewBool(false) +const ( + defaultHistoriesNum = 10 +) + +type extraProxyState struct { + history *queue.Queue[C.DelayHistory] + alive *atomic.Bool +} + type Proxy struct { C.ProxyAdapter history *queue.Queue[C.DelayHistory] alive *atomic.Bool + extra map[string]*extraProxyState } // Alive implements C.Proxy @@ -29,6 +42,17 @@ func (p *Proxy) Alive() bool { return p.alive.Load() } +// AliveForTestUrl implements C.Proxy +func (p *Proxy) AliveForTestUrl(url string) bool { + if p.extra != nil { + if state, ok := p.extra[url]; ok { + return state.alive.Load() + } + } + + return p.alive.Load() +} + // Dial implements C.Proxy func (p *Proxy) Dial(metadata *C.Metadata) (C.Conn, error) { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout) @@ -65,6 +89,42 @@ func (p *Proxy) DelayHistory() []C.DelayHistory { return histories } +// DelayHistoryForTestUrl implements C.Proxy +func (p *Proxy) DelayHistoryForTestUrl(url string) []C.DelayHistory { + var queueM []C.DelayHistory + if p.extra != nil { + if state, ok := p.extra[url]; ok { + queueM = state.history.Copy() + } + } + + if queueM == nil { + queueM = p.history.Copy() + } + + histories := []C.DelayHistory{} + for _, item := range queueM { + histories = append(histories, item) + } + return histories +} + +func (p *Proxy) ExtraDelayHistory() map[string][]C.DelayHistory { + extra := map[string][]C.DelayHistory{} + if p.extra != nil && len(p.extra) != 0 { + for url, option := range p.extra { + histories := []C.DelayHistory{} + queueM := option.history.Copy() + for _, item := range queueM { + histories = append(histories, item) + } + + extra[url] = histories + } + } + return extra +} + // LastDelay return last history record. if proxy is not alive, return the max value of uint16. // implements C.Proxy func (p *Proxy) LastDelay() (delay uint16) { @@ -80,6 +140,30 @@ func (p *Proxy) LastDelay() (delay uint16) { return history.Delay } +// LastDelayForTestUrl implements C.Proxy +func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { + var max uint16 = 0xffff + + alive := p.alive.Load() + history := p.history.Last() + + if p.extra != nil { + if state, ok := p.extra[url]; ok { + alive = state.alive.Load() + history = state.history.Last() + } + } + + if !alive { + return max + } + + if history.Delay == 0 { + return max + } + return history.Delay +} + // MarshalJSON implements C.ProxyAdapter func (p *Proxy) MarshalJSON() ([]byte, error) { inner, err := p.ProxyAdapter.MarshalJSON() @@ -90,6 +174,7 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { mapping := map[string]any{} _ = json.Unmarshal(inner, &mapping) mapping["history"] = p.DelayHistory() + mapping["extra"] = p.ExtraDelayHistory() mapping["name"] = p.Name() mapping["udp"] = p.SupportUDP() mapping["xudp"] = p.SupportXUDP() @@ -99,16 +184,46 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { // URLTest get the delay for the specified URL // implements C.Proxy -func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) { +func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16], store C.DelayHistoryStoreType) (t uint16, err error) { defer func() { - p.alive.Store(err == nil) - record := C.DelayHistory{Time: time.Now()} - if err == nil { - record.Delay = t - } - p.history.Put(record) - if p.history.Len() > 10 { - p.history.Pop() + alive := err == nil + switch store { + case C.OriginalHistory: + p.alive.Store(alive) + record := C.DelayHistory{Time: time.Now()} + if alive { + record.Delay = t + } + p.history.Put(record) + if p.history.Len() > defaultHistoriesNum { + p.history.Pop() + } + case C.ExtraHistory: + record := C.DelayHistory{Time: time.Now()} + if alive { + record.Delay = t + } + + if p.extra == nil { + p.extra = map[string]*extraProxyState{} + } + + state, ok := p.extra[url] + if !ok { + state = &extraProxyState{ + history: queue.New[C.DelayHistory](defaultHistoriesNum), + alive: atomic.NewBool(true), + } + p.extra[url] = state + } + + state.alive.Store(alive) + state.history.Put(record) + if state.history.Len() > defaultHistoriesNum { + state.history.Pop() + } + default: + log.Debugln("health check result will be discarded, url: %s alive: %t, delay: %d", url, alive, t) } }() @@ -172,12 +287,17 @@ func (p *Proxy) URLTest(ctx context.Context, url string) (t uint16, err error) { } } + if !expectedStatus.Check(uint16(resp.StatusCode)) { + // maybe another value should be returned for differentiation + err = errors.New("response status is inconsistent with the expected status") + } + t = uint16(time.Since(start) / time.Millisecond) return } func NewProxy(adapter C.ProxyAdapter) *Proxy { - return &Proxy{adapter, queue.New[C.DelayHistory](10), atomic.NewBool(true)} + return &Proxy{adapter, queue.New[C.DelayHistory](defaultHistoriesNum), atomic.NewBool(true), map[string]*extraProxyState{}} } func urlToMetadata(rawURL string) (addr C.Metadata, err error) { diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 1f4e1580..899b9a9b 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -9,6 +9,7 @@ import ( "github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/common/callback" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" @@ -16,9 +17,10 @@ import ( type Fallback struct { *GroupBase - disableUDP bool - testUrl string - selected string + disableUDP bool + testUrl string + selected string + expectedStatus string } func (f *Fallback) Now() string { @@ -82,9 +84,11 @@ func (f *Fallback) MarshalJSON() ([]byte, error) { all = append(all, proxy.Name()) } return json.Marshal(map[string]any{ - "type": f.Type().String(), - "now": f.Now(), - "all": all, + "type": f.Type().String(), + "now": f.Now(), + "all": all, + "testUrl": f.testUrl, + "expected": f.expectedStatus, }) } @@ -98,12 +102,14 @@ func (f *Fallback) findAliveProxy(touch bool) C.Proxy { proxies := f.GetProxies(touch) for _, proxy := range proxies { if len(f.selected) == 0 { - if proxy.Alive() { + // if proxy.Alive() { + if proxy.AliveForTestUrl(f.testUrl) { return proxy } } else { if proxy.Name() == f.selected { - if proxy.Alive() { + // if proxy.Alive() { + if proxy.AliveForTestUrl(f.testUrl) { return proxy } else { f.selected = "" @@ -129,10 +135,12 @@ func (f *Fallback) Set(name string) error { } f.selected = name - if !p.Alive() { + // if !p.Alive() { + if !p.AliveForTestUrl(f.testUrl) { ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(5000)) defer cancel() - _, _ = p.URLTest(ctx, f.testUrl) + expectedStatus, _ := utils.NewIntRanges[uint16](f.expectedStatus) + _, _ = p.URLTest(ctx, f.testUrl, expectedStatus, C.ExtraHistory) } return nil @@ -156,7 +164,8 @@ func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) option.ExcludeType, providers, }), - disableUDP: option.DisableUDP, - testUrl: option.URL, + disableUDP: option.DisableUDP, + testUrl: option.URL, + expectedStatus: option.ExpectedStatus, } } diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 895ca421..66776bf5 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -9,6 +9,7 @@ import ( "github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/common/atomic" + "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" types "github.com/Dreamacro/clash/constant/provider" @@ -192,7 +193,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { return proxies } -func (gb *GroupBase) URLTest(ctx context.Context, url string) (map[string]uint16, error) { +func (gb *GroupBase) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (map[string]uint16, error) { var wg sync.WaitGroup var lock sync.Mutex mp := map[string]uint16{} @@ -201,7 +202,7 @@ func (gb *GroupBase) URLTest(ctx context.Context, url string) (map[string]uint16 proxy := proxy wg.Add(1) go func() { - delay, err := proxy.URLTest(ctx, url) + delay, err := proxy.URLTest(ctx, url, expectedStatus, C.DropHistory) if err == nil { lock.Lock() mp[proxy.Name()] = delay diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 607d4f4f..dd2c0c99 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -25,8 +25,10 @@ type strategyFn = func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Pr type LoadBalance struct { *GroupBase - disableUDP bool - strategyFn strategyFn + disableUDP bool + strategyFn strategyFn + testUrl string + expectedStatus string } var errStrategy = errors.New("unsupported strategy") @@ -129,7 +131,7 @@ func (lb *LoadBalance) IsL3Protocol(metadata *C.Metadata) bool { return lb.Unwrap(metadata, false).IsL3Protocol(metadata) } -func strategyRoundRobin() strategyFn { +func strategyRoundRobin(url string) strategyFn { idx := 0 idxMutex := sync.Mutex{} return func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy { @@ -148,7 +150,8 @@ func strategyRoundRobin() strategyFn { for ; i < length; i++ { id := (idx + i) % length proxy := proxies[id] - if proxy.Alive() { + // if proxy.Alive() { + if proxy.AliveForTestUrl(url) { i++ return proxy } @@ -158,7 +161,7 @@ func strategyRoundRobin() strategyFn { } } -func strategyConsistentHashing() strategyFn { +func strategyConsistentHashing(url string) strategyFn { maxRetry := 5 return func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy { key := uint64(murmur3.Sum32([]byte(getKey(metadata)))) @@ -166,14 +169,16 @@ func strategyConsistentHashing() strategyFn { for i := 0; i < maxRetry; i, key = i+1, key+1 { idx := jumpHash(key, buckets) proxy := proxies[idx] - if proxy.Alive() { + // if proxy.Alive() { + if proxy.AliveForTestUrl(url) { return proxy } } // when availability is poor, traverse the entire list to get the available nodes for _, proxy := range proxies { - if proxy.Alive() { + // if proxy.Alive() { + if proxy.AliveForTestUrl(url) { return proxy } } @@ -182,7 +187,7 @@ func strategyConsistentHashing() strategyFn { } } -func strategyStickySessions() strategyFn { +func strategyStickySessions(url string) strategyFn { ttl := time.Minute * 10 maxRetry := 5 lruCache := cache.New[uint64, int]( @@ -199,7 +204,8 @@ func strategyStickySessions() strategyFn { nowIdx := idx for i := 1; i < maxRetry; i++ { proxy := proxies[nowIdx] - if proxy.Alive() { + // if proxy.Alive() { + if proxy.AliveForTestUrl(url) { if nowIdx != idx { lruCache.Delete(key) lruCache.Set(key, nowIdx) @@ -230,8 +236,10 @@ func (lb *LoadBalance) MarshalJSON() ([]byte, error) { all = append(all, proxy.Name()) } return json.Marshal(map[string]any{ - "type": lb.Type().String(), - "all": all, + "type": lb.Type().String(), + "all": all, + "testUrl": lb.testUrl, + "expectedStatus": lb.expectedStatus, }) } @@ -239,11 +247,11 @@ func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvide var strategyFn strategyFn switch strategy { case "consistent-hashing": - strategyFn = strategyConsistentHashing() + strategyFn = strategyConsistentHashing(option.URL) case "round-robin": - strategyFn = strategyRoundRobin() + strategyFn = strategyRoundRobin(option.URL) case "sticky-sessions": - strategyFn = strategyStickySessions() + strategyFn = strategyStickySessions(option.URL) default: return nil, fmt.Errorf("%w: %s", errStrategy, strategy) } @@ -260,7 +268,9 @@ func NewLoadBalance(option *GroupCommonOption, providers []provider.ProxyProvide option.ExcludeType, providers, }), - strategyFn: strategyFn, - disableUDP: option.DisableUDP, + strategyFn: strategyFn, + disableUDP: option.DisableUDP, + testUrl: option.URL, + expectedStatus: option.ExpectedStatus, }, nil } diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 05976c89..fccf51fd 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -3,17 +3,19 @@ package outboundgroup import ( "errors" "fmt" + "strings" "github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/adapter/provider" "github.com/Dreamacro/clash/common/structure" + "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" types "github.com/Dreamacro/clash/constant/provider" ) var ( errFormat = errors.New("format error") - errType = errors.New("unsupport type") + errType = errors.New("unsupported type") errMissProxy = errors.New("`use` or `proxies` missing") errMissHealthCheck = errors.New("`url` or `interval` missing") errDuplicateProvider = errors.New("duplicate provider name") @@ -21,17 +23,18 @@ var ( type GroupCommonOption struct { outbound.BasicOption - Name string `group:"name"` - Type string `group:"type"` - Proxies []string `group:"proxies,omitempty"` - Use []string `group:"use,omitempty"` - URL string `group:"url,omitempty"` - Interval int `group:"interval,omitempty"` - Lazy bool `group:"lazy,omitempty"` - DisableUDP bool `group:"disable-udp,omitempty"` - Filter string `group:"filter,omitempty"` - ExcludeFilter string `group:"exclude-filter,omitempty"` - ExcludeType string `group:"exclude-type,omitempty"` + Name string `group:"name"` + Type string `group:"type"` + Proxies []string `group:"proxies,omitempty"` + Use []string `group:"use,omitempty"` + URL string `group:"url,omitempty"` + Interval int `group:"interval,omitempty"` + Lazy bool `group:"lazy,omitempty"` + DisableUDP bool `group:"disable-udp,omitempty"` + Filter string `group:"filter,omitempty"` + ExcludeFilter string `group:"exclude-filter,omitempty"` + ExcludeType string `group:"exclude-type,omitempty"` + ExpectedStatus string `group:"expected-status,omitempty"` } func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, providersMap map[string]types.ProxyProvider) (C.ProxyAdapter, error) { @@ -56,6 +59,18 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide return nil, errMissProxy } + expectedStatus, err := utils.NewIntRanges[uint16](groupOption.ExpectedStatus) + if err != nil { + return nil, err + } + + status := strings.TrimSpace(groupOption.ExpectedStatus) + if status == "" { + status = "*" + } + groupOption.ExpectedStatus = status + testUrl := groupOption.URL + if len(groupOption.Proxies) != 0 { ps, err := getProxies(proxyMap, groupOption.Proxies) if err != nil { @@ -66,17 +81,14 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide return nil, errDuplicateProvider } - // select don't need health check - if groupOption.Type == "select" || groupOption.Type == "relay" { - hc := provider.NewHealthCheck(ps, "", 0, true) - pd, err := provider.NewCompatibleProvider(groupName, ps, hc) - if err != nil { - return nil, err - } + hc := provider.NewHealthCheck(ps, "", 0, true) + pd, err := provider.NewCompatibleProvider(groupName, ps, hc) + if err != nil { + return nil, err + } - providers = append(providers, pd) - providersMap[groupName] = pd - } else { + // select don't need health check + if groupOption.Type != "select" && groupOption.Type != "relay" { if groupOption.URL == "" { groupOption.URL = "https://cp.cloudflare.com/generate_204" } @@ -85,15 +97,11 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide groupOption.Interval = 300 } - hc := provider.NewHealthCheck(ps, groupOption.URL, uint(groupOption.Interval), groupOption.Lazy) - pd, err := provider.NewCompatibleProvider(groupName, ps, hc) - if err != nil { - return nil, err - } - - providers = append(providers, pd) - providersMap[groupName] = pd + pd.RegisterHealthCheckTask(groupOption.URL, expectedStatus, "", uint(groupOption.Interval)) } + + providers = append(providers, pd) + providersMap[groupName] = pd } if len(groupOption.Use) != 0 { @@ -101,6 +109,10 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide if err != nil { return nil, err } + + // different proxy groups use different test URL + addTestUrlToProviders(list, testUrl, expectedStatus, groupOption.Filter, uint(groupOption.Interval)) + providers = append(providers, list...) } else { groupOption.Filter = "" @@ -154,3 +166,13 @@ func getProviders(mapping map[string]types.ProxyProvider, list []string) ([]type } return ps, nil } + +func addTestUrlToProviders(providers []types.ProxyProvider, url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) { + if len(providers) == 0 || len(url) == 0 { + return + } + + for _, pd := range providers { + pd.RegisterHealthCheckTask(url, expectedStatus, filter, interval) + } +} diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 442494d9..3f6c6ab0 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -25,12 +25,13 @@ func urlTestWithTolerance(tolerance uint16) urlTestOption { type URLTest struct { *GroupBase - selected string - testUrl string - tolerance uint16 - disableUDP bool - fastNode C.Proxy - fastSingle *singledo.Single[C.Proxy] + selected string + testUrl string + expectedStatus string + tolerance uint16 + disableUDP bool + fastNode C.Proxy + fastSingle *singledo.Single[C.Proxy] } func (u *URLTest) Now() string { @@ -112,7 +113,8 @@ func (u *URLTest) fast(touch bool) C.Proxy { elm, _, shared := u.fastSingle.Do(func() (C.Proxy, error) { fast := proxies[0] - min := fast.LastDelay() + // min := fast.LastDelay() + min := fast.LastDelayForTestUrl(u.testUrl) fastNotExist := true for _, proxy := range proxies[1:] { @@ -120,11 +122,13 @@ func (u *URLTest) fast(touch bool) C.Proxy { fastNotExist = false } - if !proxy.Alive() { + // if !proxy.Alive() { + if !proxy.AliveForTestUrl(u.testUrl) { continue } - delay := proxy.LastDelay() + // delay := proxy.LastDelay() + delay := proxy.LastDelayForTestUrl(u.testUrl) if delay < min { fast = proxy min = delay @@ -132,7 +136,8 @@ func (u *URLTest) fast(touch bool) C.Proxy { } // tolerance - if u.fastNode == nil || fastNotExist || !u.fastNode.Alive() || u.fastNode.LastDelay() > fast.LastDelay()+u.tolerance { + // if u.fastNode == nil || fastNotExist || !u.fastNode.Alive() || u.fastNode.LastDelay() > fast.LastDelay()+u.tolerance { + if u.fastNode == nil || fastNotExist || !u.fastNode.AliveForTestUrl(u.testUrl) || u.fastNode.LastDelayForTestUrl(u.testUrl) > fast.LastDelayForTestUrl(u.testUrl)+u.tolerance { u.fastNode = fast } return u.fastNode, nil @@ -164,9 +169,11 @@ func (u *URLTest) MarshalJSON() ([]byte, error) { all = append(all, proxy.Name()) } return json.Marshal(map[string]any{ - "type": u.Type().String(), - "now": u.Now(), - "all": all, + "type": u.Type().String(), + "now": u.Now(), + "all": all, + "testUrl": u.testUrl, + "expected": u.expectedStatus, }) } @@ -198,9 +205,10 @@ func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, o option.ExcludeType, providers, }), - fastSingle: singledo.NewSingle[C.Proxy](time.Second * 10), - disableUDP: option.DisableUDP, - testUrl: option.URL, + fastSingle: singledo.NewSingle[C.Proxy](time.Second * 10), + disableUDP: option.DisableUDP, + testUrl: option.URL, + expectedStatus: option.ExpectedStatus, } for _, option := range options { diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index fa13e32e..cc7056f1 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -2,6 +2,8 @@ package provider import ( "context" + "strings" + "sync" "time" "github.com/Dreamacro/clash/common/atomic" @@ -10,10 +12,13 @@ import ( "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" + + "github.com/dlclark/regexp2" ) const ( defaultURLTestTimeout = time.Second * 5 + defaultMaxTestUrlNum = 6 ) type HealthCheckOption struct { @@ -21,8 +26,16 @@ type HealthCheckOption struct { Interval uint } +type extraOption struct { + expectedStatus utils.IntRanges[uint16] + filters map[string]struct{} +} + type HealthCheck struct { url string + extra map[string]*extraOption + mu sync.Mutex + started *atomic.Bool proxies []C.Proxy interval uint lazy bool @@ -32,7 +45,13 @@ type HealthCheck struct { } func (hc *HealthCheck) process() { + if hc.started.Load() { + log.Warnln("Skip start health check timer due to it's started") + return + } + ticker := time.NewTicker(time.Duration(hc.interval) * time.Second) + hc.start() for { select { case <-ticker.C: @@ -44,6 +63,7 @@ func (hc *HealthCheck) process() { } case <-hc.done: ticker.Stop() + hc.stop() return } } @@ -53,6 +73,63 @@ func (hc *HealthCheck) setProxy(proxies []C.Proxy) { hc.proxies = proxies } +func (hc *HealthCheck) registerHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) { + url = strings.TrimSpace(url) + if len(url) == 0 || url == hc.url { + log.Debugln("ignore invalid health check url: %s", url) + return + } + + hc.mu.Lock() + defer hc.mu.Unlock() + + // if the provider has not set up health checks, then modify it to be the same as the group's interval + if hc.interval == 0 { + hc.interval = interval + } + + if hc.extra == nil { + hc.extra = make(map[string]*extraOption) + } + + // prioritize the use of previously registered configurations, especially those from provider + if _, ok := hc.extra[url]; ok { + // provider default health check does not set filter + if url != hc.url && len(filter) != 0 { + splitAndAddFiltersToExtra(filter, hc.extra[url]) + } + + log.Debugln("health check url: %s exists", url) + return + } + + // due to the time-consuming nature of health checks, a maximum of defaultMaxTestURLNum URLs can be set for testing + if len(hc.extra) > defaultMaxTestUrlNum { + log.Debugln("skip add url: %s to health check because it has reached the maximum limit: %d", url, defaultMaxTestUrlNum) + return + } + + option := &extraOption{filters: map[string]struct{}{}, expectedStatus: expectedStatus} + splitAndAddFiltersToExtra(filter, option) + hc.extra[url] = option + + if hc.auto() && !hc.started.Load() { + go hc.process() + } +} + +func splitAndAddFiltersToExtra(filter string, option *extraOption) { + filter = strings.TrimSpace(filter) + if len(filter) != 0 { + for _, regex := range strings.Split(filter, "`") { + regex = strings.TrimSpace(regex) + if len(regex) != 0 { + option.filters[regex] = struct{}{} + } + } + } +} + func (hc *HealthCheck) auto() bool { return hc.interval != 0 } @@ -61,29 +138,78 @@ func (hc *HealthCheck) touch() { hc.lastTouch.Store(time.Now().Unix()) } +func (hc *HealthCheck) start() { + hc.started.Store(true) +} + +func (hc *HealthCheck) stop() { + hc.started.Store(false) +} + func (hc *HealthCheck) check() { _, _, _ = hc.singleDo.Do(func() (struct{}, error) { id := utils.NewUUIDV4().String() log.Debugln("Start New Health Checking {%s}", id) b, _ := batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](10)) - for _, proxy := range hc.proxies { - p := proxy - b.Go(p.Name(), func() (bool, error) { - ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout) - defer cancel() - log.Debugln("Health Checking %s {%s}", p.Name(), id) - _, _ = p.URLTest(ctx, hc.url) - log.Debugln("Health Checked %s : %t %d ms {%s}", p.Name(), p.Alive(), p.LastDelay(), id) - return false, nil - }) - } + // execute default health check + hc.execute(b, hc.url, id, nil) + + // execute extra health check + if len(hc.extra) != 0 { + for url, option := range hc.extra { + hc.execute(b, url, id, option) + } + } b.Wait() log.Debugln("Finish A Health Checking {%s}", id) return struct{}{}, nil }) } +func (hc *HealthCheck) execute(b *batch.Batch[bool], url, uid string, option *extraOption) { + url = strings.TrimSpace(url) + if len(url) == 0 { + log.Debugln("Health Check has been skipped due to testUrl is empty, {%s}", uid) + return + } + + var filterReg *regexp2.Regexp + var store = C.OriginalHistory + var expectedStatus utils.IntRanges[uint16] + if option != nil { + store = C.ExtraHistory + expectedStatus = option.expectedStatus + if len(option.filters) != 0 { + filters := make([]string, 0, len(option.filters)) + for filter := range option.filters { + filters = append(filters, filter) + } + + filterReg = regexp2.MustCompile(strings.Join(filters, "|"), 0) + } + } + + for _, proxy := range hc.proxies { + // skip proxies that do not require health check + if filterReg != nil { + if match, _ := filterReg.FindStringMatch(proxy.Name()); match == nil { + continue + } + } + + p := proxy + b.Go(p.Name(), func() (bool, error) { + ctx, cancel := context.WithTimeout(context.Background(), defaultURLTestTimeout) + defer cancel() + log.Debugln("Health Checking, proxy: %s, url: %s, id: {%s}", p.Name(), url, uid) + _, _ = p.URLTest(ctx, url, expectedStatus, store) + log.Debugln("Health Checked, proxy: %s, url: %s, alive: %t, delay: %d ms uid: {%s}", p.Name(), url, p.AliveForTestUrl(url), p.LastDelayForTestUrl(url), uid) + return false, nil + }) + } +} + func (hc *HealthCheck) close() { hc.done <- struct{}{} } @@ -92,6 +218,8 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool) *He return &HealthCheck{ proxies: proxies, url: url, + extra: map[string]*extraOption{}, + started: atomic.NewBool(false), interval: interval, lazy: lazy, lastTouch: atomic.NewInt64(0), diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 4138c0de..60fbb5f0 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -12,6 +12,7 @@ import ( "github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/common/convert" + "github.com/Dreamacro/clash/common/utils" clashHttp "github.com/Dreamacro/clash/component/http" "github.com/Dreamacro/clash/component/resource" C "github.com/Dreamacro/clash/constant" @@ -50,6 +51,7 @@ func (pp *proxySetProvider) MarshalJSON() ([]byte, error) { "type": pp.Type().String(), "vehicleType": pp.VehicleType().String(), "proxies": pp.Proxies(), + "testUrl": pp.healthCheck.url, "updatedAt": pp.UpdatedAt, "subscriptionInfo": pp.subscriptionInfo, }) @@ -98,6 +100,10 @@ func (pp *proxySetProvider) Touch() { pp.healthCheck.touch() } +func (pp *proxySetProvider) RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) { + pp.healthCheck.registerHealthCheckTask(url, expectedStatus, filter, interval) +} + func (pp *proxySetProvider) setProxies(proxies []C.Proxy) { pp.proxies = proxies pp.healthCheck.setProxy(proxies) @@ -210,6 +216,7 @@ func (cp *compatibleProvider) MarshalJSON() ([]byte, error) { "type": cp.Type().String(), "vehicleType": cp.VehicleType().String(), "proxies": cp.Proxies(), + "testUrl": cp.healthCheck.url, }) } @@ -249,6 +256,10 @@ func (cp *compatibleProvider) Touch() { cp.healthCheck.touch() } +func (cp *compatibleProvider) RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) { + cp.healthCheck.registerHealthCheckTask(url, expectedStatus, filter, interval) +} + func stopCompatibleProvider(pd *CompatibleProvider) { pd.healthCheck.close() } diff --git a/common/utils/range.go b/common/utils/range.go index c569d6a2..7b4a235c 100644 --- a/common/utils/range.go +++ b/common/utils/range.go @@ -9,36 +9,36 @@ type Range[T constraints.Ordered] struct { end T } -func NewRange[T constraints.Ordered](start, end T) *Range[T] { +func NewRange[T constraints.Ordered](start, end T) Range[T] { if start > end { - return &Range[T]{ + return Range[T]{ start: end, end: start, } } - return &Range[T]{ + return Range[T]{ start: start, end: end, } } -func (r *Range[T]) Contains(t T) bool { +func (r Range[T]) Contains(t T) bool { return t >= r.start && t <= r.end } -func (r *Range[T]) LeftContains(t T) bool { +func (r Range[T]) LeftContains(t T) bool { return t >= r.start && t < r.end } -func (r *Range[T]) RightContains(t T) bool { +func (r Range[T]) RightContains(t T) bool { return t > r.start && t <= r.end } -func (r *Range[T]) Start() T { +func (r Range[T]) Start() T { return r.start } -func (r *Range[T]) End() T { +func (r Range[T]) End() T { return r.end } diff --git a/common/utils/ranges.go b/common/utils/ranges.go new file mode 100644 index 00000000..a6293f65 --- /dev/null +++ b/common/utils/ranges.go @@ -0,0 +1,77 @@ +package utils + +import ( + "errors" + "fmt" + "strconv" + "strings" + + "golang.org/x/exp/constraints" +) + +type IntRanges[T constraints.Integer] []Range[T] + +var errIntRanges = errors.New("intRanges error") + +func NewIntRanges[T constraints.Integer](expected string) (IntRanges[T], error) { + // example: 200 or 200/302 or 200-400 or 200/204/401-429/501-503 + expected = strings.TrimSpace(expected) + if len(expected) == 0 || expected == "*" { + return nil, nil + } + + list := strings.Split(expected, "/") + if len(list) > 28 { + return nil, fmt.Errorf("%w, too many ranges to use, maximum support 28 ranges", errIntRanges) + } + + return NewIntRangesFromList[T](list) +} + +func NewIntRangesFromList[T constraints.Integer](list []string) (IntRanges[T], error) { + var ranges IntRanges[T] + for _, s := range list { + if s == "" { + continue + } + + status := strings.Split(s, "-") + statusLen := len(status) + if statusLen > 2 { + return nil, errIntRanges + } + + start, err := strconv.ParseInt(strings.Trim(status[0], "[ ]"), 10, 64) + if err != nil { + return nil, errIntRanges + } + + switch statusLen { + case 1: + ranges = append(ranges, NewRange(T(start), T(start))) + case 2: + end, err := strconv.ParseUint(strings.Trim(status[1], "[ ]"), 10, 64) + if err != nil { + return nil, errIntRanges + } + + ranges = append(ranges, NewRange(T(start), T(end))) + } + } + + return ranges, nil +} + +func (ranges IntRanges[T]) Check(status T) bool { + if ranges == nil || len(ranges) == 0 { + return true + } + + for _, segment := range ranges { + if segment.Contains(status) { + return true + } + } + + return false +} diff --git a/component/sniffer/base_sniffer.go b/component/sniffer/base_sniffer.go index c2958cc6..cf7cb940 100644 --- a/component/sniffer/base_sniffer.go +++ b/component/sniffer/base_sniffer.go @@ -10,11 +10,11 @@ import ( type SnifferConfig struct { OverrideDest bool - Ports []utils.Range[uint16] + Ports utils.IntRanges[uint16] } type BaseSniffer struct { - ports []utils.Range[uint16] + ports utils.IntRanges[uint16] supportNetworkType constant.NetWork } @@ -35,15 +35,10 @@ func (bs *BaseSniffer) SupportNetwork() constant.NetWork { // SupportPort implements sniffer.Sniffer func (bs *BaseSniffer) SupportPort(port uint16) bool { - for _, portRange := range bs.ports { - if portRange.Contains(port) { - return true - } - } - return false + return bs.ports.Check(port) } -func NewBaseSniffer(ports []utils.Range[uint16], networkType constant.NetWork) *BaseSniffer { +func NewBaseSniffer(ports utils.IntRanges[uint16], networkType constant.NetWork) *BaseSniffer { return &BaseSniffer{ ports: ports, supportNetworkType: networkType, diff --git a/component/sniffer/http_sniffer.go b/component/sniffer/http_sniffer.go index bfa7ca6e..beb4bd20 100644 --- a/component/sniffer/http_sniffer.go +++ b/component/sniffer/http_sniffer.go @@ -34,11 +34,9 @@ type HTTPSniffer struct { var _ sniffer.Sniffer = (*HTTPSniffer)(nil) func NewHTTPSniffer(snifferConfig SnifferConfig) (*HTTPSniffer, error) { - ports := make([]utils.Range[uint16], 0) - if len(snifferConfig.Ports) == 0 { - ports = append(ports, *utils.NewRange[uint16](80, 80)) - } else { - ports = append(ports, snifferConfig.Ports...) + ports := snifferConfig.Ports + if len(ports) == 0 { + ports = utils.IntRanges[uint16]{utils.NewRange[uint16](80, 80)} } return &HTTPSniffer{ BaseSniffer: NewBaseSniffer(ports, C.TCP), diff --git a/component/sniffer/tls_sniffer.go b/component/sniffer/tls_sniffer.go index 0867d0f0..58e1e29e 100644 --- a/component/sniffer/tls_sniffer.go +++ b/component/sniffer/tls_sniffer.go @@ -22,11 +22,9 @@ type TLSSniffer struct { } func NewTLSSniffer(snifferConfig SnifferConfig) (*TLSSniffer, error) { - ports := make([]utils.Range[uint16], 0) - if len(snifferConfig.Ports) == 0 { - ports = append(ports, *utils.NewRange[uint16](443, 443)) - } else { - ports = append(ports, snifferConfig.Ports...) + ports := snifferConfig.Ports + if len(ports) == 0 { + ports = utils.IntRanges[uint16]{utils.NewRange[uint16](443, 443)} } return &TLSSniffer{ BaseSniffer: NewBaseSniffer(ports, C.TCP), diff --git a/component/tls/config.go b/component/tls/config.go index 6f808248..2896a1be 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -17,7 +17,7 @@ import ( var trustCerts []*x509.Certificate var certPool *x509.CertPool var mutex sync.RWMutex -var errNotMacth error = errors.New("certificate fingerprints do not match") +var errNotMatch = errors.New("certificate fingerprints do not match") func AddCertificate(certificate string) error { mutex.Lock() @@ -79,7 +79,7 @@ func verifyFingerprint(fingerprint *[32]byte) func(rawCerts [][]byte, verifiedCh } } } - return errNotMacth + return errNotMatch } } diff --git a/config/config.go b/config/config.go index ff16ac11..2f563b30 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,6 @@ import ( "net/url" "os" "regexp" - "strconv" "strings" "time" @@ -1304,7 +1303,7 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { if len(snifferRaw.Sniff) != 0 { for sniffType, sniffConfig := range snifferRaw.Sniff { find := false - ports, err := parsePortRange(sniffConfig.Ports) + ports, err := utils.NewIntRangesFromList[uint16](sniffConfig.Ports) if err != nil { return nil, err } @@ -1331,7 +1330,7 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { // Deprecated: Use Sniff instead log.Warnln("Deprecated: Use Sniff instead") } - globalPorts, err := parsePortRange(snifferRaw.Ports) + globalPorts, err := utils.NewIntRangesFromList[uint16](snifferRaw.Ports) if err != nil { return nil, err } @@ -1376,28 +1375,3 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { return sniffer, nil } - -func parsePortRange(portRanges []string) ([]utils.Range[uint16], error) { - ports := make([]utils.Range[uint16], 0) - for _, portRange := range portRanges { - portRaws := strings.Split(portRange, "-") - p, err := strconv.ParseUint(portRaws[0], 10, 16) - if err != nil { - return nil, fmt.Errorf("%s format error", portRange) - } - - start := uint16(p) - if len(portRaws) > 1 { - p, err = strconv.ParseUint(portRaws[1], 10, 16) - if err != nil { - return nil, fmt.Errorf("%s format error", portRange) - } - - end := uint16(p) - ports = append(ports, *utils.NewRange(start, end)) - } else { - ports = append(ports, *utils.NewRange(start, start)) - } - } - return ports, nil -} diff --git a/constant/adapters.go b/constant/adapters.go index 39b7d6eb..a55c2d18 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -10,6 +10,7 @@ import ( "time" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/dialer" ) @@ -132,7 +133,7 @@ type ProxyAdapter interface { } type Group interface { - URLTest(ctx context.Context, url string) (mp map[string]uint16, err error) + URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16]) (mp map[string]uint16, err error) GetProxies(touch bool) []Proxy Touch() } @@ -142,12 +143,23 @@ type DelayHistory struct { Delay uint16 `json:"delay"` } +type DelayHistoryStoreType int + +const ( + OriginalHistory DelayHistoryStoreType = iota + ExtraHistory + DropHistory +) + type Proxy interface { ProxyAdapter Alive() bool + AliveForTestUrl(url string) bool DelayHistory() []DelayHistory + ExtraDelayHistory() map[string][]DelayHistory LastDelay() uint16 - URLTest(ctx context.Context, url string) (uint16, error) + LastDelayForTestUrl(url string) uint16 + URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16], store DelayHistoryStoreType) (uint16, error) // Deprecated: use DialContext instead. Dial(metadata *Metadata) (Conn, error) diff --git a/constant/provider/interface.go b/constant/provider/interface.go index fb5efd87..34590a48 100644 --- a/constant/provider/interface.go +++ b/constant/provider/interface.go @@ -1,6 +1,7 @@ package provider import ( + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/constant" ) @@ -71,6 +72,7 @@ type ProxyProvider interface { Touch() HealthCheck() Version() uint32 + RegisterHealthCheckTask(url string, expectedStatus utils.IntRanges[uint16], filter string, interval uint) } // RuleProvider interface diff --git a/hub/route/groups.go b/hub/route/groups.go index 13133e9c..e5b61fb5 100644 --- a/hub/route/groups.go +++ b/hub/route/groups.go @@ -2,14 +2,16 @@ package route import ( "context" - "github.com/Dreamacro/clash/adapter" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" "net/http" "strconv" "time" + + "github.com/Dreamacro/clash/adapter" + "github.com/Dreamacro/clash/common/utils" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/tunnel" ) func GroupRouter() http.Handler { @@ -64,10 +66,17 @@ func getGroupDelay(w http.ResponseWriter, r *http.Request) { return } + expectedStatus, err := utils.NewIntRanges[uint16](query.Get("expected")) + if err != nil { + render.Status(r, http.StatusBadRequest) + render.JSON(w, r, ErrBadRequest) + return + } + ctx, cancel := context.WithTimeout(r.Context(), time.Millisecond*time.Duration(timeout)) defer cancel() - dm, err := group.URLTest(ctx, url) + dm, err := group.URLTest(ctx, url, expectedStatus) if err != nil { render.Status(r, http.StatusGatewayTimeout) diff --git a/hub/route/proxies.go b/hub/route/proxies.go index 5bf6eb9c..ea6a3302 100644 --- a/hub/route/proxies.go +++ b/hub/route/proxies.go @@ -9,6 +9,7 @@ import ( "github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter/outboundgroup" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/profile/cachefile" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/tunnel" @@ -112,12 +113,19 @@ func getProxyDelay(w http.ResponseWriter, r *http.Request) { return } + expectedStatus, err := utils.NewIntRanges[uint16](query.Get("expected")) + if err != nil { + render.Status(r, http.StatusBadRequest) + render.JSON(w, r, ErrBadRequest) + return + } + proxy := r.Context().Value(CtxKeyProxy).(C.Proxy) ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout)) defer cancel() - delay, err := proxy.URLTest(ctx, url) + delay, err := proxy.URLTest(ctx, url, expectedStatus, C.DropHistory) if ctx.Err() != nil { render.Status(r, http.StatusGatewayTimeout) render.JSON(w, r, ErrRequestTimeout) @@ -126,7 +134,11 @@ func getProxyDelay(w http.ResponseWriter, r *http.Request) { if err != nil || delay == 0 { render.Status(r, http.StatusServiceUnavailable) - render.JSON(w, r, newError("An error occurred in the delay test")) + if err != nil && delay != 0 { + render.JSON(w, r, err) + } else { + render.JSON(w, r, newError("An error occurred in the delay test")) + } return } diff --git a/rules/common/port.go b/rules/common/port.go index 3b7ea1fc..e3949f51 100644 --- a/rules/common/port.go +++ b/rules/common/port.go @@ -3,7 +3,6 @@ package common import ( "fmt" "strconv" - "strings" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" @@ -11,10 +10,10 @@ import ( type Port struct { *Base - adapter string - port string - ruleType C.RuleType - portList []utils.Range[uint16] + adapter string + port string + ruleType C.RuleType + portRanges utils.IntRanges[uint16] } func (p *Port) RuleType() C.RuleType { @@ -43,61 +42,25 @@ func (p *Port) Payload() string { func (p *Port) matchPortReal(portRef string) bool { port, _ := strconv.Atoi(portRef) - for _, pr := range p.portList { - if pr.Contains(uint16(port)) { - return true - } - } - - return false + return p.portRanges.Check(uint16(port)) } func NewPort(port string, adapter string, ruleType C.RuleType) (*Port, error) { - ports := strings.Split(port, "/") - if len(ports) > 28 { - return nil, fmt.Errorf("%s, too many ports to use, maximum support 28 ports", errPayload.Error()) + portRanges, err := utils.NewIntRanges[uint16](port) + if err != nil { + return nil, fmt.Errorf("%w, %s", errPayload, err.Error()) } - var portRange []utils.Range[uint16] - for _, p := range ports { - if p == "" { - continue - } - - subPorts := strings.Split(p, "-") - subPortsLen := len(subPorts) - if subPortsLen > 2 { - return nil, errPayload - } - - portStart, err := strconv.ParseUint(strings.Trim(subPorts[0], "[ ]"), 10, 16) - if err != nil { - return nil, errPayload - } - - switch subPortsLen { - case 1: - portRange = append(portRange, *utils.NewRange(uint16(portStart), uint16(portStart))) - case 2: - portEnd, err := strconv.ParseUint(strings.Trim(subPorts[1], "[ ]"), 10, 16) - if err != nil { - return nil, errPayload - } - - portRange = append(portRange, *utils.NewRange(uint16(portStart), uint16(portEnd))) - } - } - - if len(portRange) == 0 { + if len(portRanges) == 0 { return nil, errPayload } return &Port{ - Base: &Base{}, - adapter: adapter, - port: port, - ruleType: ruleType, - portList: portRange, + Base: &Base{}, + adapter: adapter, + port: port, + ruleType: ruleType, + portRanges: portRanges, }, nil } diff --git a/rules/common/uid.go b/rules/common/uid.go index ea275c28..b191a55f 100644 --- a/rules/common/uid.go +++ b/rules/common/uid.go @@ -2,57 +2,28 @@ package common import ( "fmt" + "runtime" + "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - "runtime" - "strconv" - "strings" ) type Uid struct { *Base - uids []utils.Range[uint32] + uids utils.IntRanges[uint32] oUid string adapter string } func NewUid(oUid, adapter string) (*Uid, error) { - //if len(_uids) > 28 { - // return nil, fmt.Errorf("%s, too many uid to use, maximum support 28 uid", errPayload.Error()) - //} if !(runtime.GOOS == "linux" || runtime.GOOS == "android") { return nil, fmt.Errorf("uid rule not support this platform") } - var uidRange []utils.Range[uint32] - for _, u := range strings.Split(oUid, "/") { - if u == "" { - continue - } - - subUids := strings.Split(u, "-") - subUidsLen := len(subUids) - if subUidsLen > 2 { - return nil, errPayload - } - - uidStart, err := strconv.ParseUint(strings.Trim(subUids[0], "[ ]"), 10, 32) - if err != nil { - return nil, errPayload - } - - switch subUidsLen { - case 1: - uidRange = append(uidRange, *utils.NewRange(uint32(uidStart), uint32(uidStart))) - case 2: - uidEnd, err := strconv.ParseUint(strings.Trim(subUids[1], "[ ]"), 10, 32) - if err != nil { - return nil, errPayload - } - - uidRange = append(uidRange, *utils.NewRange(uint32(uidStart), uint32(uidEnd))) - } + uidRange, err := utils.NewIntRanges[uint32](oUid) + if err != nil { + return nil, fmt.Errorf("%w, %s", errPayload, err.Error()) } if len(uidRange) == 0 { @@ -72,10 +43,8 @@ func (u *Uid) RuleType() C.RuleType { func (u *Uid) Match(metadata *C.Metadata) (bool, string) { if metadata.Uid != 0 { - for _, uid := range u.uids { - if uid.Contains(metadata.Uid) { - return true, u.adapter - } + if u.uids.Check(metadata.Uid) { + return true, u.adapter } } log.Warnln("[UID] could not get uid from %s", metadata.String()) From 3c1f9a995397cb94a32f4e7f6bc42aa7b8f74d82 Mon Sep 17 00:00:00 2001 From: wzdnzd Date: Sun, 4 Jun 2023 14:00:24 +0800 Subject: [PATCH 10/79] ProxyProvider health check also supports specifying expected status (#600) Co-authored-by: wwqgtxx --- adapter/outboundgroup/parser.go | 2 +- adapter/provider/healthcheck.go | 50 ++++++++++++++++++--------------- adapter/provider/parser.go | 17 +++++++---- config/config.go | 2 +- 4 files changed, 42 insertions(+), 29 deletions(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index fccf51fd..7ebaa6c0 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -81,7 +81,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide return nil, errDuplicateProvider } - hc := provider.NewHealthCheck(ps, "", 0, true) + hc := provider.NewHealthCheck(ps, "", 0, true, nil) pd, err := provider.NewCompatibleProvider(groupName, ps, hc) if err != nil { return nil, err diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index cc7056f1..330e306e 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -32,16 +32,17 @@ type extraOption struct { } type HealthCheck struct { - url string - extra map[string]*extraOption - mu sync.Mutex - started *atomic.Bool - proxies []C.Proxy - interval uint - lazy bool - lastTouch *atomic.Int64 - done chan struct{} - singleDo *singledo.Single[struct{}] + url string + extra map[string]*extraOption + mu sync.Mutex + started *atomic.Bool + proxies []C.Proxy + interval uint + lazy bool + expectedStatus utils.IntRanges[uint16] + lastTouch *atomic.Int64 + done chan struct{} + singleDo *singledo.Single[struct{}] } func (hc *HealthCheck) process() { @@ -153,7 +154,8 @@ func (hc *HealthCheck) check() { b, _ := batch.New[bool](context.Background(), batch.WithConcurrencyNum[bool](10)) // execute default health check - hc.execute(b, hc.url, id, nil) + option := &extraOption{filters: nil, expectedStatus: hc.expectedStatus} + hc.execute(b, hc.url, id, option) // execute extra health check if len(hc.extra) != 0 { @@ -178,7 +180,10 @@ func (hc *HealthCheck) execute(b *batch.Batch[bool], url, uid string, option *ex var store = C.OriginalHistory var expectedStatus utils.IntRanges[uint16] if option != nil { - store = C.ExtraHistory + if url != hc.url { + store = C.ExtraHistory + } + expectedStatus = option.expectedStatus if len(option.filters) != 0 { filters := make([]string, 0, len(option.filters)) @@ -214,16 +219,17 @@ func (hc *HealthCheck) close() { hc.done <- struct{}{} } -func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool) *HealthCheck { +func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, expectedStatus utils.IntRanges[uint16]) *HealthCheck { return &HealthCheck{ - proxies: proxies, - url: url, - extra: map[string]*extraOption{}, - started: atomic.NewBool(false), - interval: interval, - lazy: lazy, - lastTouch: atomic.NewInt64(0), - done: make(chan struct{}, 1), - singleDo: singledo.NewSingle[struct{}](time.Second), + proxies: proxies, + url: url, + extra: map[string]*extraOption{}, + started: atomic.NewBool(false), + interval: interval, + lazy: lazy, + expectedStatus: expectedStatus, + lastTouch: atomic.NewInt64(0), + done: make(chan struct{}, 1), + singleDo: singledo.NewSingle[struct{}](time.Second), } } diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 1df7f320..954db5cb 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -6,6 +6,7 @@ import ( "time" "github.com/Dreamacro/clash/common/structure" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/resource" C "github.com/Dreamacro/clash/constant" types "github.com/Dreamacro/clash/constant/provider" @@ -14,10 +15,11 @@ import ( var errVehicleType = errors.New("unsupport vehicle type") type healthCheckSchema struct { - Enable bool `provider:"enable"` - URL string `provider:"url"` - Interval int `provider:"interval"` - Lazy bool `provider:"lazy,omitempty"` + Enable bool `provider:"enable"` + URL string `provider:"url"` + Interval int `provider:"interval"` + Lazy bool `provider:"lazy,omitempty"` + ExpectedStatus string `provider:"expected-status,omitempty"` } type proxyProviderSchema struct { @@ -44,11 +46,16 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide return nil, err } + expectedStatus, err := utils.NewIntRanges[uint16](schema.HealthCheck.ExpectedStatus) + if err != nil { + return nil, err + } + var hcInterval uint if schema.HealthCheck.Enable { hcInterval = uint(schema.HealthCheck.Interval) } - hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, hcInterval, schema.HealthCheck.Lazy) + hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, hcInterval, schema.HealthCheck.Lazy, expectedStatus) path := C.Path.Resolve(schema.Path) diff --git a/config/config.go b/config/config.go index 2f563b30..191dbf13 100644 --- a/config/config.go +++ b/config/config.go @@ -654,7 +654,7 @@ func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[ } ps = append(ps, proxies[v]) } - hc := provider.NewHealthCheck(ps, "", 0, true) + hc := provider.NewHealthCheck(ps, "", 0, true, nil) pd, _ := provider.NewCompatibleProvider(provider.ReservedName, ps, hc) providersMap[provider.ReservedName] = pd From fd0c71a485432e98991415cc4a9dcae261f96cbc Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 4 Jun 2023 15:51:25 +0800 Subject: [PATCH 11/79] chore: Ignore PR in Docker build --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index bbf8e721..26dc455b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -285,6 +285,7 @@ jobs: generate_release_notes: true Docker: + if: ${{ github.event_name != 'pull_request' }} permissions: write-all needs: [Build] runs-on: ubuntu-latest From fdaa6a22a4d14ccb08a5173128e1c47585678627 Mon Sep 17 00:00:00 2001 From: Mars160 <74127225+Mars160@users.noreply.github.com> Date: Sun, 4 Jun 2023 23:43:54 +0800 Subject: [PATCH 12/79] fix hysteria faketcp lookback in TUN mode (#601) --- component/dialer/bind.go | 2 +- component/iface/iface.go | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/component/dialer/bind.go b/component/dialer/bind.go index 34d40ca2..edfc79c7 100644 --- a/component/dialer/bind.go +++ b/component/dialer/bind.go @@ -22,7 +22,7 @@ func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination addr, err = ifaceObj.PickIPv6Addr(destination) default: if destination.IsValid() { - if destination.Is4() { + if destination.Is4() || destination.Is4In6() { addr, err = ifaceObj.PickIPv4Addr(destination) } else { addr, err = ifaceObj.PickIPv6Addr(destination) diff --git a/component/iface/iface.go b/component/iface/iface.go index 11c754f8..c32b65ab 100644 --- a/component/iface/iface.go +++ b/component/iface/iface.go @@ -4,6 +4,7 @@ import ( "errors" "net" "net/netip" + "strings" "time" "github.com/Dreamacro/clash/common/singledo" @@ -37,12 +38,21 @@ func ResolveInterface(name string) (*Interface, error) { if err != nil { continue } + // if not available device like Meta, dummy0, docker0, etc. + if (iface.Flags&net.FlagMulticast == 0) || (iface.Flags&net.FlagPointToPoint != 0) || (iface.Flags&net.FlagRunning == 0) { + continue + } ipNets := make([]*netip.Prefix, 0, len(addrs)) for _, addr := range addrs { ipNet := addr.(*net.IPNet) ip, _ := netip.AddrFromSlice(ipNet.IP) + //unavailable IPv6 Address + if ip.Is6() && strings.HasPrefix(ip.String(), "fe80") { + continue + } + ones, bits := ipNet.Mask.Size() if bits == 32 { ip = ip.Unmap() From e7174866e501dcdd525660cafe788ee2e55ac76b Mon Sep 17 00:00:00 2001 From: wzdnzd Date: Mon, 5 Jun 2023 12:40:46 +0800 Subject: [PATCH 13/79] fix: nil pointer in urltest (#603) --- adapter/adapter.go | 2 +- common/utils/ranges.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index d2c362bc..32fd2b77 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -287,7 +287,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In } } - if !expectedStatus.Check(uint16(resp.StatusCode)) { + if expectedStatus != nil && !expectedStatus.Check(uint16(resp.StatusCode)) { // maybe another value should be returned for differentiation err = errors.New("response status is inconsistent with the expected status") } diff --git a/common/utils/ranges.go b/common/utils/ranges.go index a6293f65..705bbdee 100644 --- a/common/utils/ranges.go +++ b/common/utils/ranges.go @@ -63,7 +63,7 @@ func NewIntRangesFromList[T constraints.Integer](list []string) (IntRanges[T], e } func (ranges IntRanges[T]) Check(status T) bool { - if ranges == nil || len(ranges) == 0 { + if len(ranges) == 0 { return true } From dafecebdc09627e74324f8d3e5e967e0894dce6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=A0=E3=83=A9=E3=82=A4=E3=83=B3?= <53483352+Nep-Timeline@users.noreply.github.com> Date: Tue, 6 Jun 2023 09:45:05 +0800 Subject: [PATCH 14/79] chore: Something update from clash :) (#606) --- Makefile | 5 ++++ adapter/outboundgroup/parser.go | 12 ++++---- adapter/provider/parser.go | 8 ++++- component/process/process_windows.go | 2 +- config/config.go | 2 +- constant/path.go | 12 ++++++++ dns/resolver.go | 3 +- dns/util.go | 29 ++++++++++++++++-- go.mod | 2 +- hub/route/server.go | 12 ++++++-- listener/redir/tcp_freebsd.go | 44 ++++++++++++++++++---------- 11 files changed, 100 insertions(+), 31 deletions(-) diff --git a/Makefile b/Makefile index ecd1f5e6..028b986c 100644 --- a/Makefile +++ b/Makefile @@ -31,6 +31,8 @@ PLATFORM_LIST = \ linux-mips-hardfloat \ linux-mipsle-softfloat \ linux-mipsle-hardfloat \ + linux-riscv64 \ + linux-loong64 \ android-arm64 \ freebsd-386 \ freebsd-amd64 \ @@ -103,6 +105,9 @@ linux-mips64le: linux-riscv64: GOARCH=riscv64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ + +linux-loong64: + GOARCH=loong64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ android-arm64: GOARCH=arm64 GOOS=android $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 7ebaa6c0..684960b3 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -56,12 +56,12 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide providers := []types.ProxyProvider{} if len(groupOption.Proxies) == 0 && len(groupOption.Use) == 0 { - return nil, errMissProxy + return nil, fmt.Errorf("%s: %w", groupName, errMissProxy) } expectedStatus, err := utils.NewIntRanges[uint16](groupOption.ExpectedStatus) if err != nil { - return nil, err + return nil, fmt.Errorf("%s: %w", groupName, err) } status := strings.TrimSpace(groupOption.ExpectedStatus) @@ -74,17 +74,17 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide if len(groupOption.Proxies) != 0 { ps, err := getProxies(proxyMap, groupOption.Proxies) if err != nil { - return nil, err + return nil, fmt.Errorf("%s: %w", groupName, err) } if _, ok := providersMap[groupName]; ok { - return nil, errDuplicateProvider + return nil, fmt.Errorf("%s: %w", groupName, errDuplicateProvider) } hc := provider.NewHealthCheck(ps, "", 0, true, nil) pd, err := provider.NewCompatibleProvider(groupName, ps, hc) if err != nil { - return nil, err + return nil, fmt.Errorf("%s: %w", groupName, err) } // select don't need health check @@ -107,7 +107,7 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide if len(groupOption.Use) != 0 { list, err := getProviders(providersMap, groupOption.Use) if err != nil { - return nil, err + return nil, fmt.Errorf("%s: %w", groupName, err) } // different proxy groups use different test URL diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 954db5cb..07bef4e5 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -12,7 +12,10 @@ import ( types "github.com/Dreamacro/clash/constant/provider" ) -var errVehicleType = errors.New("unsupport vehicle type") +var ( + errVehicleType = errors.New("unsupport vehicle type") + errSubPath = errors.New("path is not subpath of home directory") +) type healthCheckSchema struct { Enable bool `provider:"enable"` @@ -64,6 +67,9 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide case "file": vehicle = resource.NewFileVehicle(path) case "http": + if !C.Path.IsSubPath(path) { + return nil, fmt.Errorf("%w: %s", errSubPath, path) + } vehicle = resource.NewHTTPVehicle(schema.URL, path) default: return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type) diff --git a/component/process/process_windows.go b/component/process/process_windows.go index cce08e30..21878bf6 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -67,7 +67,7 @@ func findProcessName(network string, ip netip.Addr, srcPort int) (uint32, string err := initWin32API() if err != nil { log.Errorln("Initialize PROCESS-NAME failed: %s", err.Error()) - log.Warnln("All PROCESS-NAMES rules will be skiped") + log.Warnln("All PROCESS-NAMES rules will be skipped") return } }) diff --git a/config/config.go b/config/config.go index 191dbf13..5f1c6710 100644 --- a/config/config.go +++ b/config/config.go @@ -913,7 +913,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) addr, err = hostWithDefaultPort(u.Host, "443") if err == nil { proxyName = "" - clearURL := url.URL{Scheme: "https", Host: addr, Path: u.Path} + clearURL := url.URL{Scheme: "https", Host: addr, Path: u.Path, User: u.User} addr = clearURL.String() dnsNetType = "https" // DNS over HTTPS if len(u.Fragment) != 0 { diff --git a/constant/path.go b/constant/path.go index 29ac9872..e724e6b4 100644 --- a/constant/path.go +++ b/constant/path.go @@ -56,6 +56,18 @@ func (p *path) Resolve(path string) string { return path } +// IsSubPath return true if path is a subpath of homedir +func (p *path) IsSubPath(path string) bool { + homedir := p.HomeDir() + path = p.Resolve(path) + rel, err := filepath.Rel(homedir, path) + if err != nil { + return false + } + + return !strings.Contains(rel, "..") +} + func (p *path) MMDB() string { files, err := os.ReadDir(p.homeDir) if err != nil { diff --git a/dns/resolver.go b/dns/resolver.go index 7e1b007d..5ae7ba33 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -165,7 +165,8 @@ func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, e setMsgTTL(msg, uint32(1)) // Continue fetch continueFetch = true } else { - setMsgTTL(msg, uint32(time.Until(expireTime).Seconds())) + // updating TTL by subtracting common delta time from each DNS record + updateMsgTTL(msg, uint32(time.Until(expireTime).Seconds())) } return } diff --git a/dns/util.go b/dns/util.go index d85deb17..1b8f9635 100644 --- a/dns/util.go +++ b/dns/util.go @@ -21,12 +21,29 @@ import ( "github.com/Dreamacro/clash/tunnel" D "github.com/miekg/dns" + "github.com/samber/lo" ) const ( MaxMsgSize = 65535 ) +func minimalTTL(records []D.RR) uint32 { + return lo.MinBy(records, func(r1 D.RR, r2 D.RR) bool { + return r1.Header().Ttl < r2.Header().Ttl + }).Header().Ttl +} + +func updateTTL(records []D.RR, ttl uint32) { + if len(records) == 0 { + return + } + delta := minimalTTL(records) - ttl + for i := range records { + records[i].Header().Ttl = lo.Clamp(records[i].Header().Ttl-delta, 1, records[i].Header().Ttl) + } +} + func putMsgToCache(c *cache.LruCache[string, *D.Msg], key string, msg *D.Msg) { // skip dns cache for acme challenge if len(msg.Question) != 0 { @@ -38,11 +55,11 @@ func putMsgToCache(c *cache.LruCache[string, *D.Msg], key string, msg *D.Msg) { var ttl uint32 switch { case len(msg.Answer) != 0: - ttl = msg.Answer[0].Header().Ttl + ttl = minimalTTL(msg.Answer) case len(msg.Ns) != 0: - ttl = msg.Ns[0].Header().Ttl + ttl = minimalTTL(msg.Ns) case len(msg.Extra) != 0: - ttl = msg.Extra[0].Header().Ttl + ttl = minimalTTL(msg.Extra) default: log.Debugln("[DNS] response msg empty: %#v", msg) return @@ -65,6 +82,12 @@ func setMsgTTL(msg *D.Msg, ttl uint32) { } } +func updateMsgTTL(msg *D.Msg, ttl uint32) { + updateTTL(msg.Answer, ttl) + updateTTL(msg.Ns, ttl) + updateTTL(msg.Extra, ttl) +} + func isIPRequest(q D.Question) bool { return q.Qclass == D.ClassINET && (q.Qtype == D.TypeA || q.Qtype == D.TypeAAAA || q.Qtype == D.TypeCNAME) } diff --git a/go.mod b/go.mod index 89071513..29dd4b86 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Dreamacro/clash -go 1.19 +go 1.20 require ( github.com/3andne/restls-client-go v0.1.4 diff --git a/hub/route/server.go b/hub/route/server.go index d8124d33..8ccb79f5 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -2,12 +2,14 @@ package route import ( "bytes" + "crypto/subtle" "crypto/tls" "encoding/json" "net/http" "runtime/debug" "strings" "time" + "unsafe" "github.com/Dreamacro/clash/adapter/inbound" CN "github.com/Dreamacro/clash/common/net" @@ -149,6 +151,12 @@ func Start(addr string, tlsAddr string, secret string, } +func safeEuqal(a, b string) bool { + aBuf := unsafe.Slice(unsafe.StringData(a), len(a)) + bBuf := unsafe.Slice(unsafe.StringData(b), len(b)) + return subtle.ConstantTimeCompare(aBuf, bBuf) == 1 +} + func authentication(next http.Handler) http.Handler { fn := func(w http.ResponseWriter, r *http.Request) { if serverSecret == "" { @@ -159,7 +167,7 @@ func authentication(next http.Handler) http.Handler { // Browser websocket not support custom header if websocket.IsWebSocketUpgrade(r) && r.URL.Query().Get("token") != "" { token := r.URL.Query().Get("token") - if token != serverSecret { + if !safeEuqal(token, serverSecret) { render.Status(r, http.StatusUnauthorized) render.JSON(w, r, ErrUnauthorized) return @@ -172,7 +180,7 @@ func authentication(next http.Handler) http.Handler { bearer, token, found := strings.Cut(header, " ") hasInvalidHeader := bearer != "Bearer" - hasInvalidSecret := !found || token != serverSecret + hasInvalidSecret := !found || !safeEuqal(token, serverSecret) if hasInvalidHeader || hasInvalidSecret { render.Status(r, http.StatusUnauthorized) render.JSON(w, r, ErrUnauthorized) diff --git a/listener/redir/tcp_freebsd.go b/listener/redir/tcp_freebsd.go index 12c4ba6a..6ecb2496 100644 --- a/listener/redir/tcp_freebsd.go +++ b/listener/redir/tcp_freebsd.go @@ -1,12 +1,16 @@ package redir import ( + "encoding/binary" "errors" "net" + "net/netip" "syscall" "unsafe" "github.com/Dreamacro/clash/transport/socks5" + + "golang.org/x/sys/unix" ) const ( @@ -25,28 +29,38 @@ func parserPacket(conn net.Conn) (socks5.Addr, error) { return nil, err } - var addr socks5.Addr + var addr netip.AddrPort rc.Control(func(fd uintptr) { - addr, err = getorigdst(fd) + if ip4 := c.LocalAddr().(*net.TCPAddr).IP.To4(); ip4 != nil { + addr, err = getorigdst(fd) + } else { + addr, err = getorigdst6(fd) + } }) - return addr, err + return socks5.AddrFromStdAddrPort(addr), err } // Call getorigdst() from linux/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c -func getorigdst(fd uintptr) (socks5.Addr, error) { - raw := syscall.RawSockaddrInet4{} - siz := unsafe.Sizeof(raw) - _, _, err := syscall.Syscall6(syscall.SYS_GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&raw)), uintptr(unsafe.Pointer(&siz)), 0) +func getorigdst(fd uintptr) (netip.AddrPort, error) { + addr := unix.RawSockaddrInet4{} + size := uint32(unsafe.Sizeof(addr)) + _, _, err := syscall.Syscall6(syscall.SYS_GETSOCKOPT, fd, syscall.IPPROTO_IP, SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&size)), 0) if err != 0 { - return nil, err + return netip.AddrPort{}, err } - - addr := make([]byte, 1+net.IPv4len+2) - addr[0] = socks5.AtypIPv4 - copy(addr[1:1+net.IPv4len], raw.Addr[:]) - port := (*[2]byte)(unsafe.Pointer(&raw.Port)) // big-endian - addr[1+net.IPv4len], addr[1+net.IPv4len+1] = port[0], port[1] - return addr, nil + port := binary.BigEndian.Uint16((*(*[2]byte)(unsafe.Pointer(&addr.Port)))[:]) + return netip.AddrPortFrom(netip.AddrFrom4(addr.Addr), port), nil +} + +func getorigdst6(fd uintptr) (netip.AddrPort, error) { + addr := unix.RawSockaddrInet6{} + size := uint32(unsafe.Sizeof(addr)) + _, _, err := syscall.Syscall6(syscall.SYS_GETSOCKOPT, fd, syscall.IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, uintptr(unsafe.Pointer(&addr)), uintptr(unsafe.Pointer(&size)), 0) + if err != 0 { + return netip.AddrPort{}, err + } + port := binary.BigEndian.Uint16((*(*[2]byte)(unsafe.Pointer(&addr.Port)))[:]) + return netip.AddrPortFrom(netip.AddrFrom16(addr.Addr), port), nil } From ad11a2b8130aa77eda793f1082f99dd6161da469 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 6 Jun 2023 10:47:50 +0800 Subject: [PATCH 15/79] fix: go1.19 compile --- common/utils/string_unsafe.go | 49 +++++++++++++++++++++++++++++++++++ component/iface/iface.go | 4 ++- component/trie/domain_set.go | 3 ++- go.mod | 2 +- hub/route/server.go | 7 ++--- 5 files changed, 59 insertions(+), 6 deletions(-) create mode 100644 common/utils/string_unsafe.go diff --git a/common/utils/string_unsafe.go b/common/utils/string_unsafe.go new file mode 100644 index 00000000..7733df39 --- /dev/null +++ b/common/utils/string_unsafe.go @@ -0,0 +1,49 @@ +package utils + +import "unsafe" + +// sliceHeader is equivalent to reflect.SliceHeader, but represents the pointer +// to the underlying array as unsafe.Pointer rather than uintptr, allowing +// sliceHeaders to be directly converted to slice objects. +type sliceHeader struct { + Data unsafe.Pointer + Len int + Cap int +} + +// slice returns a slice whose underlying array starts at ptr an which length +// and capacity are len. +func slice[T any](ptr *T, length int) []T { + var s []T + hdr := (*sliceHeader)(unsafe.Pointer(&s)) + hdr.Data = unsafe.Pointer(ptr) + hdr.Len = length + hdr.Cap = length + return s +} + +// stringHeader is equivalent to reflect.StringHeader, but represents the +// pointer to the underlying array as unsafe.Pointer rather than uintptr, +// allowing StringHeaders to be directly converted to strings. +type stringHeader struct { + Data unsafe.Pointer + Len int +} + +// ImmutableBytesFromString is equivalent to []byte(s), except that it uses the +// same memory backing s instead of making a heap-allocated copy. This is only +// valid if the returned slice is never mutated. +func ImmutableBytesFromString(s string) []byte { + shdr := (*stringHeader)(unsafe.Pointer(&s)) + return slice((*byte)(shdr.Data), shdr.Len) +} + +// StringFromImmutableBytes is equivalent to string(bs), except that it uses +// the same memory backing bs instead of making a heap-allocated copy. This is +// only valid if bs is never mutated after StringFromImmutableBytes returns. +func StringFromImmutableBytes(bs []byte) string { + // This is cheaper than messing with StringHeader and SliceHeader, which as + // of this writing produces many dead stores of zeroes. Compare + // strings.Builder.String(). + return *(*string)(unsafe.Pointer(&bs)) +} diff --git a/component/iface/iface.go b/component/iface/iface.go index c32b65ab..dca6cca1 100644 --- a/component/iface/iface.go +++ b/component/iface/iface.go @@ -24,6 +24,8 @@ var ( var interfaces = singledo.NewSingle[map[string]*Interface](time.Second * 20) +const FlagRunning = 32 // interface is in running state, compatibility with golang<1.20 + func ResolveInterface(name string) (*Interface, error) { value, err, _ := interfaces.Do(func() (map[string]*Interface, error) { ifaces, err := net.Interfaces() @@ -39,7 +41,7 @@ func ResolveInterface(name string) (*Interface, error) { continue } // if not available device like Meta, dummy0, docker0, etc. - if (iface.Flags&net.FlagMulticast == 0) || (iface.Flags&net.FlagPointToPoint != 0) || (iface.Flags&net.FlagRunning == 0) { + if (iface.Flags&net.FlagMulticast == 0) || (iface.Flags&net.FlagPointToPoint != 0) || (iface.Flags&FlagRunning == 0) { continue } diff --git a/component/trie/domain_set.go b/component/trie/domain_set.go index 41ca2161..e1ad6559 100644 --- a/component/trie/domain_set.go +++ b/component/trie/domain_set.go @@ -23,6 +23,8 @@ type DomainSet struct { ranks, selects []int32 } +type qElt struct{ s, e, col int } + // NewDomainSet creates a new *DomainSet struct, from a DomainTrie. func (t *DomainTrie[T]) NewDomainSet() *DomainSet { reserveDomains := make([]string, 0) @@ -39,7 +41,6 @@ func (t *DomainTrie[T]) NewDomainSet() *DomainSet { ss := &DomainSet{} lIdx := 0 - type qElt struct{ s, e, col int } queue := []qElt{{0, len(keys), 0}} for i := 0; i < len(queue); i++ { elt := queue[i] diff --git a/go.mod b/go.mod index 29dd4b86..89071513 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Dreamacro/clash -go 1.20 +go 1.19 require ( github.com/3andne/restls-client-go v0.1.4 diff --git a/hub/route/server.go b/hub/route/server.go index 8ccb79f5..d2fecd05 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -9,13 +9,14 @@ import ( "runtime/debug" "strings" "time" - "unsafe" "github.com/Dreamacro/clash/adapter/inbound" CN "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/tunnel/statistic" + "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" @@ -152,8 +153,8 @@ func Start(addr string, tlsAddr string, secret string, } func safeEuqal(a, b string) bool { - aBuf := unsafe.Slice(unsafe.StringData(a), len(a)) - bBuf := unsafe.Slice(unsafe.StringData(b), len(b)) + aBuf := utils.ImmutableBytesFromString(a) + bBuf := utils.ImmutableBytesFromString(b) return subtle.ConstantTimeCompare(aBuf, bBuf) == 1 } From 767aa182b9116902e5f7f0f7d8e98ad7043dcd65 Mon Sep 17 00:00:00 2001 From: wzdnzd Date: Wed, 7 Jun 2023 11:04:03 +0800 Subject: [PATCH 16/79] When testing the delay through REST API, determine whether to store the delay data based on certain conditions instead of discarding it directly (#609) --- adapter/adapter.go | 35 ++++++++++++++++++++++++++++++--- adapter/outboundgroup/parser.go | 17 +++++++++------- adapter/provider/healthcheck.go | 10 +++++++--- constant/adapters.go | 7 ++++--- 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 32fd2b77..32b6bae0 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -34,6 +34,7 @@ type Proxy struct { C.ProxyAdapter history *queue.Queue[C.DelayHistory] alive *atomic.Bool + url string extra map[string]*extraProxyState } @@ -112,14 +113,14 @@ func (p *Proxy) DelayHistoryForTestUrl(url string) []C.DelayHistory { func (p *Proxy) ExtraDelayHistory() map[string][]C.DelayHistory { extra := map[string][]C.DelayHistory{} if p.extra != nil && len(p.extra) != 0 { - for url, option := range p.extra { + for testUrl, option := range p.extra { histories := []C.DelayHistory{} queueM := option.history.Copy() for _, item := range queueM { histories = append(histories, item) } - extra[url] = histories + extra[testUrl] = histories } } return extra @@ -187,6 +188,8 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.IntRanges[uint16], store C.DelayHistoryStoreType) (t uint16, err error) { defer func() { alive := err == nil + store = p.determineFinalStoreType(store, url) + switch store { case C.OriginalHistory: p.alive.Store(alive) @@ -198,6 +201,11 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In if p.history.Len() > defaultHistoriesNum { p.history.Pop() } + + // test URL configured by the proxy provider + if len(p.url) == 0 { + p.url = url + } case C.ExtraHistory: record := C.DelayHistory{Time: time.Now()} if alive { @@ -297,7 +305,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In } func NewProxy(adapter C.ProxyAdapter) *Proxy { - return &Proxy{adapter, queue.New[C.DelayHistory](defaultHistoriesNum), atomic.NewBool(true), map[string]*extraProxyState{}} + return &Proxy{adapter, queue.New[C.DelayHistory](defaultHistoriesNum), atomic.NewBool(true), "", map[string]*extraProxyState{}} } func urlToMetadata(rawURL string) (addr C.Metadata, err error) { @@ -326,3 +334,24 @@ func urlToMetadata(rawURL string) (addr C.Metadata, err error) { } return } + +func (p *Proxy) determineFinalStoreType(store C.DelayHistoryStoreType, url string) C.DelayHistoryStoreType { + if store != C.DropHistory { + return store + } + + if len(p.url) == 0 || url == p.url { + return C.OriginalHistory + } + + if p.extra == nil { + store = C.ExtraHistory + } else { + if _, ok := p.extra[url]; ok { + store = C.ExtraHistory + } else if len(p.extra) < 2*C.DefaultMaxHealthCheckUrlNum { + store = C.ExtraHistory + } + } + return store +} diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 684960b3..a8bdc557 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -17,7 +17,6 @@ var ( errFormat = errors.New("format error") errType = errors.New("unsupported type") errMissProxy = errors.New("`use` or `proxies` missing") - errMissHealthCheck = errors.New("`url` or `interval` missing") errDuplicateProvider = errors.New("duplicate provider name") ) @@ -81,11 +80,8 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide return nil, fmt.Errorf("%s: %w", groupName, errDuplicateProvider) } - hc := provider.NewHealthCheck(ps, "", 0, true, nil) - pd, err := provider.NewCompatibleProvider(groupName, ps, hc) - if err != nil { - return nil, fmt.Errorf("%s: %w", groupName, err) - } + var url string + var interval uint // select don't need health check if groupOption.Type != "select" && groupOption.Type != "relay" { @@ -97,7 +93,14 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide groupOption.Interval = 300 } - pd.RegisterHealthCheckTask(groupOption.URL, expectedStatus, "", uint(groupOption.Interval)) + url = groupOption.URL + interval = uint(groupOption.Interval) + } + + hc := provider.NewHealthCheck(ps, url, interval, true, expectedStatus) + pd, err := provider.NewCompatibleProvider(groupName, ps, hc) + if err != nil { + return nil, fmt.Errorf("%s: %w", groupName, err) } providers = append(providers, pd) diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 330e306e..35327b1c 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -18,7 +18,6 @@ import ( const ( defaultURLTestTimeout = time.Second * 5 - defaultMaxTestUrlNum = 6 ) type HealthCheckOption struct { @@ -105,8 +104,8 @@ func (hc *HealthCheck) registerHealthCheckTask(url string, expectedStatus utils. } // due to the time-consuming nature of health checks, a maximum of defaultMaxTestURLNum URLs can be set for testing - if len(hc.extra) > defaultMaxTestUrlNum { - log.Debugln("skip add url: %s to health check because it has reached the maximum limit: %d", url, defaultMaxTestUrlNum) + if len(hc.extra) > C.DefaultMaxHealthCheckUrlNum { + log.Debugln("skip add url: %s to health check because it has reached the maximum limit: %d", url, C.DefaultMaxHealthCheckUrlNum) return } @@ -220,6 +219,11 @@ func (hc *HealthCheck) close() { } func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, expectedStatus utils.IntRanges[uint16]) *HealthCheck { + if len(url) == 0 { + interval = 0 + expectedStatus = nil + } + return &HealthCheck{ proxies: proxies, url: url, diff --git a/constant/adapters.go b/constant/adapters.go index a55c2d18..a3796ef7 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -41,9 +41,10 @@ const ( ) const ( - DefaultTCPTimeout = 5 * time.Second - DefaultUDPTimeout = DefaultTCPTimeout - DefaultTLSTimeout = DefaultTCPTimeout + DefaultTCPTimeout = 5 * time.Second + DefaultUDPTimeout = DefaultTCPTimeout + DefaultTLSTimeout = DefaultTCPTimeout + DefaultMaxHealthCheckUrlNum = 16 ) var ErrNotSupport = errors.New("no support") From 093453582f23a714104fe4a54e7e29445db72344 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 7 Jun 2023 13:20:45 +0800 Subject: [PATCH 17/79] fix: Resolve delay omission in the presence of nested proxy-groups --- hub/route/proxies.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hub/route/proxies.go b/hub/route/proxies.go index ea6a3302..36c9d1b1 100644 --- a/hub/route/proxies.go +++ b/hub/route/proxies.go @@ -125,7 +125,7 @@ func getProxyDelay(w http.ResponseWriter, r *http.Request) { ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*time.Duration(timeout)) defer cancel() - delay, err := proxy.URLTest(ctx, url, expectedStatus, C.DropHistory) + delay, err := proxy.URLTest(ctx, url, expectedStatus, C.ExtraHistory) if ctx.Err() != nil { render.Status(r, http.StatusGatewayTimeout) render.JSON(w, r, ErrRequestTimeout) From c3ef05b257a8310adf31b06eb21126e6a6626ad7 Mon Sep 17 00:00:00 2001 From: H1JK Date: Wed, 7 Jun 2023 23:03:36 +0800 Subject: [PATCH 18/79] 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 { From 766d08a8eb98af582de2bb44aea37677dbc2ce00 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 8 Jun 2023 11:58:38 +0800 Subject: [PATCH 19/79] chore: init gopacket only when dial fake-tcp to decrease memory using --- go.mod | 2 +- go.sum | 8 ++++++-- transport/hysteria/conns/faketcp/tcp_linux.go | 8 ++++++-- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index 7c3d56f2..12155a5b 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,6 @@ require ( github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.2 github.com/gofrs/uuid/v5 v5.0.0 - github.com/google/gopacket v1.1.19 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/golang-lru v0.5.4 github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb @@ -20,6 +19,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.5 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 + github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca diff --git a/go.sum b/go.sum index 0d3eebbf..8e868b55 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= @@ -91,6 +89,8 @@ github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/ github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= +github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb h1:92YTNmYXCSycERjKn/zPbeK5DiW3dd80j3+oVTEWTE8= @@ -191,6 +191,9 @@ github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYm github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM= @@ -228,6 +231,7 @@ golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/transport/hysteria/conns/faketcp/tcp_linux.go b/transport/hysteria/conns/faketcp/tcp_linux.go index 1d6f277c..76ed0d5e 100644 --- a/transport/hysteria/conns/faketcp/tcp_linux.go +++ b/transport/hysteria/conns/faketcp/tcp_linux.go @@ -17,8 +17,8 @@ import ( "time" "github.com/coreos/go-iptables/iptables" - "github.com/google/gopacket" - "github.com/google/gopacket/layers" + "github.com/metacubex/gopacket" + "github.com/metacubex/gopacket/layers" "github.com/Dreamacro/clash/component/dialer" ) @@ -394,6 +394,8 @@ func (conn *TCPConn) SyscallConn() (syscall.RawConn, error) { // Dial connects to the remote TCP port, // and returns a single packet-oriented connection func Dial(network, address string) (*TCPConn, error) { + // init gopacket.layers + layers.Init() // remote address resolve raddr, err := net.ResolveTCPAddr(network, address) if err != nil { @@ -478,6 +480,8 @@ func Dial(network, address string) (*TCPConn, error) { // Listen acts like net.ListenTCP, // and returns a single packet-oriented connection func Listen(network, address string) (*TCPConn, error) { + // init gopacket.layers + layers.Init() // fields conn := new(TCPConn) conn.flowTable = make(map[string]*tcpFlow) From cd44901e90b0dbe2d42c97035935b9303d513367 Mon Sep 17 00:00:00 2001 From: H1JK Date: Thu, 8 Jun 2023 15:57:51 +0800 Subject: [PATCH 20/79] fix: Disable XUDP global ID if source address invalid --- adapter/outbound/vless.go | 6 +++++- adapter/outbound/vmess.go | 8 ++++++-- constant/metadata.go | 4 ++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 558342d5..325ccccd 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -374,9 +374,13 @@ func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada } if v.option.XUDP { + var globalID [8]byte + if metadata.SourceValid() { + globalID = utils.GlobalID(metadata.SourceAddress()) + } return newPacketConn(N.NewThreadSafePacketConn( vmessSing.NewXUDPConn(c, - utils.GlobalID(metadata.SourceAddress()), + globalID, M.SocksaddrFromNet(metadata.UDPAddr())), ), v), nil } else if v.option.PacketAddr { diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 0a75aa1a..e9409aa4 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -224,13 +224,17 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M func (v *Vmess) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err error) { if metadata.NetWork == C.UDP { if v.option.XUDP { + var globalID [8]byte + if metadata.SourceValid() { + globalID = utils.GlobalID(metadata.SourceAddress()) + } if N.NeedHandshake(c) { conn = v.client.DialEarlyXUDPPacketConn(c, - utils.GlobalID(metadata.SourceAddress()), + globalID, M.SocksaddrFromNet(metadata.UDPAddr())) } else { conn, err = v.client.DialXUDPPacketConn(c, - utils.GlobalID(metadata.SourceAddress()), + globalID, M.SocksaddrFromNet(metadata.UDPAddr())) } } else if v.option.PacketAddr { diff --git a/constant/metadata.go b/constant/metadata.go index edc58aec..de26a05f 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -171,6 +171,10 @@ func (m *Metadata) SourceDetail() string { } } +func (m *Metadata) SourceValid() bool { + return m.SrcPort != "" && m.SrcIP.IsValid() +} + func (m *Metadata) AddrType() int { switch true { case m.Host != "" || !m.DstIP.IsValid(): From c57f17d0944435a9c553ccdb96fefe9b42c28483 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 8 Jun 2023 18:07:56 +0800 Subject: [PATCH 21/79] chore: reduce process lookup attempts when process not exist #613 --- tunnel/tunnel.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index cbbcaa75..e375f656 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -539,8 +539,8 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { configMux.RLock() defer configMux.RUnlock() var ( - resolved bool - processFound bool + resolved bool + attemptProcessLookup = true ) if node, ok := resolver.DefaultHosts.Search(metadata.Host, false); ok { @@ -564,8 +564,9 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { }() } - if !findProcessMode.Off() && !processFound && (findProcessMode.Always() || rule.ShouldFindProcess()) { - srcPort, err := strconv.ParseUint(metadata.SrcPort, 10, 16) + if attemptProcessLookup && !findProcessMode.Off() && (findProcessMode.Always() || rule.ShouldFindProcess()) { + attemptProcessLookup = false + srcPort, _ := strconv.ParseUint(metadata.SrcPort, 10, 16) uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(srcPort)) if err != nil { log.Debugln("[Process] find process %s: %v", metadata.String(), err) @@ -573,7 +574,6 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { metadata.Process = filepath.Base(path) metadata.ProcessPath = path metadata.Uid = uid - processFound = true } } From 64b23257dbfe57fb324b7871e1a2df4c2bf8ccb1 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 10 Jun 2023 17:35:19 +0800 Subject: [PATCH 22/79] chore: Replace murmur3 with maphash --- adapter/outboundgroup/loadbalance.go | 6 +- common/utils/global_id.go | 4 + test/go.mod | 69 ++++++------ test/go.sum | 157 ++++++++++++++------------- 4 files changed, 122 insertions(+), 114 deletions(-) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index dd2c0c99..e336c5f0 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -12,8 +12,8 @@ import ( "github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/common/callback" - "github.com/Dreamacro/clash/common/murmur3" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" @@ -164,7 +164,7 @@ func strategyRoundRobin(url string) strategyFn { func strategyConsistentHashing(url string) strategyFn { maxRetry := 5 return func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy { - key := uint64(murmur3.Sum32([]byte(getKey(metadata)))) + key := utils.MapHash(getKey(metadata)) buckets := int32(len(proxies)) for i := 0; i < maxRetry; i, key = i+1, key+1 { idx := jumpHash(key, buckets) @@ -194,7 +194,7 @@ func strategyStickySessions(url string) strategyFn { cache.WithAge[uint64, int](int64(ttl.Seconds())), cache.WithSize[uint64, int](1000)) return func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy { - key := uint64(murmur3.Sum32([]byte(getKeyWithSrcAndDst(metadata)))) + key := utils.MapHash(getKeyWithSrcAndDst(metadata)) length := len(proxies) idx, has := lruCache.Get(key) if !has { diff --git a/common/utils/global_id.go b/common/utils/global_id.go index e634116a..68b46137 100644 --- a/common/utils/global_id.go +++ b/common/utils/global_id.go @@ -11,3 +11,7 @@ func GlobalID(material string) (id [8]byte) { *(*uint64)(unsafe.Pointer(&id[0])) = maphash.String(globalSeed, material) return } + +func MapHash(material string) uint64 { + return maphash.String(globalSeed, material) +} diff --git a/test/go.mod b/test/go.mod index 1327f84f..957c444b 100644 --- a/test/go.mod +++ b/test/go.mod @@ -6,9 +6,9 @@ require ( github.com/Dreamacro/clash v0.0.0 github.com/docker/docker v20.10.21+incompatible github.com/docker/go-connections v0.4.0 - github.com/miekg/dns v1.1.53 - github.com/stretchr/testify v1.8.2 - golang.org/x/net v0.9.0 + github.com/miekg/dns v1.1.54 + github.com/stretchr/testify v1.8.3 + golang.org/x/net v0.10.0 ) replace github.com/Dreamacro/clash => ../ @@ -20,11 +20,11 @@ require ( github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/andybalholm/brotli v1.0.5 // indirect - github.com/cilium/ebpf v0.9.3 // indirect + github.com/cilium/ebpf v0.10.0 // indirect github.com/coreos/go-iptables v0.6.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dlclark/regexp2 v1.7.0 // indirect - github.com/docker/distribution v2.8.1+incompatible // indirect + github.com/dlclark/regexp2 v1.10.0 // indirect + github.com/docker/distribution v2.8.2+incompatible // indirect github.com/docker/go-units v0.4.0 // indirect github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect @@ -38,27 +38,28 @@ require ( github.com/golang/mock v1.6.0 // indirect github.com/google/btree v1.0.1 // indirect github.com/google/go-cmp v0.5.9 // indirect - github.com/google/gopacket v1.1.19 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 // indirect + github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb // indirect github.com/josharian/native v1.1.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.15.15 // indirect - github.com/klauspost/cpuid/v2 v2.0.12 // indirect + github.com/klauspost/cpuid/v2 v2.2.5 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect - github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 // indirect - github.com/mdlayher/socket v0.4.0 // indirect + github.com/mdlayher/netlink v1.7.2 // indirect + github.com/mdlayher/socket v0.4.1 // indirect + github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c // indirect - github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 // indirect - github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba // indirect - github.com/metacubex/sing-tun v0.1.4 // indirect + github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb // indirect + github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c // indirect + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca // indirect + github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e // indirect github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a // indirect - github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect + github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/mroth/weightedrand/v2 v2.0.0 // indirect + github.com/mroth/weightedrand/v2 v2.0.1 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/openacid/low v0.1.21 // indirect @@ -71,44 +72,44 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.2.1 // indirect - github.com/quic-go/qtls-go1-20 v0.1.1 // indirect + github.com/quic-go/qtls-go1-19 v0.3.2 // indirect + github.com/quic-go/qtls-go1-20 v0.2.2 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a // indirect - github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e // indirect - github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9 // indirect - github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b // indirect + github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c // indirect + github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 // indirect + github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3 // indirect github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 // indirect github.com/samber/lo v1.38.1 // indirect - github.com/shirou/gopsutil/v3 v3.23.4 // indirect - github.com/shoenig/go-m1cpu v0.1.5 // indirect + github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect + github.com/shirou/gopsutil/v3 v3.23.5 // indirect + github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect - github.com/sirupsen/logrus v1.9.0 // indirect + github.com/sirupsen/logrus v1.9.2 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 // indirect - github.com/yusufpapurcu/wmi v1.2.2 // indirect + github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 // indirect + github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zhangyunhao116/fastrand v0.3.0 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect - go.etcd.io/bbolt v1.3.6 // indirect - golang.org/x/crypto v0.8.0 // indirect - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect + go.etcd.io/bbolt v1.3.7 // indirect + golang.org/x/crypto v0.9.0 // indirect + golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect golang.org/x/mod v0.8.0 // indirect - golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.7.0 // indirect + golang.org/x/sync v0.2.0 // indirect + golang.org/x/sys v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.org/x/tools v0.6.0 // indirect - google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d // indirect + google.golang.org/protobuf v1.30.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect - lukechampine.com/blake3 v1.1.7 // indirect + lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/test/go.sum b/test/go.sum index b6f03871..dc47342f 100644 --- a/test/go.sum +++ b/test/go.sum @@ -15,17 +15,17 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.9.3 h1:5KtxXZU+scyERvkJMEm16TbScVvuuMrlhPly78ZMbSc= -github.com/cilium/ebpf v0.9.3/go.mod h1:w27N4UjpaQ9X/DGrSugxUG+H+NhgntDuPb5lCzxCn8A= +github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ= +github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE= github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= 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= -github.com/dlclark/regexp2 v1.7.0 h1:7lJfhqlPssTb1WQx4yvTHN0uElPEv52sbaECrAQxjAo= -github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= -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/dlclark/regexp2 v1.10.0 h1:+/GIL799phkJqYW+3YbOd8LCcbHzT0Pbo8zl70MHsq0= +github.com/dlclark/regexp2 v1.10.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= 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= @@ -41,7 +41,7 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBE github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= -github.com/frankban/quicktest v1.14.0 h1:+cqqvzZV87b4adx/5ayVOaYZ2CrvM4ejQvUdBzPPUss= +github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= @@ -63,8 +63,6 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/ github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 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/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= -github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE= github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= @@ -73,8 +71,8 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 h1:+aAGyK41KRn8jbF2Q7PLL0Sxwg6dShGcQSeCC7nZQ8E= -github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI= +github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb h1:6fDKEAXwe3rsfS4khW3EZ8kEqmSiV9szhMPcDrD+Y7Q= +github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -84,38 +82,40 @@ github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.15.15 h1:EF27CXIuDsYJ6mmvtBRlEuB2UVOqHG1tAXgZ7yIO+lw= github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9fHZNnD9+Vo/4= -github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= -github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= -github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg= +github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 h1:EnfXoSqDfSNJv0VBNqY/88RNnhSGYkrHaO0mmFGbVsc= github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40/go.mod h1:vy1vK6wD6j7xX6O6hXe621WabdtNkou2h7uRtTfRMyg= -github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 h1:HSkXG1bE/qcRuuPlZ2Jyf0Od8HLxOowi7CzKQqNtWn4= -github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7/go.mod h1:1ztDZHGbU5MjN5lNZpkpG8ygndjjWzcojp/H7r6l6QQ= -github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= -github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= +github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g= +github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw= +github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U= +github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= +github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= +github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM= github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= -github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 h1:KD96JPdTIayTGGgRl6PuVqo2Bpo6+x3LqDDyqrYDDXw= -github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba h1:He8YwyK600lHAS1xxNsP4k/jnZ8zqQ34XjCGn925+Yk= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= -github.com/metacubex/sing-tun v0.1.4 h1:OQDBNHjuPKrOprCiK+sLt97YQ0K6b9ZWmJB6z51ibZQ= -github.com/metacubex/sing-tun v0.1.4/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= +github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb h1:92YTNmYXCSycERjKn/zPbeK5DiW3dd80j3+oVTEWTE8= +github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb/go.mod h1:6pg8+Tje9KOltnj1whuvB2i5KFUMPp1TAF3oPhc5axM= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c h1:LpVNvlW/xE+mR8z76xJeYZlYznZXEmU4TeWeuygYdJg= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca h1:10qc50Q1hHrfGO4NjEJpIAgHX63Y256tHE0dFCTN8J4= +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-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.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= -github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= -github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c h1:RC8WMpjonrBfyAh6VN/POIPtYD5tRAq0qMqCRjQNK+g= -github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c/go.mod h1:9OcmHNQQUTbk4XCffrLgN1NEKc2mh5u++biHVrvHsSU= +github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= +github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= +github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo= -github.com/mroth/weightedrand/v2 v2.0.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/mroth/weightedrand/v2 v2.0.1 h1:zrEVDIaau/E4QLOKu02kpg8T8myweFlMGikIgbIdrRA= +github.com/mroth/weightedrand/v2 v2.0.1/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= @@ -144,25 +144,23 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1TSG1A= -github.com/quic-go/qtls-go1-19 v0.2.1/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.1.1 h1:KbChDlg82d3IHqaj2bn6GfKRj84Per2VGf5XV3wSwQk= -github.com/quic-go/qtls-go1-20 v0.1.1/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= +github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= +github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= +github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= +github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= 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/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a h1:s2kkd/eR3mWGkYioknxhgQzG8uft4VRx9skhqxxeyVQ= -github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e h1:t8nuY9plpHEzlnPxOpuv64jhjz3teIvccu3YMFX4fJI= -github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= -github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9 h1:0Dc1t9ao9EyvRil6l/950PLwND1qO1rgnxwbcctE8KE= -github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9/go.mod h1:Dpib342FFR68SZ3CSRYxk/zWbanAqRBrCxoLuda5I0A= -github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4= -github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI= +github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c h1:OAwuwvyjPPsCCdSxqZA7T+ABNezeNbF68sRbcMkKT7M= +github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 h1:X3ADfMqeGns1Q1FlXc9kaL9FwW1UM6D6tEQo8jFstpc= +github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= +github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3 h1:PNwJs1F+3e/iZguYQR7YzxsH8Sm0Eu7vVuHawD89r34= +github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI= github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= @@ -175,20 +173,22 @@ github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2d github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0= github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/shirou/gopsutil/v3 v3.23.4 h1:hZwmDxZs7Ewt75DV81r4pFMqbq+di2cbt9FsQBqLD2o= -github.com/shirou/gopsutil/v3 v3.23.4/go.mod h1:ZcGxyfzAMRevhUR2+cfhXDH6gQdFYE/t8j1nsU4mPI8= -github.com/shoenig/go-m1cpu v0.1.5 h1:LF57Z/Fpb/WdGLjt2HZilNnmZOxg/q2bSKTQhgbrLrQ= -github.com/shoenig/go-m1cpu v0.1.5/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= -github.com/shoenig/test v0.6.3 h1:GVXWJFk9PiOjN0KoJ7VrJGH6uLPnqxR7/fe3HUPfE0c= -github.com/shoenig/test v0.6.3/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= +github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= +github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= +github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y= +github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY= +github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= +github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= +github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= +github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnjqq0k= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8= github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b/go.mod h1:X7qrxNQViEaAN9LNZOPl9PfvQtp3V3c7LTo0dvGi0fM= github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6yjG3IxDaeAj3PCoRr+IsO+bzyT+Se2m2Hk= github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c/go.mod h1:NV/a66PhhWYVmUMaotlXJ8fIEFB98u+c8l/CQIEFLrU= github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIFG3i4Gi093BQITvwH9znsz2VUZmnmwHvpIo= github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= +github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -198,36 +198,39 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= -github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= +github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gVBKXc2MVSZ4G/NnWLtzw4gNA= github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 h1:AHhUwwFJGl27E46OpdJHplZkK09m7aETNBNzhT6t15M= -github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= +github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM= +github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg= -github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= +github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiVfzQttTuxanPIT43FtkkCFypIod8LHo= gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= -go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU= -go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4= +go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= +go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= 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.8.0 h1:pd9TJtTueMTVQXzk8E2XESSMQDj/U7OUu0PqJqPXQjQ= -golang.org/x/crypto v0.8.0/go.mod h1:mRqEX+O9/h5TFCrQhkgjo2yKi0yYA+9ecGkdQoHrywE= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= -golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= +golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= +golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -240,21 +243,21 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= -golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= +golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= 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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= -golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -266,8 +269,8 @@ golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= -golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= +golang.org/x/sys v0.8.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= @@ -288,14 +291,14 @@ 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= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d h1:qp0AnQCvRCMlu9jBjtdbTaaEmThIgZOrbVyDEOcmKhQ= -google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= +google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= -lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= -lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= +lukechampine.com/blake3 v1.2.1 h1:YuqqRuaqsGV71BV/nm9xlI0MKUv4QC54jQnBChWbGnI= +lukechampine.com/blake3 v1.2.1/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= From b72219c06a7800766592a24a690384580050b439 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 11 Jun 2023 01:55:49 +0000 Subject: [PATCH 23/79] chore: allow unsafe path for provider by environment variable --- adapter/provider/parser.go | 2 +- constant/path.go | 16 ++++++++++------ docs/config.yaml | 4 ++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 07bef4e5..2281c89b 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -67,7 +67,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide case "file": vehicle = resource.NewFileVehicle(path) case "http": - if !C.Path.IsSubPath(path) { + if !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } vehicle = resource.NewHTTPVehicle(schema.URL, path) diff --git a/constant/path.go b/constant/path.go index e724e6b4..a3124b24 100644 --- a/constant/path.go +++ b/constant/path.go @@ -20,14 +20,15 @@ var Path = func() *path { if err != nil { homeDir, _ = os.Getwd() } - + allowUnsafePath := strings.TrimSpace(os.Getenv("SKIP_SAFE_PATH_CHECK")) == "1" homeDir = P.Join(homeDir, ".config", Name) - return &path{homeDir: homeDir, configFile: "config.yaml"} + return &path{homeDir: homeDir, configFile: "config.yaml", allowUnsafePath: allowUnsafePath} }() type path struct { - homeDir string - configFile string + homeDir string + configFile string + allowUnsafePath bool } // SetHomeDir is used to set the configuration path @@ -56,8 +57,11 @@ func (p *path) Resolve(path string) string { return path } -// IsSubPath return true if path is a subpath of homedir -func (p *path) IsSubPath(path string) bool { +// IsSafePath return true if path is a subpath of homedir +func (p *path) IsSafePath(path string) bool { + if p.allowUnsafePath { + return true + } homedir := p.HomeDir() path = p.Resolve(path) rel, err := filepath.Rel(homedir, path) diff --git a/docs/config.yaml b/docs/config.yaml index 4239abcf..27c6a331 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -773,7 +773,7 @@ proxy-providers: type: http url: "url" interval: 3600 - path: ./provider1.yaml + path: ./provider1.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 health-check: enable: true interval: 600 @@ -790,7 +790,7 @@ rule-providers: rule1: behavior: classical # domain ipcidr interval: 259200 - path: /path/to/save/file.yaml + path: /path/to/save/file.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 type: http url: "url" rule2: From c7de0e0253bed53530a2787b75877c4054cc53c9 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 11 Jun 2023 23:01:45 +0800 Subject: [PATCH 24/79] feat: Add RCode DNS client --- config/config.go | 13 ++++++++++++ dns/rcode.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ dns/util.go | 15 ++++++++------ docs/config.yaml | 1 + 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 dns/rcode.go diff --git a/config/config.go b/config/config.go index 5f1c6710..0a263a08 100644 --- a/config/config.go +++ b/config/config.go @@ -939,6 +939,19 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) dnsNetType = "quic" // DNS over QUIC case "system": dnsNetType = "system" // System DNS + case "rcode": + dnsNetType = "rcode" + addr = u.Host + switch addr { + case "success", + "format_error", + "server_failure", + "name_error", + "not_implemented", + "refused": + default: + err = fmt.Errorf("unsupported RCode type: %s", addr) + } default: return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme) } diff --git a/dns/rcode.go b/dns/rcode.go new file mode 100644 index 00000000..61fc8d72 --- /dev/null +++ b/dns/rcode.go @@ -0,0 +1,54 @@ +package dns + +import ( + "context" + "fmt" + + D "github.com/miekg/dns" +) + +func newRCodeClient(addr string) rcodeClient { + var rcode int + switch addr { + case "success": + rcode = D.RcodeSuccess + case "format_error": + rcode = D.RcodeFormatError + case "server_failure": + rcode = D.RcodeServerFailure + case "name_error": + rcode = D.RcodeNameError + case "not_implemented": + rcode = D.RcodeNotImplemented + case "refused": + rcode = D.RcodeRefused + default: + panic(fmt.Errorf("unsupported RCode type: %s", addr)) + } + + return rcodeClient{ + rcode: rcode, + addr: "rcode://" + addr, + } +} + +type rcodeClient struct { + rcode int + addr string +} + +var _ dnsClient = rcodeClient{} + +func (r rcodeClient) Exchange(m *D.Msg) (*D.Msg, error) { + m.Response = true + m.Rcode = r.rcode + return m, nil +} + +func (r rcodeClient) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) { + return r.Exchange(m) +} + +func (r rcodeClient) Address() string { + return r.addr +} diff --git a/dns/util.go b/dns/util.go index 1b8f9635..a409d679 100644 --- a/dns/util.go +++ b/dns/util.go @@ -93,7 +93,7 @@ func isIPRequest(q D.Question) bool { } func transform(servers []NameServer, resolver *Resolver) []dnsClient { - ret := []dnsClient{} + ret := make([]dnsClient, 0, len(servers)) for _, s := range servers { switch s.Net { case "https": @@ -114,6 +114,9 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { } ret = append(ret, clients...) continue + case "rcode": + ret = append(ret, newRCodeClient(s.Addr)) + continue case "quic": if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil { ret = append(ret, doq) @@ -288,16 +291,16 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) domain := msgToDomain(m) for _, client := range clients { - r := client + _, ignoreRCodeError := client.(rcodeClient) fast.Go(func() (*D.Msg, error) { - log.Debugln("[DNS] resolve %s from %s", domain, r.Address()) - m, err := r.ExchangeContext(ctx, m) + log.Debugln("[DNS] resolve %s from %s", domain, client.Address()) + m, err := client.ExchangeContext(ctx, m) if err != nil { return nil, err - } else if m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused { + } else if !ignoreRCodeError && (m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused) { return nil, errors.New("server failure") } - log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), r.Address()) + log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), client.Address()) return m, nil }) } diff --git a/docs/config.yaml b/docs/config.yaml index 27c6a331..311cf50f 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -238,6 +238,7 @@ dns: "geosite:cn,private,apple": - https://doh.pub/dns-query - https://dns.alidns.com/dns-query + "geosite:category-ads-all": rcode://success "www.baidu.com,+.google.cn": [223.5.5.5, https://dns.alidns.com/dns-query] ## global,dns 为 rule-providers 中的名为 global 和 dns 规则订阅, ## 且 behavior 必须为 domain/classical,当为 classical 时仅会生效域名类规则 From 54337ecdf3d6d4fee0a61e6786ef4e338ab8b93f Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 11 Jun 2023 20:58:51 +0800 Subject: [PATCH 25/79] chore: Disable cache for RCode client --- dns/dhcp.go | 3 ++- dns/resolver.go | 15 ++++++++++----- dns/util.go | 11 +++++++---- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/dns/dhcp.go b/dns/dhcp.go index a6c1df76..7d420d89 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -59,7 +59,8 @@ func (d *dhcpClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, return nil, err } - return batchExchange(ctx, clients, m) + msg, _, err = batchExchange(ctx, clients, m) + return } func (d *dhcpClient) resolve(ctx context.Context) ([]dnsClient, error) { diff --git a/dns/resolver.go b/dns/resolver.go index 5ae7ba33..8f41a44e 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -182,6 +182,7 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M fn := func() (result any, err error) { ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout) // reset timeout in singleflight defer cancel() + cache := false defer func() { if err != nil { @@ -192,7 +193,9 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M msg := result.(*D.Msg) - putMsgToCache(r.lruCache, q.String(), msg) + if cache { + putMsgToCache(r.lruCache, q.String(), msg) + } }() isIPReq := isIPRequest(q) @@ -201,9 +204,11 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M } if matched := r.matchPolicy(m); len(matched) != 0 { - return r.batchExchange(ctx, matched, m) + result, cache, err = r.batchExchange(ctx, matched, m) + return } - return r.batchExchange(ctx, r.main, m) + result, cache, err = r.batchExchange(ctx, r.main, m) + return } ch := r.group.DoChan(q.String(), fn) @@ -244,7 +249,7 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M return } -func (r *Resolver) batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) { +func (r *Resolver) batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, cache bool, err error) { ctx, cancel := context.WithTimeout(ctx, resolver.DefaultDNSTimeout) defer cancel() @@ -371,7 +376,7 @@ func (r *Resolver) lookupIP(ctx context.Context, host string, dnsType uint16) (i func (r *Resolver) asyncExchange(ctx context.Context, client []dnsClient, msg *D.Msg) <-chan *result { ch := make(chan *result, 1) go func() { - res, err := r.batchExchange(ctx, client, msg) + res, _, err := r.batchExchange(ctx, client, msg) ch <- &result{Msg: res, Error: err} }() return ch diff --git a/dns/util.go b/dns/util.go index a409d679..2ba4d426 100644 --- a/dns/util.go +++ b/dns/util.go @@ -287,17 +287,20 @@ func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName st return proxyAdapter.ListenPacketContext(ctx, metadata, opts...) } -func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) { +func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, cache bool, err error) { fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) domain := msgToDomain(m) for _, client := range clients { - _, ignoreRCodeError := client.(rcodeClient) + _, cache = client.(rcodeClient) + cache = !cache fast.Go(func() (*D.Msg, error) { log.Debugln("[DNS] resolve %s from %s", domain, client.Address()) m, err := client.ExchangeContext(ctx, m) if err != nil { return nil, err - } else if !ignoreRCodeError && (m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused) { + } else if cache && (m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused) { + // currently, cache indicates whether this msg was from a RCode client, + // so we would ignore RCode errors from RCode clients. return nil, errors.New("server failure") } log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), client.Address()) @@ -311,7 +314,7 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M if fErr := fast.Error(); fErr != nil { err = fmt.Errorf("%w, first error: %s", err, fErr.Error()) } - return nil, err + return nil, true, err } msg = elm return From 5e20fedf5f1ecffe5784d8c4141aab3a8dbfd8b3 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 11 Jun 2023 23:57:25 +0800 Subject: [PATCH 26/79] chore: Update dependencies --- go.mod | 10 +++++----- go.sum | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 12155a5b..7e67d5bb 100644 --- a/go.mod +++ b/go.mod @@ -23,8 +23,8 @@ require ( github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca - github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e - github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a + github.com/metacubex/sing-tun v0.1.5-0.20230611154506-9fe2c0dc331d + github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 github.com/miekg/dns v1.1.54 github.com/mroth/weightedrand/v2 v2.0.1 github.com/openacid/low v0.1.21 @@ -69,7 +69,7 @@ require ( github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/golang/mock v1.6.0 // indirect - github.com/google/btree v1.0.1 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect @@ -77,7 +77,7 @@ require ( github.com/klauspost/compress v1.15.15 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mdlayher/socket v0.4.1 // indirect - github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c // indirect + github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect @@ -102,7 +102,7 @@ require ( gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect + golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect ) diff --git a/go.sum b/go.sum index 8e868b55..f503e205 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,8 @@ github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+Licev github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= @@ -91,8 +91,8 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= -github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM= -github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= +github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= +github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb h1:92YTNmYXCSycERjKn/zPbeK5DiW3dd80j3+oVTEWTE8= github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb/go.mod h1:6pg8+Tje9KOltnj1whuvB2i5KFUMPp1TAF3oPhc5axM= github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b h1:Bw4j3ktf5vivi5qm/ZQGtyRAgybRKSGJaMV1t3rtC+I= @@ -101,12 +101,12 @@ github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c h1:Lp github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca h1:10qc50Q1hHrfGO4NjEJpIAgHX63Y256tHE0dFCTN8J4= 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-tun v0.1.5-0.20230611154506-9fe2c0dc331d h1:S4Oms2FG+IGhvup1LvgOCk0mW5i0Gn/VZ7JOXoXhTjg= +github.com/metacubex/sing-tun v0.1.5-0.20230611154506-9fe2c0dc331d/go.mod h1:6U1GUU8C2WzS9B2185K3wIE20gBF6gRmdpydqTesr18= 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/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= +github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mroth/weightedrand/v2 v2.0.1 h1:zrEVDIaau/E4QLOKu02kpg8T8myweFlMGikIgbIdrRA= @@ -253,8 +253,8 @@ 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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= From e914317bef65deefc074164ee8d5ab9049bdb178 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 12 Jun 2023 17:44:22 +0800 Subject: [PATCH 27/79] feat: support tuicV5 --- adapter/outbound/tuic.go | 64 ++- config/config.go | 23 +- docs/config.yaml | 16 +- hub/route/configs.go | 24 +- listener/config/tuic.go | 23 +- listener/inbound/tuic.go | 18 +- listener/tuic/server.go | 99 +++- transport/tuic/common/congestion.go | 44 ++ transport/tuic/common/stream.go | 67 +++ transport/tuic/common/type.go | 34 ++ transport/tuic/pool_client.go | 68 ++- transport/tuic/tuic.go | 47 ++ transport/tuic/{ => v4}/client.go | 74 +-- transport/tuic/{conn.go => v4/packet.go} | 94 +--- transport/tuic/{ => v4}/protocol.go | 2 +- transport/tuic/{ => v4}/server.go | 29 +- transport/tuic/v5/client.go | 386 ++++++++++++++ transport/tuic/v5/frag.go | 80 +++ transport/tuic/v5/packet.go | 208 ++++++++ transport/tuic/v5/protocol.go | 651 +++++++++++++++++++++++ transport/tuic/v5/server.go | 303 +++++++++++ 21 files changed, 2103 insertions(+), 251 deletions(-) create mode 100644 transport/tuic/common/congestion.go create mode 100644 transport/tuic/common/stream.go create mode 100644 transport/tuic/common/type.go create mode 100644 transport/tuic/tuic.go rename transport/tuic/{ => v4}/client.go (85%) rename transport/tuic/{conn.go => v4/packet.go} (60%) rename transport/tuic/{ => v4}/protocol.go (99%) rename transport/tuic/{ => v4}/server.go (91%) create mode 100644 transport/tuic/v5/client.go create mode 100644 transport/tuic/v5/frag.go create mode 100644 transport/tuic/v5/packet.go create mode 100644 transport/tuic/v5/protocol.go create mode 100644 transport/tuic/v5/server.go diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index ab371757..e2aafca5 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -13,13 +13,14 @@ import ( "strconv" "time" - "github.com/metacubex/quic-go" - "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/tuic" + + "github.com/gofrs/uuid/v5" + "github.com/metacubex/quic-go" ) type Tuic struct { @@ -33,7 +34,9 @@ type TuicOption struct { Name string `proxy:"name"` Server string `proxy:"server"` Port int `proxy:"port"` - Token string `proxy:"token"` + Token string `proxy:"token,omitempty"` + UUID string `proxy:"uuid,omitempty"` + Password string `proxy:"password,omitempty"` Ip string `proxy:"ip,omitempty"` HeartbeatInterval int `proxy:"heartbeat-interval,omitempty"` ALPN []string `proxy:"alpn,omitempty"` @@ -184,14 +187,19 @@ func NewTuic(option TuicOption) (*Tuic, error) { option.MaxOpenStreams = 100 } + packetOverHead := tuic.PacketOverHeadV4 + if len(option.Token) == 0 { + packetOverHead = tuic.PacketOverHeadV5 + } + if option.MaxDatagramFrameSize == 0 { - option.MaxDatagramFrameSize = option.MaxUdpRelayPacketSize + tuic.PacketOverHead + option.MaxDatagramFrameSize = option.MaxUdpRelayPacketSize + packetOverHead } if option.MaxDatagramFrameSize > 1400 { option.MaxDatagramFrameSize = 1400 } - option.MaxUdpRelayPacketSize = option.MaxDatagramFrameSize - tuic.PacketOverHead + option.MaxUdpRelayPacketSize = option.MaxDatagramFrameSize - packetOverHead // ensure server's incoming stream can handle correctly, increase to 1.1x quicMaxOpenStreams := int64(option.MaxOpenStreams) @@ -222,8 +230,8 @@ func NewTuic(option TuicOption) (*Tuic, error) { } if option.DisableSni { tlsConfig.ServerName = "" + tlsConfig.InsecureSkipVerify = true // tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config } - tkn := tuic.GenTKN(option.Token) t := &Tuic{ Base: &Base{ @@ -249,20 +257,38 @@ func NewTuic(option TuicOption) (*Tuic, error) { if clientMaxOpenStreams < 1 { clientMaxOpenStreams = 1 } - clientOption := &tuic.ClientOption{ - TlsConfig: tlsConfig, - QuicConfig: quicConfig, - Token: tkn, - UdpRelayMode: option.UdpRelayMode, - CongestionController: option.CongestionController, - ReduceRtt: option.ReduceRtt, - RequestTimeout: time.Duration(option.RequestTimeout) * time.Millisecond, - MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, - FastOpen: option.FastOpen, - MaxOpenStreams: clientMaxOpenStreams, - } - t.client = tuic.NewPoolClient(clientOption) + if len(option.Token) > 0 { + tkn := tuic.GenTKN(option.Token) + clientOption := &tuic.ClientOptionV4{ + TlsConfig: tlsConfig, + QuicConfig: quicConfig, + Token: tkn, + UdpRelayMode: option.UdpRelayMode, + CongestionController: option.CongestionController, + ReduceRtt: option.ReduceRtt, + RequestTimeout: time.Duration(option.RequestTimeout) * time.Millisecond, + MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, + FastOpen: option.FastOpen, + MaxOpenStreams: clientMaxOpenStreams, + } + + t.client = tuic.NewPoolClientV4(clientOption) + } else { + clientOption := &tuic.ClientOptionV5{ + TlsConfig: tlsConfig, + QuicConfig: quicConfig, + Uuid: uuid.FromStringOrNil(option.UUID), + Password: option.Password, + UdpRelayMode: option.UdpRelayMode, + CongestionController: option.CongestionController, + ReduceRtt: option.ReduceRtt, + MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, + MaxOpenStreams: clientMaxOpenStreams, + } + + t.client = tuic.NewPoolClientV5(clientOption) + } return t, nil } diff --git a/config/config.go b/config/config.go index 0a263a08..0e161ddd 100644 --- a/config/config.go +++ b/config/config.go @@ -219,16 +219,17 @@ type RawTun struct { } type RawTuicServer struct { - Enable bool `yaml:"enable" json:"enable"` - Listen string `yaml:"listen" json:"listen"` - Token []string `yaml:"token" json:"token"` - Certificate string `yaml:"certificate" json:"certificate"` - PrivateKey string `yaml:"private-key" json:"private-key"` - CongestionController string `yaml:"congestion-controller" json:"congestion-controller,omitempty"` - MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"` - AuthenticationTimeout int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"` - ALPN []string `yaml:"alpn" json:"alpn,omitempty"` - MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` + Enable bool `yaml:"enable" json:"enable"` + Listen string `yaml:"listen" json:"listen"` + Token []string `yaml:"token" json:"token"` + Users map[string]string `yaml:"users" json:"users,omitempty"` + Certificate string `yaml:"certificate" json:"certificate"` + PrivateKey string `yaml:"private-key" json:"private-key"` + CongestionController string `yaml:"congestion-controller" json:"congestion-controller,omitempty"` + MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"` + AuthenticationTimeout int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"` + ALPN []string `yaml:"alpn" json:"alpn,omitempty"` + MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` } type RawConfig struct { @@ -355,6 +356,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { TuicServer: RawTuicServer{ Enable: false, Token: nil, + Users: nil, Certificate: "", PrivateKey: "", Listen: "", @@ -1294,6 +1296,7 @@ func parseTuicServer(rawTuic RawTuicServer, general *General) error { Enable: rawTuic.Enable, Listen: rawTuic.Listen, Token: rawTuic.Token, + Users: rawTuic.Users, Certificate: rawTuic.Certificate, PrivateKey: rawTuic.PrivateKey, CongestionController: rawTuic.CongestionController, diff --git a/docs/config.yaml b/docs/config.yaml index 311cf50f..a8207917 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -661,7 +661,11 @@ proxies: # socks5 server: www.example.com port: 10443 type: tuic + # tuicV4必须填写token (不可同时填写uuid和password) token: TOKEN + # tuicV5必须填写uuid和password(不可同时填写token) + uuid: 00000000-0000-0000-0000-000000000001 + password: PASSWORD_1 # ip: 127.0.0.1 # for overwriting the DNS lookup result of the server address set in option 'server' # heartbeat-interval: 10000 # alpn: [h3] @@ -899,8 +903,11 @@ listeners: listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - # token: - # - TOKEN + # token: # tuicV4填写(不可同时填写users) + # - TOKEN + # users: # tuicV5填写(不可同时填写token) + # 00000000-0000-0000-0000-000000000000: PASSWORD_0 + # 00000000-0000-0000-0000-000000000001: PASSWORD_1 # certificate: ./server.crt # private-key: ./server.key # congestion-controller: bbr @@ -970,8 +977,11 @@ listeners: # tuic-server: # enable: true # listen: 127.0.0.1:10443 -# token: +# token: # tuicV4填写(不可同时填写users) # - TOKEN +# users: # tuicV5填写(不可同时填写token) +# 00000000-0000-0000-0000-000000000000: PASSWORD_0 +# 00000000-0000-0000-0000-000000000001: PASSWORD_1 # certificate: ./server.crt # private-key: ./server.key # congestion-controller: bbr diff --git a/hub/route/configs.go b/hub/route/configs.go index afafe80e..a8c24f90 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -84,16 +84,17 @@ type tunSchema struct { } type tuicServerSchema struct { - Enable bool `yaml:"enable" json:"enable"` - Listen *string `yaml:"listen" json:"listen"` - Token *[]string `yaml:"token" json:"token"` - Certificate *string `yaml:"certificate" json:"certificate"` - PrivateKey *string `yaml:"private-key" json:"private-key"` - CongestionController *string `yaml:"congestion-controller" json:"congestion-controller,omitempty"` - MaxIdleTime *int `yaml:"max-idle-time" json:"max-idle-time,omitempty"` - AuthenticationTimeout *int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"` - ALPN *[]string `yaml:"alpn" json:"alpn,omitempty"` - MaxUdpRelayPacketSize *int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` + Enable bool `yaml:"enable" json:"enable"` + Listen *string `yaml:"listen" json:"listen"` + Token *[]string `yaml:"token" json:"token"` + Users *map[string]string `yaml:"users" json:"users,omitempty"` + Certificate *string `yaml:"certificate" json:"certificate"` + PrivateKey *string `yaml:"private-key" json:"private-key"` + CongestionController *string `yaml:"congestion-controller" json:"congestion-controller,omitempty"` + MaxIdleTime *int `yaml:"max-idle-time" json:"max-idle-time,omitempty"` + AuthenticationTimeout *int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"` + ALPN *[]string `yaml:"alpn" json:"alpn,omitempty"` + MaxUdpRelayPacketSize *int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` } func getConfigs(w http.ResponseWriter, r *http.Request) { @@ -186,6 +187,9 @@ func pointerOrDefaultTuicServer(p *tuicServerSchema, def LC.TuicServer) LC.TuicS if p.Token != nil { def.Token = *p.Token } + if p.Users != nil { + def.Users = *p.Users + } if p.Certificate != nil { def.Certificate = *p.Certificate } diff --git a/listener/config/tuic.go b/listener/config/tuic.go index 991a04c9..30c99054 100644 --- a/listener/config/tuic.go +++ b/listener/config/tuic.go @@ -5,17 +5,18 @@ import ( ) type TuicServer struct { - Enable bool `yaml:"enable" json:"enable"` - Listen string `yaml:"listen" json:"listen"` - Token []string `yaml:"token" json:"token"` - Certificate string `yaml:"certificate" json:"certificate"` - PrivateKey string `yaml:"private-key" json:"private-key"` - CongestionController string `yaml:"congestion-controller" json:"congestion-controller,omitempty"` - MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"` - AuthenticationTimeout int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"` - ALPN []string `yaml:"alpn" json:"alpn,omitempty"` - MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` - MaxDatagramFrameSize int `yaml:"max-datagram-frame-size" json:"max-datagram-frame-size,omitempty"` + Enable bool `yaml:"enable" json:"enable"` + Listen string `yaml:"listen" json:"listen"` + Token []string `yaml:"token" json:"token,omitempty"` + Users map[string]string `yaml:"users" json:"users,omitempty"` + Certificate string `yaml:"certificate" json:"certificate"` + PrivateKey string `yaml:"private-key" json:"private-key"` + CongestionController string `yaml:"congestion-controller" json:"congestion-controller,omitempty"` + MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"` + AuthenticationTimeout int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"` + ALPN []string `yaml:"alpn" json:"alpn,omitempty"` + MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` + MaxDatagramFrameSize int `yaml:"max-datagram-frame-size" json:"max-datagram-frame-size,omitempty"` } func (t TuicServer) String() string { diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index f6641500..2e234e2d 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -9,14 +9,15 @@ import ( type TuicOption struct { BaseOption - Token []string `inbound:"token"` - Certificate string `inbound:"certificate"` - PrivateKey string `inbound:"private-key"` - CongestionController string `inbound:"congestion-controller,omitempty"` - MaxIdleTime int `inbound:"max-idle-time,omitempty"` - AuthenticationTimeout int `inbound:"authentication-timeout,omitempty"` - ALPN []string `inbound:"alpn,omitempty"` - MaxUdpRelayPacketSize int `inbound:"max-udp-relay-packet-size,omitempty"` + Token []string `inbound:"token,omitempty"` + Users map[string]string `inbound:"users,omitempty"` + Certificate string `inbound:"certificate"` + PrivateKey string `inbound:"private-key"` + CongestionController string `inbound:"congestion-controller,omitempty"` + MaxIdleTime int `inbound:"max-idle-time,omitempty"` + AuthenticationTimeout int `inbound:"authentication-timeout,omitempty"` + ALPN []string `inbound:"alpn,omitempty"` + MaxUdpRelayPacketSize int `inbound:"max-udp-relay-packet-size,omitempty"` } func (o TuicOption) Equal(config C.InboundConfig) bool { @@ -42,6 +43,7 @@ func NewTuic(options *TuicOption) (*Tuic, error) { Enable: true, Listen: base.RawAddress(), Token: options.Token, + Users: options.Users, Certificate: options.Certificate, PrivateKey: options.PrivateKey, CongestionController: options.CongestionController, diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 498708bf..e1d8175c 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -6,8 +6,6 @@ import ( "strings" "time" - "github.com/metacubex/quic-go" - "github.com/Dreamacro/clash/adapter/inbound" CN "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/sockopt" @@ -16,6 +14,10 @@ import ( "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/tuic" + + "github.com/gofrs/uuid/v5" + "github.com/metacubex/quic-go" + "golang.org/x/exp/slices" ) const ServerMaxIncomingStreams = (1 << 32) - 1 @@ -24,7 +26,7 @@ type Listener struct { closed bool config LC.TuicServer udpListeners []net.PacketConn - servers []*tuic.Server + servers []tuic.Server } func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (*Listener, error) { @@ -59,39 +61,77 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet quicConfig.InitialConnectionReceiveWindow = tuic.DefaultConnectionReceiveWindow / 10 quicConfig.MaxConnectionReceiveWindow = tuic.DefaultConnectionReceiveWindow + packetOverHead := tuic.PacketOverHeadV4 + if len(config.Token) == 0 { + packetOverHead = tuic.PacketOverHeadV5 + } + if config.MaxUdpRelayPacketSize == 0 { config.MaxUdpRelayPacketSize = 1500 } - maxDatagramFrameSize := config.MaxUdpRelayPacketSize + tuic.PacketOverHead + maxDatagramFrameSize := config.MaxUdpRelayPacketSize + packetOverHead if maxDatagramFrameSize > 1400 { maxDatagramFrameSize = 1400 } - config.MaxUdpRelayPacketSize = maxDatagramFrameSize - tuic.PacketOverHead + config.MaxUdpRelayPacketSize = maxDatagramFrameSize - packetOverHead quicConfig.MaxDatagramFrameSize = int64(maxDatagramFrameSize) - tokens := make([][32]byte, len(config.Token)) - for i, token := range config.Token { - tokens[i] = tuic.GenTKN(token) + handleTcpFn := func(conn net.Conn, addr socks5.Addr, _additions ...inbound.Addition) error { + newAdditions := additions + if len(_additions) > 0 { + newAdditions = slices.Clone(additions) + newAdditions = append(newAdditions, _additions...) + } + tcpIn <- inbound.NewSocket(addr, conn, C.TUIC, newAdditions...) + return nil + } + handleUdpFn := func(addr socks5.Addr, packet C.UDPPacket, _additions ...inbound.Addition) error { + newAdditions := additions + if len(_additions) > 0 { + newAdditions = slices.Clone(additions) + newAdditions = append(newAdditions, _additions...) + } + select { + case udpIn <- inbound.NewPacket(addr, packet, C.TUIC, newAdditions...): + default: + } + return nil } - option := &tuic.ServerOption{ - HandleTcpFn: func(conn net.Conn, addr socks5.Addr) error { - tcpIn <- inbound.NewSocket(addr, conn, C.TUIC, additions...) - return nil - }, - HandleUdpFn: func(addr socks5.Addr, packet C.UDPPacket) error { - select { - case udpIn <- inbound.NewPacket(addr, packet, C.TUIC, additions...): - default: - } - return nil - }, - TlsConfig: tlsConfig, - QuicConfig: quicConfig, - Tokens: tokens, - CongestionController: config.CongestionController, - AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond, - MaxUdpRelayPacketSize: config.MaxUdpRelayPacketSize, + var optionV4 *tuic.ServerOptionV4 + var optionV5 *tuic.ServerOptionV5 + if len(config.Token) > 0 { + tokens := make([][32]byte, len(config.Token)) + for i, token := range config.Token { + tokens[i] = tuic.GenTKN(token) + } + + optionV4 = &tuic.ServerOptionV4{ + HandleTcpFn: handleTcpFn, + HandleUdpFn: handleUdpFn, + TlsConfig: tlsConfig, + QuicConfig: quicConfig, + Tokens: tokens, + CongestionController: config.CongestionController, + AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond, + MaxUdpRelayPacketSize: config.MaxUdpRelayPacketSize, + } + } else { + users := make(map[[16]byte]string) + for _uuid, password := range config.Users { + users[uuid.FromStringOrNil(_uuid)] = password + } + + optionV5 = &tuic.ServerOptionV5{ + HandleTcpFn: handleTcpFn, + HandleUdpFn: handleUdpFn, + TlsConfig: tlsConfig, + QuicConfig: quicConfig, + Users: users, + CongestionController: config.CongestionController, + AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond, + MaxUdpRelayPacketSize: config.MaxUdpRelayPacketSize, + } } sl := &Listener{false, config, nil, nil} @@ -111,7 +151,12 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet sl.udpListeners = append(sl.udpListeners, ul) - server, err := tuic.NewServer(option, ul) + var server tuic.Server + if optionV4 != nil { + server, err = tuic.NewServerV4(optionV4, ul) + } else { + server, err = tuic.NewServerV5(optionV5, ul) + } if err != nil { return nil, err } diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go new file mode 100644 index 00000000..e2f7d867 --- /dev/null +++ b/transport/tuic/common/congestion.go @@ -0,0 +1,44 @@ +package common + +import ( + "github.com/Dreamacro/clash/transport/tuic/congestion" + + "github.com/metacubex/quic-go" +) + +const ( + DefaultStreamReceiveWindow = 15728640 // 15 MB/s + DefaultConnectionReceiveWindow = 67108864 // 64 MB/s +) + +func SetCongestionController(quicConn quic.Connection, cc string) { + switch cc { + case "cubic": + quicConn.SetCongestionControl( + congestion.NewCubicSender( + congestion.DefaultClock{}, + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), + false, + nil, + ), + ) + case "new_reno": + quicConn.SetCongestionControl( + congestion.NewCubicSender( + congestion.DefaultClock{}, + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), + true, + nil, + ), + ) + case "bbr": + quicConn.SetCongestionControl( + congestion.NewBBRSender( + congestion.DefaultClock{}, + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), + congestion.InitialCongestionWindow*congestion.InitialMaxDatagramSize, + congestion.DefaultBBRMaxCongestionWindow*congestion.InitialMaxDatagramSize, + ), + ) + } +} diff --git a/transport/tuic/common/stream.go b/transport/tuic/common/stream.go new file mode 100644 index 00000000..e65f9a49 --- /dev/null +++ b/transport/tuic/common/stream.go @@ -0,0 +1,67 @@ +package common + +import ( + "net" + "sync" + "time" + + "github.com/metacubex/quic-go" +) + +type quicStreamConn struct { + quic.Stream + lock sync.Mutex + lAddr net.Addr + rAddr net.Addr + + closeDeferFn func() + + closeOnce sync.Once + closeErr error +} + +func (q *quicStreamConn) Write(p []byte) (n int, err error) { + q.lock.Lock() + defer q.lock.Unlock() + return q.Stream.Write(p) +} + +func (q *quicStreamConn) Close() error { + q.closeOnce.Do(func() { + q.closeErr = q.close() + }) + return q.closeErr +} + +func (q *quicStreamConn) close() error { + if q.closeDeferFn != nil { + defer q.closeDeferFn() + } + + // https://github.com/cloudflare/cloudflared/commit/ed2bac026db46b239699ac5ce4fcf122d7cab2cd + // Make sure a possible writer does not block the lock forever. We need it, so we can close the writer + // side of the stream safely. + _ = q.Stream.SetWriteDeadline(time.Now()) + + // This lock is eventually acquired despite Write also acquiring it, because we set a deadline to writes. + q.lock.Lock() + defer q.lock.Unlock() + + // We have to clean up the receiving stream ourselves since the Close in the bottom does not handle that. + q.Stream.CancelRead(0) + return q.Stream.Close() +} + +func (q *quicStreamConn) LocalAddr() net.Addr { + return q.lAddr +} + +func (q *quicStreamConn) RemoteAddr() net.Addr { + return q.rAddr +} + +var _ net.Conn = (*quicStreamConn)(nil) + +func NewQuicStreamConn(stream quic.Stream, lAddr, rAddr net.Addr, closeDeferFn func()) net.Conn { + return &quicStreamConn{Stream: stream, lAddr: lAddr, rAddr: rAddr, closeDeferFn: closeDeferFn} +} diff --git a/transport/tuic/common/type.go b/transport/tuic/common/type.go new file mode 100644 index 00000000..16c6f49e --- /dev/null +++ b/transport/tuic/common/type.go @@ -0,0 +1,34 @@ +package common + +import ( + "context" + "errors" + "net" + "time" + + C "github.com/Dreamacro/clash/constant" + + "github.com/metacubex/quic-go" +) + +var ( + ClientClosed = errors.New("tuic: client closed") + TooManyOpenStreams = errors.New("tuic: too many open streams") +) + +type DialFunc func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) + +type Client interface { + DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.Conn, error) + ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) + OpenStreams() int64 + DialerRef() C.Dialer + LastVisited() time.Time + SetLastVisited(last time.Time) + Close() +} + +type Server interface { + Serve() error + Close() error +} diff --git a/transport/tuic/pool_client.go b/transport/tuic/pool_client.go index 223436cd..4a779706 100644 --- a/transport/tuic/pool_client.go +++ b/transport/tuic/pool_client.go @@ -23,15 +23,14 @@ type dialResult struct { } type PoolClient struct { - *ClientOption - - newClientOption *ClientOption - dialResultMap map[C.Dialer]dialResult - dialResultMutex *sync.Mutex - tcpClients *list.List[*Client] - tcpClientsMutex *sync.Mutex - udpClients *list.List[*Client] - udpClientsMutex *sync.Mutex + newClientOptionV4 *ClientOptionV4 + newClientOptionV5 *ClientOptionV5 + dialResultMap map[C.Dialer]dialResult + dialResultMutex *sync.Mutex + tcpClients *list.List[Client] + tcpClientsMutex *sync.Mutex + udpClients *list.List[Client] + udpClientsMutex *sync.Mutex } func (t *PoolClient) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.Conn, error) { @@ -99,7 +98,7 @@ func (t *PoolClient) forceClose() { } } -func (t *PoolClient) newClient(udp bool, dialer C.Dialer) *Client { +func (t *PoolClient) newClient(udp bool, dialer C.Dialer) (client Client) { clients := t.tcpClients clientsMutex := t.tcpClientsMutex if udp { @@ -110,22 +109,26 @@ func (t *PoolClient) newClient(udp bool, dialer C.Dialer) *Client { clientsMutex.Lock() defer clientsMutex.Unlock() - client := NewClient(t.newClientOption, udp) - client.dialerRef = dialer - client.lastVisited = time.Now() + if t.newClientOptionV4 != nil { + client = NewClientV4(t.newClientOptionV4, udp, dialer) + } else { + client = NewClientV5(t.newClientOptionV5, udp, dialer) + } + + client.SetLastVisited(time.Now()) clients.PushFront(client) return client } -func (t *PoolClient) getClient(udp bool, dialer C.Dialer) *Client { +func (t *PoolClient) getClient(udp bool, dialer C.Dialer) Client { clients := t.tcpClients clientsMutex := t.tcpClientsMutex if udp { clients = t.udpClients clientsMutex = t.udpClientsMutex } - var bestClient *Client + var bestClient Client func() { clientsMutex.Lock() @@ -138,11 +141,11 @@ func (t *PoolClient) getClient(udp bool, dialer C.Dialer) *Client { it = next continue } - if client.dialerRef == dialer { + if client.DialerRef() == dialer { if bestClient == nil { bestClient = client } else { - if client.openStreams.Load() < bestClient.openStreams.Load() { + if client.OpenStreams() < bestClient.OpenStreams() { bestClient = client } } @@ -152,7 +155,7 @@ func (t *PoolClient) getClient(udp bool, dialer C.Dialer) *Client { }() for it := clients.Front(); it != nil; { client := it.Value - if client != bestClient && client.openStreams.Load() == 0 && time.Now().Sub(client.lastVisited) > 30*time.Minute { + if client != bestClient && client.OpenStreams() == 0 && time.Now().Sub(client.LastVisited()) > 30*time.Minute { client.Close() next := it.Next() clients.Remove(it) @@ -165,25 +168,40 @@ func (t *PoolClient) getClient(udp bool, dialer C.Dialer) *Client { if bestClient == nil { return t.newClient(udp, dialer) } else { - bestClient.lastVisited = time.Now() + bestClient.SetLastVisited(time.Now()) return bestClient } } -func NewPoolClient(clientOption *ClientOption) *PoolClient { +func NewPoolClientV4(clientOption *ClientOptionV4) *PoolClient { p := &PoolClient{ - ClientOption: clientOption, dialResultMap: make(map[C.Dialer]dialResult), dialResultMutex: &sync.Mutex{}, - tcpClients: list.New[*Client](), + tcpClients: list.New[Client](), tcpClientsMutex: &sync.Mutex{}, - udpClients: list.New[*Client](), + udpClients: list.New[Client](), udpClientsMutex: &sync.Mutex{}, } newClientOption := *clientOption - p.newClientOption = &newClientOption + p.newClientOptionV4 = &newClientOption runtime.SetFinalizer(p, closeClientPool) - log.Debugln("New Tuic PoolClient at %p", p) + log.Debugln("New TuicV4 PoolClient at %p", p) + return p +} + +func NewPoolClientV5(clientOption *ClientOptionV5) *PoolClient { + p := &PoolClient{ + dialResultMap: make(map[C.Dialer]dialResult), + dialResultMutex: &sync.Mutex{}, + tcpClients: list.New[Client](), + tcpClientsMutex: &sync.Mutex{}, + udpClients: list.New[Client](), + udpClientsMutex: &sync.Mutex{}, + } + newClientOption := *clientOption + p.newClientOptionV5 = &newClientOption + runtime.SetFinalizer(p, closeClientPool) + log.Debugln("New TuicV5 PoolClient at %p", p) return p } diff --git a/transport/tuic/tuic.go b/transport/tuic/tuic.go new file mode 100644 index 00000000..279cec95 --- /dev/null +++ b/transport/tuic/tuic.go @@ -0,0 +1,47 @@ +package tuic + +import ( + "net" + + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/transport/tuic/common" + v4 "github.com/Dreamacro/clash/transport/tuic/v4" + v5 "github.com/Dreamacro/clash/transport/tuic/v5" +) + +type ClientOptionV4 = v4.ClientOption +type ClientOptionV5 = v5.ClientOption + +type Client = common.Client + +func NewClientV4(clientOption *ClientOptionV4, udp bool, dialerRef C.Dialer) Client { + return v4.NewClient(clientOption, udp, dialerRef) +} + +func NewClientV5(clientOption *ClientOptionV5, udp bool, dialerRef C.Dialer) Client { + return v5.NewClient(clientOption, udp, dialerRef) +} + +type DialFunc = common.DialFunc + +var TooManyOpenStreams = common.TooManyOpenStreams + +type ServerOptionV4 = v4.ServerOption +type ServerOptionV5 = v5.ServerOption + +type Server = common.Server + +func NewServerV4(option *ServerOptionV4, pc net.PacketConn) (Server, error) { + return v4.NewServer(option, pc) +} + +func NewServerV5(option *ServerOptionV5, pc net.PacketConn) (Server, error) { + return v5.NewServer(option, pc) +} + +const DefaultStreamReceiveWindow = common.DefaultStreamReceiveWindow +const DefaultConnectionReceiveWindow = common.DefaultConnectionReceiveWindow + +var GenTKN = v4.GenTKN +var PacketOverHeadV4 = v4.PacketOverHead +var PacketOverHeadV5 = v5.PacketOverHead diff --git a/transport/tuic/client.go b/transport/tuic/v4/client.go similarity index 85% rename from transport/tuic/client.go rename to transport/tuic/v4/client.go index 6fd2a241..ae0cf473 100644 --- a/transport/tuic/client.go +++ b/transport/tuic/v4/client.go @@ -1,4 +1,4 @@ -package tuic +package v4 import ( "bufio" @@ -13,23 +13,18 @@ import ( "time" "unsafe" + atomic2 "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" + "github.com/Dreamacro/clash/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/zhangyunhao116/fastrand" ) -var ( - ClientClosed = errors.New("tuic: client closed") - TooManyOpenStreams = errors.New("tuic: too many open streams") -) - -type DialFunc func(ctx context.Context, dialer C.Dialer) (transport *quic.Transport, addr net.Addr, err error) - type ClientOption struct { TlsConfig *tls.Config QuicConfig *quic.Config @@ -57,10 +52,26 @@ type clientImpl struct { // only ready for PoolClient dialerRef C.Dialer - lastVisited time.Time + lastVisited atomic2.TypedValue[time.Time] } -func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn DialFunc) (quic.Connection, error) { +func (t *clientImpl) OpenStreams() int64 { + return t.openStreams.Load() +} + +func (t *clientImpl) DialerRef() C.Dialer { + return t.dialerRef +} + +func (t *clientImpl) LastVisited() time.Time { + return t.lastVisited.Load() +} + +func (t *clientImpl) SetLastVisited(last time.Time) { + t.lastVisited.Store(last) +} + +func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn common.DialFunc) (quic.Connection, error) { t.connMutex.Lock() defer t.connMutex.Unlock() if t.quicConn != nil { @@ -80,7 +91,7 @@ func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn Di return nil, err } - SetCongestionController(quicConn, t.CongestionController) + common.SetCongestionController(quicConn, t.CongestionController) go func() { _ = t.sendAuthentication(quicConn) @@ -237,11 +248,11 @@ func (t *clientImpl) forceClose(quicConn quic.Connection, err error) { func (t *clientImpl) Close() { t.closed.Store(true) if t.openStreams.Load() == 0 { - t.forceClose(nil, ClientClosed) + t.forceClose(nil, common.ClientClosed) } } -func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.Conn, error) { +func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) { quicConn, err := t.getQuicConn(ctx, dialer, dialFn) if err != nil { return nil, err @@ -249,9 +260,9 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta openStreams := t.openStreams.Add(1) if openStreams >= t.MaxOpenStreams { t.openStreams.Add(-1) - return nil, TooManyOpenStreams + return nil, common.TooManyOpenStreams } - stream, err := func() (stream *quicStreamConn, err error) { + stream, err := func() (stream net.Conn, err error) { defer func() { t.deferQuicConn(quicConn, err) }() @@ -265,19 +276,19 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta if err != nil { return nil, err } - stream = &quicStreamConn{ - Stream: quicStream, - lAddr: quicConn.LocalAddr(), - rAddr: quicConn.RemoteAddr(), - closeDeferFn: func() { + stream = common.NewQuicStreamConn( + quicStream, + quicConn.LocalAddr(), + quicConn.RemoteAddr(), + func() { time.AfterFunc(C.DefaultTCPTimeout, func() { openStreams := t.openStreams.Add(-1) if openStreams == 0 && t.closed.Load() { - t.forceClose(quicConn, ClientClosed) + t.forceClose(quicConn, common.ClientClosed) } }) }, - } + ) _, err = buf.WriteTo(stream) if err != nil { _ = stream.Close() @@ -361,7 +372,7 @@ func (conn *earlyConn) WriterReplaceable() bool { return true } -func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) { +func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) { quicConn, err := t.getQuicConn(ctx, dialer, dialFn) if err != nil { return nil, err @@ -369,7 +380,7 @@ func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Met openStreams := t.openStreams.Add(1) if openStreams >= t.MaxOpenStreams { t.openStreams.Add(-1) - return nil, TooManyOpenStreams + return nil, common.TooManyOpenStreams } pipe1, pipe2 := net.Pipe() @@ -393,7 +404,7 @@ func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Met time.AfterFunc(C.DefaultUDPTimeout, func() { openStreams := t.openStreams.Add(-1) if openStreams == 0 && t.closed.Load() { - t.forceClose(quicConn, ClientClosed) + t.forceClose(quicConn, common.ClientClosed) } }) }, @@ -405,7 +416,7 @@ type Client struct { *clientImpl // use an independent pointer to let Finalizer can work no matter somewhere handle an influence in clientImpl inner } -func (t *Client) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.Conn, error) { +func (t *Client) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) { conn, err := t.clientImpl.DialContextWithDialer(ctx, metadata, dialer, dialFn) if err != nil { return nil, err @@ -413,7 +424,7 @@ func (t *Client) DialContextWithDialer(ctx context.Context, metadata *C.Metadata return N.NewRefConn(conn, t), err } -func (t *Client) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) { +func (t *Client) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) { pc, err := t.clientImpl.ListenPacketWithDialer(ctx, metadata, dialer, dialFn) if err != nil { return nil, err @@ -422,21 +433,22 @@ func (t *Client) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadat } func (t *Client) forceClose() { - t.clientImpl.forceClose(nil, ClientClosed) + t.clientImpl.forceClose(nil, common.ClientClosed) } -func NewClient(clientOption *ClientOption, udp bool) *Client { +func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client { ci := &clientImpl{ ClientOption: clientOption, udp: udp, + dialerRef: dialerRef, } c := &Client{ci} runtime.SetFinalizer(c, closeClient) - log.Debugln("New Tuic Client at %p", c) + log.Debugln("New TuicV4 Client at %p", c) return c } func closeClient(client *Client) { - log.Debugln("Close Tuic Client at %p", client) + log.Debugln("Close TuicV4 Client at %p", client) client.forceClose() } diff --git a/transport/tuic/conn.go b/transport/tuic/v4/packet.go similarity index 60% rename from transport/tuic/conn.go rename to transport/tuic/v4/packet.go index f226746d..edd872cc 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/v4/packet.go @@ -1,4 +1,4 @@ -package tuic +package v4 import ( "net" @@ -10,100 +10,8 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/tuic/congestion" ) -const ( - DefaultStreamReceiveWindow = 15728640 // 15 MB/s - DefaultConnectionReceiveWindow = 67108864 // 64 MB/s -) - -func SetCongestionController(quicConn quic.Connection, cc string) { - switch cc { - case "cubic": - quicConn.SetCongestionControl( - congestion.NewCubicSender( - congestion.DefaultClock{}, - congestion.GetInitialPacketSize(quicConn.RemoteAddr()), - false, - nil, - ), - ) - case "new_reno": - quicConn.SetCongestionControl( - congestion.NewCubicSender( - congestion.DefaultClock{}, - congestion.GetInitialPacketSize(quicConn.RemoteAddr()), - true, - nil, - ), - ) - case "bbr": - quicConn.SetCongestionControl( - congestion.NewBBRSender( - congestion.DefaultClock{}, - congestion.GetInitialPacketSize(quicConn.RemoteAddr()), - congestion.InitialCongestionWindow*congestion.InitialMaxDatagramSize, - congestion.DefaultBBRMaxCongestionWindow*congestion.InitialMaxDatagramSize, - ), - ) - } -} - -type quicStreamConn struct { - quic.Stream - lock sync.Mutex - lAddr net.Addr - rAddr net.Addr - - closeDeferFn func() - - closeOnce sync.Once - closeErr error -} - -func (q *quicStreamConn) Write(p []byte) (n int, err error) { - q.lock.Lock() - defer q.lock.Unlock() - return q.Stream.Write(p) -} - -func (q *quicStreamConn) Close() error { - q.closeOnce.Do(func() { - q.closeErr = q.close() - }) - return q.closeErr -} - -func (q *quicStreamConn) close() error { - if q.closeDeferFn != nil { - defer q.closeDeferFn() - } - - // https://github.com/cloudflare/cloudflared/commit/ed2bac026db46b239699ac5ce4fcf122d7cab2cd - // Make sure a possible writer does not block the lock forever. We need it, so we can close the writer - // side of the stream safely. - _ = q.Stream.SetWriteDeadline(time.Now()) - - // This lock is eventually acquired despite Write also acquiring it, because we set a deadline to writes. - q.lock.Lock() - defer q.lock.Unlock() - - // We have to clean up the receiving stream ourselves since the Close in the bottom does not handle that. - q.Stream.CancelRead(0) - return q.Stream.Close() -} - -func (q *quicStreamConn) LocalAddr() net.Addr { - return q.lAddr -} - -func (q *quicStreamConn) RemoteAddr() net.Addr { - return q.rAddr -} - -var _ net.Conn = (*quicStreamConn)(nil) - type quicStreamPacketConn struct { connId uint32 quicConn quic.Connection diff --git a/transport/tuic/protocol.go b/transport/tuic/v4/protocol.go similarity index 99% rename from transport/tuic/protocol.go rename to transport/tuic/v4/protocol.go index 472bb980..65f0f9d5 100644 --- a/transport/tuic/protocol.go +++ b/transport/tuic/v4/protocol.go @@ -1,4 +1,4 @@ -package tuic +package v4 import ( "encoding/binary" diff --git a/transport/tuic/server.go b/transport/tuic/v4/server.go similarity index 91% rename from transport/tuic/server.go rename to transport/tuic/v4/server.go index f8c4b20a..525ead17 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/v4/server.go @@ -1,4 +1,4 @@ -package tuic +package v4 import ( "bufio" @@ -11,19 +11,21 @@ import ( "sync/atomic" "time" + "github.com/Dreamacro/clash/adapter/inbound" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" + "github.com/Dreamacro/clash/transport/tuic/common" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" ) type ServerOption struct { - HandleTcpFn func(conn net.Conn, addr socks5.Addr) error - HandleUdpFn func(addr socks5.Addr, packet C.UDPPacket) error + HandleTcpFn func(conn net.Conn, addr socks5.Addr, additions ...inbound.Addition) error + HandleUdpFn func(addr socks5.Addr, packet C.UDPPacket, additions ...inbound.Addition) error TlsConfig *tls.Config QuicConfig *quic.Config @@ -55,7 +57,7 @@ func (s *Server) Serve() error { if err != nil { return err } - SetCongestionController(conn, s.CongestionController) + common.SetCongestionController(conn, s.CongestionController) h := &serverHandler{ Server: s, quicConn: conn, @@ -162,11 +164,12 @@ func (s *serverHandler) handleStream() (err error) { return err } go func() (err error) { - stream := &quicStreamConn{ - Stream: quicStream, - lAddr: s.quicConn.LocalAddr(), - rAddr: s.quicConn.RemoteAddr(), - } + stream := common.NewQuicStreamConn( + quicStream, + s.quicConn.LocalAddr(), + s.quicConn.RemoteAddr(), + nil, + ) conn := N.NewBufferedConn(stream) connect, err := ReadConnect(conn) if err != nil { @@ -224,18 +227,18 @@ func (s *serverHandler) handleUniStream() (err error) { if err != nil { return } - ok := false + authOk := false for _, tkn := range s.Tokens { if authenticate.TKN == tkn { - ok = true + authOk = true break } } s.authOnce.Do(func() { - if !ok { + if !authOk { _ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed") } - s.authOk = ok + s.authOk = authOk close(s.authCh) }) case PacketType: diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go new file mode 100644 index 00000000..9b878177 --- /dev/null +++ b/transport/tuic/v5/client.go @@ -0,0 +1,386 @@ +package v5 + +import ( + "bufio" + "bytes" + "context" + "crypto/tls" + "errors" + "net" + "runtime" + "sync" + "sync/atomic" + "time" + + atomic2 "github.com/Dreamacro/clash/common/atomic" + N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/pool" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" + "github.com/Dreamacro/clash/transport/tuic/common" + + "github.com/metacubex/quic-go" + "github.com/zhangyunhao116/fastrand" +) + +type ClientOption struct { + TlsConfig *tls.Config + QuicConfig *quic.Config + Uuid [16]byte + Password string + UdpRelayMode string + CongestionController string + ReduceRtt bool + MaxUdpRelayPacketSize int + MaxOpenStreams int64 +} + +type clientImpl struct { + *ClientOption + udp bool + + quicConn quic.Connection + connMutex sync.Mutex + + openStreams atomic.Int64 + closed atomic.Bool + + udpInputMap sync.Map + + // only ready for PoolClient + dialerRef C.Dialer + lastVisited atomic2.TypedValue[time.Time] +} + +func (t *clientImpl) OpenStreams() int64 { + return t.openStreams.Load() +} + +func (t *clientImpl) DialerRef() C.Dialer { + return t.dialerRef +} + +func (t *clientImpl) LastVisited() time.Time { + return t.lastVisited.Load() +} + +func (t *clientImpl) SetLastVisited(last time.Time) { + t.lastVisited.Store(last) +} + +func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn common.DialFunc) (quic.Connection, error) { + t.connMutex.Lock() + defer t.connMutex.Unlock() + if t.quicConn != nil { + return t.quicConn, nil + } + transport, addr, err := dialFn(ctx, dialer) + if err != nil { + return nil, err + } + var quicConn quic.Connection + if t.ReduceRtt { + quicConn, err = transport.DialEarly(ctx, addr, t.TlsConfig, t.QuicConfig) + } else { + quicConn, err = transport.Dial(ctx, addr, t.TlsConfig, t.QuicConfig) + } + if err != nil { + return nil, err + } + + common.SetCongestionController(quicConn, t.CongestionController) + + go func() { + _ = t.sendAuthentication(quicConn) + }() + + if t.udp { + go func() { + _ = t.parseUDP(quicConn) + }() + } + + t.quicConn = quicConn + t.openStreams.Store(0) + return quicConn, nil +} + +func (t *clientImpl) sendAuthentication(quicConn quic.Connection) (err error) { + defer func() { + t.deferQuicConn(quicConn, err) + }() + stream, err := quicConn.OpenUniStream() + if err != nil { + return err + } + buf := pool.GetBuffer() + defer pool.PutBuffer(buf) + token, err := GenToken(quicConn.ConnectionState(), t.Uuid, t.Password) + if err != nil { + return err + } + err = NewAuthenticate(t.Uuid, token).WriteTo(buf) + if err != nil { + return err + } + _, err = buf.WriteTo(stream) + if err != nil { + return err + } + err = stream.Close() + if err != nil { + return + } + return nil +} + +func (t *clientImpl) parseUDP(quicConn quic.Connection) (err error) { + defer func() { + t.deferQuicConn(quicConn, err) + }() + switch t.UdpRelayMode { + case "quic": + for { + var stream quic.ReceiveStream + stream, err = quicConn.AcceptUniStream(context.Background()) + if err != nil { + return err + } + go func() (err error) { + var assocId uint16 + defer func() { + t.deferQuicConn(quicConn, err) + if err != nil && assocId != 0 { + if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { + if conn, ok := val.(net.Conn); ok { + _ = conn.Close() + } + } + } + stream.CancelRead(0) + }() + reader := bufio.NewReader(stream) + packet, err := ReadPacket(reader) + if err != nil { + return + } + assocId = packet.ASSOC_ID + if val, ok := t.udpInputMap.Load(assocId); ok { + if conn, ok := val.(net.Conn); ok { + writer := bufio.NewWriterSize(conn, packet.BytesLen()) + _ = packet.WriteTo(writer) + _ = writer.Flush() + } + } + return + }() + } + default: // native + for { + var message []byte + message, err = quicConn.ReceiveMessage() + if err != nil { + return err + } + go func() (err error) { + var assocId uint16 + defer func() { + t.deferQuicConn(quicConn, err) + if err != nil && assocId != 0 { + if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { + if conn, ok := val.(net.Conn); ok { + _ = conn.Close() + } + } + } + }() + buffer := bytes.NewBuffer(message) + packet, err := ReadPacket(buffer) + if err != nil { + return + } + assocId = packet.ASSOC_ID + if val, ok := t.udpInputMap.Load(assocId); ok { + if conn, ok := val.(net.Conn); ok { + _, _ = conn.Write(message) + } + } + return + }() + } + } +} + +func (t *clientImpl) deferQuicConn(quicConn quic.Connection, err error) { + var netError net.Error + if err != nil && errors.As(err, &netError) { + t.forceClose(quicConn, err) + } +} + +func (t *clientImpl) forceClose(quicConn quic.Connection, err error) { + t.connMutex.Lock() + defer t.connMutex.Unlock() + if quicConn == nil { + quicConn = t.quicConn + } + if quicConn != nil { + if quicConn == t.quicConn { + t.quicConn = nil + } + } + errStr := "" + if err != nil { + errStr = err.Error() + } + if quicConn != nil { + _ = quicConn.CloseWithError(ProtocolError, errStr) + } + udpInputMap := &t.udpInputMap + udpInputMap.Range(func(key, value any) bool { + if conn, ok := value.(net.Conn); ok { + _ = conn.Close() + } + udpInputMap.Delete(key) + return true + }) +} + +func (t *clientImpl) Close() { + t.closed.Store(true) + if t.openStreams.Load() == 0 { + t.forceClose(nil, common.ClientClosed) + } +} + +func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) { + quicConn, err := t.getQuicConn(ctx, dialer, dialFn) + if err != nil { + return nil, err + } + openStreams := t.openStreams.Add(1) + if openStreams >= t.MaxOpenStreams { + t.openStreams.Add(-1) + return nil, common.TooManyOpenStreams + } + stream, err := func() (stream net.Conn, err error) { + defer func() { + t.deferQuicConn(quicConn, err) + }() + buf := pool.GetBuffer() + defer pool.PutBuffer(buf) + err = NewConnect(NewAddress(metadata)).WriteTo(buf) + if err != nil { + return nil, err + } + quicStream, err := quicConn.OpenStream() + if err != nil { + return nil, err + } + stream = common.NewQuicStreamConn( + quicStream, + quicConn.LocalAddr(), + quicConn.RemoteAddr(), + func() { + time.AfterFunc(C.DefaultTCPTimeout, func() { + openStreams := t.openStreams.Add(-1) + if openStreams == 0 && t.closed.Load() { + t.forceClose(quicConn, common.ClientClosed) + } + }) + }, + ) + _, err = buf.WriteTo(stream) + if err != nil { + _ = stream.Close() + return nil, err + } + return stream, err + }() + if err != nil { + return nil, err + } + + return stream, nil +} + +func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) { + quicConn, err := t.getQuicConn(ctx, dialer, dialFn) + if err != nil { + return nil, err + } + openStreams := t.openStreams.Add(1) + if openStreams >= t.MaxOpenStreams { + t.openStreams.Add(-1) + return nil, common.TooManyOpenStreams + } + + pipe1, pipe2 := net.Pipe() + var connId uint16 + for { + connId = uint16(fastrand.Intn(0xFFFF)) + _, loaded := t.udpInputMap.LoadOrStore(connId, pipe1) + if !loaded { + break + } + } + pc := &quicStreamPacketConn{ + connId: connId, + quicConn: quicConn, + inputConn: N.NewBufferedConn(pipe2), + udpRelayMode: t.UdpRelayMode, + maxUdpRelayPacketSize: t.MaxUdpRelayPacketSize, + deferQuicConnFn: t.deferQuicConn, + closeDeferFn: func() { + t.udpInputMap.Delete(connId) + time.AfterFunc(C.DefaultUDPTimeout, func() { + openStreams := t.openStreams.Add(-1) + if openStreams == 0 && t.closed.Load() { + t.forceClose(quicConn, common.ClientClosed) + } + }) + }, + } + return pc, nil +} + +type Client struct { + *clientImpl // use an independent pointer to let Finalizer can work no matter somewhere handle an influence in clientImpl inner +} + +func (t *Client) DialContextWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.Conn, error) { + conn, err := t.clientImpl.DialContextWithDialer(ctx, metadata, dialer, dialFn) + if err != nil { + return nil, err + } + return N.NewRefConn(conn, t), err +} + +func (t *Client) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn common.DialFunc) (net.PacketConn, error) { + pc, err := t.clientImpl.ListenPacketWithDialer(ctx, metadata, dialer, dialFn) + if err != nil { + return nil, err + } + return N.NewRefPacketConn(pc, t), nil +} + +func (t *Client) forceClose() { + t.clientImpl.forceClose(nil, common.ClientClosed) +} + +func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client { + ci := &clientImpl{ + ClientOption: clientOption, + udp: udp, + dialerRef: dialerRef, + } + c := &Client{ci} + runtime.SetFinalizer(c, closeClient) + log.Debugln("New TuicV5 Client at %p", c) + return c +} + +func closeClient(client *Client) { + log.Debugln("Close TuicV5 Client at %p", client) + client.forceClose() +} diff --git a/transport/tuic/v5/frag.go b/transport/tuic/v5/frag.go new file mode 100644 index 00000000..30b7b3f5 --- /dev/null +++ b/transport/tuic/v5/frag.go @@ -0,0 +1,80 @@ +package v5 + +import ( + "bytes" + + "github.com/metacubex/quic-go" +) + +func fragWriteNative(quicConn quic.Connection, packet Packet, buf *bytes.Buffer, fragSize int) (err error) { + fullPayload := packet.DATA + off := 0 + fragID := uint8(0) + fragCount := uint8((len(fullPayload) + fragSize - 1) / fragSize) // round up + packet.FRAG_TOTAL = fragCount + for off < len(fullPayload) { + payloadSize := len(fullPayload) - off + if payloadSize > fragSize { + payloadSize = fragSize + } + frag := packet + frag.FRAG_ID = fragID + frag.SIZE = uint16(payloadSize) + frag.DATA = fullPayload[off : off+payloadSize] + off += payloadSize + fragID++ + buf.Reset() + err = frag.WriteTo(buf) + if err != nil { + return + } + data := buf.Bytes() + err = quicConn.SendMessage(data) + if err != nil { + return + } + packet.ADDR.TYPE = AtypNone // avoid "fragment 2/2: address in non-first fragment" + } + return +} + +type deFragger struct { + pkgID uint16 + frags []*Packet + count uint8 +} + +func (d *deFragger) Feed(m Packet) *Packet { + if m.FRAG_TOTAL <= 1 { + return &m + } + if m.FRAG_ID >= m.FRAG_TOTAL { + // wtf is this? + return nil + } + if d.count == 0 || m.PKT_ID != d.pkgID { + // new message, clear previous state + d.pkgID = m.PKT_ID + d.frags = make([]*Packet, m.FRAG_TOTAL) + d.count = 1 + d.frags[m.FRAG_ID] = &m + } else if d.frags[m.FRAG_ID] == nil { + d.frags[m.FRAG_ID] = &m + d.count++ + if int(d.count) == len(d.frags) { + // all fragments received, assemble + var data []byte + for _, frag := range d.frags { + data = append(data, frag.DATA...) + } + p := d.frags[0] // recover from first fragment + p.SIZE = uint16(len(data)) + p.DATA = data + p.FRAG_ID = 0 + p.FRAG_TOTAL = 1 + d.count = 0 + return p + } + } + return nil +} diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go new file mode 100644 index 00000000..50c602eb --- /dev/null +++ b/transport/tuic/v5/packet.go @@ -0,0 +1,208 @@ +package v5 + +import ( + "errors" + "net" + "sync" + "sync/atomic" + "time" + + N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/pool" + + "github.com/metacubex/quic-go" + "github.com/zhangyunhao116/fastrand" +) + +type quicStreamPacketConn struct { + connId uint16 + quicConn quic.Connection + inputConn *N.BufferedConn + + udpRelayMode string + maxUdpRelayPacketSize int + + deferQuicConnFn func(quicConn quic.Connection, err error) + closeDeferFn func() + writeClosed *atomic.Bool + + closeOnce sync.Once + closeErr error + closed bool + + deFragger +} + +func (q *quicStreamPacketConn) Close() error { + q.closeOnce.Do(func() { + q.closed = true + q.closeErr = q.close() + }) + return q.closeErr +} + +func (q *quicStreamPacketConn) close() (err error) { + if q.closeDeferFn != nil { + defer q.closeDeferFn() + } + if q.deferQuicConnFn != nil { + defer func() { + q.deferQuicConnFn(q.quicConn, err) + }() + } + if q.inputConn != nil { + _ = q.inputConn.Close() + q.inputConn = nil + + buf := pool.GetBuffer() + defer pool.PutBuffer(buf) + err = NewDissociate(q.connId).WriteTo(buf) + if err != nil { + return + } + var stream quic.SendStream + stream, err = q.quicConn.OpenUniStream() + if err != nil { + return + } + _, err = buf.WriteTo(stream) + if err != nil { + return + } + err = stream.Close() + if err != nil { + return + } + } + return +} + +func (q *quicStreamPacketConn) SetDeadline(t time.Time) error { + //TODO implement me + return nil +} + +func (q *quicStreamPacketConn) SetReadDeadline(t time.Time) error { + if q.inputConn != nil { + return q.inputConn.SetReadDeadline(t) + } + return nil +} + +func (q *quicStreamPacketConn) SetWriteDeadline(t time.Time) error { + //TODO implement me + return nil +} + +func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { + if q.inputConn != nil { + for { + var packet Packet + packet, err = ReadPacket(q.inputConn) + if err != nil { + return + } + if packetPtr := q.deFragger.Feed(packet); packetPtr != nil { + n = copy(p, packet.DATA) + addr = packetPtr.ADDR.UDPAddr() + return + } + } + } else { + err = net.ErrClosed + } + return +} + +func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + if q.inputConn != nil { + for { + var packet Packet + packet, err = ReadPacket(q.inputConn) + if err != nil { + return + } + if packetPtr := q.deFragger.Feed(packet); packetPtr != nil { + data = packetPtr.DATA + addr = packetPtr.ADDR.UDPAddr() + return + } + } + } else { + err = net.ErrClosed + } + return +} + +func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { + if len(p) > 0xffff { // uint16 max + return 0, quic.ErrMessageTooLarge(0xffff) + } + if q.closed { + return 0, net.ErrClosed + } + if q.writeClosed != nil && q.writeClosed.Load() { + _ = q.Close() + return 0, net.ErrClosed + } + if q.deferQuicConnFn != nil { + defer func() { + q.deferQuicConnFn(q.quicConn, err) + }() + } + buf := pool.GetBuffer() + defer pool.PutBuffer(buf) + address, err := NewAddressNetAddr(addr) + if err != nil { + return + } + pktId := uint16(fastrand.Uint32()) + packet := NewPacket(q.connId, pktId, 1, 0, uint16(len(p)), address, p) + switch q.udpRelayMode { + case "quic": + err = packet.WriteTo(buf) + if err != nil { + return + } + var stream quic.SendStream + stream, err = q.quicConn.OpenUniStream() + if err != nil { + return + } + defer stream.Close() + _, err = buf.WriteTo(stream) + if err != nil { + return + } + default: // native + if len(p) > q.maxUdpRelayPacketSize { + err = fragWriteNative(q.quicConn, packet, buf, q.maxUdpRelayPacketSize) + if err != nil { + return + } + } + err = packet.WriteTo(buf) + if err != nil { + return + } + data := buf.Bytes() + err = q.quicConn.SendMessage(data) + + var tooLarge quic.ErrMessageTooLarge + if errors.As(err, &tooLarge) { + err = fragWriteNative(q.quicConn, packet, buf, int(tooLarge)-PacketOverHead) + } + if err != nil { + return + } + } + n = len(p) + + return +} + +func (q *quicStreamPacketConn) LocalAddr() net.Addr { + return q.quicConn.LocalAddr() +} + +var _ net.PacketConn = (*quicStreamPacketConn)(nil) diff --git a/transport/tuic/v5/protocol.go b/transport/tuic/v5/protocol.go new file mode 100644 index 00000000..f2849746 --- /dev/null +++ b/transport/tuic/v5/protocol.go @@ -0,0 +1,651 @@ +package v5 + +import ( + "encoding/binary" + "fmt" + "io" + "net" + "net/netip" + "strconv" + + "github.com/Dreamacro/clash/common/utils" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/transport/socks5" + + "github.com/metacubex/quic-go" +) + +type BufferedReader interface { + io.Reader + io.ByteReader +} + +type BufferedWriter interface { + io.Writer + io.ByteWriter +} + +type CommandType byte + +const ( + AuthenticateType = CommandType(0x00) + ConnectType = CommandType(0x01) + PacketType = CommandType(0x02) + DissociateType = CommandType(0x03) + HeartbeatType = CommandType(0x04) + ResponseType = CommandType(0xff) +) + +func (c CommandType) String() string { + switch c { + case AuthenticateType: + return "Authenticate" + case ConnectType: + return "Connect" + case PacketType: + return "Packet" + case DissociateType: + return "Dissociate" + case HeartbeatType: + return "Heartbeat" + case ResponseType: + return "Response" + default: + return fmt.Sprintf("UnknowCommand: %#x", byte(c)) + } +} + +func (c CommandType) BytesLen() int { + return 1 +} + +type CommandHead struct { + VER byte + TYPE CommandType +} + +func NewCommandHead(TYPE CommandType) CommandHead { + return CommandHead{ + VER: 0x05, + TYPE: TYPE, + } +} + +func ReadCommandHead(reader BufferedReader) (c CommandHead, err error) { + c.VER, err = reader.ReadByte() + if err != nil { + return + } + TYPE, err := reader.ReadByte() + if err != nil { + return + } + c.TYPE = CommandType(TYPE) + return +} + +func (c CommandHead) WriteTo(writer BufferedWriter) (err error) { + err = writer.WriteByte(c.VER) + if err != nil { + return + } + err = writer.WriteByte(byte(c.TYPE)) + if err != nil { + return + } + return +} + +func (c CommandHead) BytesLen() int { + return 1 + c.TYPE.BytesLen() +} + +type Authenticate struct { + CommandHead + UUID [16]byte + TOKEN [32]byte +} + +func NewAuthenticate(UUID [16]byte, TOKEN [32]byte) Authenticate { + return Authenticate{ + CommandHead: NewCommandHead(AuthenticateType), + UUID: UUID, + TOKEN: TOKEN, + } +} + +func ReadAuthenticateWithHead(head CommandHead, reader BufferedReader) (c Authenticate, err error) { + c.CommandHead = head + if c.CommandHead.TYPE != AuthenticateType { + err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) + return + } + _, err = io.ReadFull(reader, c.UUID[:]) + if err != nil { + return + } + _, err = io.ReadFull(reader, c.TOKEN[:]) + if err != nil { + return + } + return +} + +func ReadAuthenticate(reader BufferedReader) (c Authenticate, err error) { + head, err := ReadCommandHead(reader) + if err != nil { + return + } + return ReadAuthenticateWithHead(head, reader) +} + +func GenToken(state quic.ConnectionState, uuid [16]byte, password string) (token [32]byte, err error) { + var tokenBytes []byte + tokenBytes, err = state.TLS.ExportKeyingMaterial(utils.StringFromImmutableBytes(uuid[:]), utils.ImmutableBytesFromString(password), 32) + if err != nil { + return + } + copy(token[:], tokenBytes) + return +} + +func (c Authenticate) WriteTo(writer BufferedWriter) (err error) { + err = c.CommandHead.WriteTo(writer) + if err != nil { + return + } + _, err = writer.Write(c.UUID[:]) + if err != nil { + return + } + _, err = writer.Write(c.TOKEN[:]) + if err != nil { + return + } + return +} + +func (c Authenticate) BytesLen() int { + return c.CommandHead.BytesLen() + 16 + 32 +} + +type Connect struct { + CommandHead + ADDR Address +} + +func NewConnect(ADDR Address) Connect { + return Connect{ + CommandHead: NewCommandHead(ConnectType), + ADDR: ADDR, + } +} + +func ReadConnectWithHead(head CommandHead, reader BufferedReader) (c Connect, err error) { + c.CommandHead = head + if c.CommandHead.TYPE != ConnectType { + err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) + return + } + c.ADDR, err = ReadAddress(reader) + if err != nil { + return + } + return +} + +func ReadConnect(reader BufferedReader) (c Connect, err error) { + head, err := ReadCommandHead(reader) + if err != nil { + return + } + return ReadConnectWithHead(head, reader) +} + +func (c Connect) WriteTo(writer BufferedWriter) (err error) { + err = c.CommandHead.WriteTo(writer) + if err != nil { + return + } + err = c.ADDR.WriteTo(writer) + if err != nil { + return + } + return +} + +func (c Connect) BytesLen() int { + return c.CommandHead.BytesLen() + c.ADDR.BytesLen() +} + +type Packet struct { + CommandHead + ASSOC_ID uint16 + PKT_ID uint16 + FRAG_TOTAL uint8 + FRAG_ID uint8 + SIZE uint16 + ADDR Address + DATA []byte +} + +func NewPacket(ASSOC_ID uint16, PKT_ID uint16, FRGA_TOTAL uint8, FRAG_ID uint8, SIZE uint16, ADDR Address, DATA []byte) Packet { + return Packet{ + CommandHead: NewCommandHead(PacketType), + ASSOC_ID: ASSOC_ID, + PKT_ID: PKT_ID, + FRAG_ID: FRAG_ID, + FRAG_TOTAL: FRGA_TOTAL, + SIZE: SIZE, + ADDR: ADDR, + DATA: DATA, + } +} + +func ReadPacketWithHead(head CommandHead, reader BufferedReader) (c Packet, err error) { + c.CommandHead = head + if c.CommandHead.TYPE != PacketType { + err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) + return + } + err = binary.Read(reader, binary.BigEndian, &c.ASSOC_ID) + if err != nil { + return + } + err = binary.Read(reader, binary.BigEndian, &c.PKT_ID) + if err != nil { + return + } + err = binary.Read(reader, binary.BigEndian, &c.FRAG_TOTAL) + if err != nil { + return + } + err = binary.Read(reader, binary.BigEndian, &c.FRAG_ID) + if err != nil { + return + } + err = binary.Read(reader, binary.BigEndian, &c.SIZE) + if err != nil { + return + } + c.ADDR, err = ReadAddress(reader) + if err != nil { + return + } + c.DATA = make([]byte, c.SIZE) + _, err = io.ReadFull(reader, c.DATA) + if err != nil { + return + } + return +} + +func ReadPacket(reader BufferedReader) (c Packet, err error) { + head, err := ReadCommandHead(reader) + if err != nil { + return + } + return ReadPacketWithHead(head, reader) +} + +func (c Packet) WriteTo(writer BufferedWriter) (err error) { + err = c.CommandHead.WriteTo(writer) + if err != nil { + return + } + err = binary.Write(writer, binary.BigEndian, c.ASSOC_ID) + if err != nil { + return + } + err = binary.Write(writer, binary.BigEndian, c.PKT_ID) + if err != nil { + return + } + err = binary.Write(writer, binary.BigEndian, c.FRAG_TOTAL) + if err != nil { + return + } + err = binary.Write(writer, binary.BigEndian, c.FRAG_ID) + if err != nil { + return + } + err = binary.Write(writer, binary.BigEndian, c.SIZE) + if err != nil { + return + } + err = c.ADDR.WriteTo(writer) + if err != nil { + return + } + _, err = writer.Write(c.DATA) + if err != nil { + return + } + return +} + +func (c Packet) BytesLen() int { + return c.CommandHead.BytesLen() + 4 + 2 + c.ADDR.BytesLen() + len(c.DATA) +} + +var PacketOverHead = NewPacket(0, 0, 0, 0, 0, NewAddressAddrPort(netip.AddrPortFrom(netip.IPv6Unspecified(), 0)), nil).BytesLen() + +type Dissociate struct { + CommandHead + ASSOC_ID uint16 +} + +func NewDissociate(ASSOC_ID uint16) Dissociate { + return Dissociate{ + CommandHead: NewCommandHead(DissociateType), + ASSOC_ID: ASSOC_ID, + } +} + +func ReadDissociateWithHead(head CommandHead, reader BufferedReader) (c Dissociate, err error) { + c.CommandHead = head + if c.CommandHead.TYPE != DissociateType { + err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) + return + } + err = binary.Read(reader, binary.BigEndian, &c.ASSOC_ID) + if err != nil { + return + } + return +} + +func ReadDissociate(reader BufferedReader) (c Dissociate, err error) { + head, err := ReadCommandHead(reader) + if err != nil { + return + } + return ReadDissociateWithHead(head, reader) +} + +func (c Dissociate) WriteTo(writer BufferedWriter) (err error) { + err = c.CommandHead.WriteTo(writer) + if err != nil { + return + } + err = binary.Write(writer, binary.BigEndian, c.ASSOC_ID) + if err != nil { + return + } + return +} + +func (c Dissociate) BytesLen() int { + return c.CommandHead.BytesLen() + 4 +} + +type Heartbeat struct { + CommandHead +} + +func NewHeartbeat() Heartbeat { + return Heartbeat{ + CommandHead: NewCommandHead(HeartbeatType), + } +} + +func ReadHeartbeatWithHead(head CommandHead, reader BufferedReader) (c Heartbeat, err error) { + c.CommandHead = head + if c.CommandHead.TYPE != HeartbeatType { + err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) + return + } + return +} + +func ReadHeartbeat(reader BufferedReader) (c Heartbeat, err error) { + head, err := ReadCommandHead(reader) + if err != nil { + return + } + return ReadHeartbeatWithHead(head, reader) +} + +type Response struct { + CommandHead + REP byte +} + +func NewResponse(REP byte) Response { + return Response{ + CommandHead: NewCommandHead(ResponseType), + REP: REP, + } +} + +func NewResponseSucceed() Response { + return NewResponse(0x00) +} + +func NewResponseFailed() Response { + return NewResponse(0xff) +} + +func ReadResponseWithHead(head CommandHead, reader BufferedReader) (c Response, err error) { + c.CommandHead = head + if c.CommandHead.TYPE != ResponseType { + err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) + return + } + c.REP, err = reader.ReadByte() + if err != nil { + return + } + return +} + +func ReadResponse(reader BufferedReader) (c Response, err error) { + head, err := ReadCommandHead(reader) + if err != nil { + return + } + return ReadResponseWithHead(head, reader) +} + +func (c Response) WriteTo(writer BufferedWriter) (err error) { + err = c.CommandHead.WriteTo(writer) + if err != nil { + return + } + err = writer.WriteByte(c.REP) + if err != nil { + return + } + return +} + +func (c Response) IsSucceed() bool { + return c.REP == 0x00 +} + +func (c Response) IsFailed() bool { + return c.REP == 0xff +} + +func (c Response) BytesLen() int { + return c.CommandHead.BytesLen() + 1 +} + +// Addr types +const ( + AtypDomainName byte = 0 + AtypIPv4 byte = 1 + AtypIPv6 byte = 2 + AtypNone byte = 255 // Address type None is used in Packet commands that is not the first fragment of a UDP packet. +) + +type Address struct { + TYPE byte + ADDR []byte + PORT uint16 +} + +func NewAddress(metadata *C.Metadata) Address { + var addrType byte + var addr []byte + switch metadata.AddrType() { + case socks5.AtypIPv4: + addrType = AtypIPv4 + addr = metadata.DstIP.AsSlice() + case socks5.AtypIPv6: + addrType = AtypIPv6 + addr = metadata.DstIP.AsSlice() + case socks5.AtypDomainName: + addrType = AtypDomainName + addr = make([]byte, len(metadata.Host)+1) + addr[0] = byte(len(metadata.Host)) + copy(addr[1:], metadata.Host) + } + + port, _ := strconv.ParseUint(metadata.DstPort, 10, 16) + + return Address{ + TYPE: addrType, + ADDR: addr, + PORT: uint16(port), + } +} + +func NewAddressNetAddr(addr net.Addr) (Address, error) { + if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { + if addrPort := addr.AddrPort(); addrPort.IsValid() { // sing's M.Socksaddr maybe return an invalid AddrPort if it's a DomainName + return NewAddressAddrPort(addrPort), nil + } + } + addrStr := addr.String() + if addrPort, err := netip.ParseAddrPort(addrStr); err == nil { + return NewAddressAddrPort(addrPort), nil + } + metadata := &C.Metadata{} + if err := metadata.SetRemoteAddress(addrStr); err != nil { + return Address{}, err + } + return NewAddress(metadata), nil +} + +func NewAddressAddrPort(addrPort netip.AddrPort) Address { + var addrType byte + port := addrPort.Port() + addr := addrPort.Addr().Unmap() + if addr.Is4() { + addrType = AtypIPv4 + } else { + addrType = AtypIPv6 + } + return Address{ + TYPE: addrType, + ADDR: addr.AsSlice(), + PORT: port, + } +} + +func ReadAddress(reader BufferedReader) (c Address, err error) { + c.TYPE, err = reader.ReadByte() + if err != nil { + return + } + switch c.TYPE { + case AtypIPv4: + c.ADDR = make([]byte, net.IPv4len) + _, err = io.ReadFull(reader, c.ADDR) + if err != nil { + return + } + case AtypIPv6: + c.ADDR = make([]byte, net.IPv6len) + _, err = io.ReadFull(reader, c.ADDR) + if err != nil { + return + } + case AtypDomainName: + var addrLen byte + addrLen, err = reader.ReadByte() + if err != nil { + return + } + c.ADDR = make([]byte, addrLen+1) + c.ADDR[0] = addrLen + _, err = io.ReadFull(reader, c.ADDR[1:]) + if err != nil { + return + } + } + + if c.TYPE == AtypNone { + return + } + err = binary.Read(reader, binary.BigEndian, &c.PORT) + if err != nil { + return + } + return +} + +func (c Address) WriteTo(writer BufferedWriter) (err error) { + err = writer.WriteByte(c.TYPE) + if err != nil { + return + } + if c.TYPE == AtypNone { + return + } + _, err = writer.Write(c.ADDR[:]) + if err != nil { + return + } + err = binary.Write(writer, binary.BigEndian, c.PORT) + if err != nil { + return + } + return +} + +func (c Address) String() string { + switch c.TYPE { + case AtypDomainName: + return net.JoinHostPort(string(c.ADDR[1:]), strconv.Itoa(int(c.PORT))) + default: + addr, _ := netip.AddrFromSlice(c.ADDR) + addrPort := netip.AddrPortFrom(addr, c.PORT) + return addrPort.String() + } +} + +func (c Address) SocksAddr() socks5.Addr { + addr := make([]byte, 1+len(c.ADDR)+2) + switch c.TYPE { + case AtypIPv4: + addr[0] = socks5.AtypIPv4 + case AtypIPv6: + addr[0] = socks5.AtypIPv6 + case AtypDomainName: + addr[0] = socks5.AtypDomainName + } + copy(addr[1:], c.ADDR) + binary.BigEndian.PutUint16(addr[len(addr)-2:], c.PORT) + return addr +} + +func (c Address) UDPAddr() *net.UDPAddr { + return &net.UDPAddr{ + IP: c.ADDR, + Port: int(c.PORT), + Zone: "", + } +} + +func (c Address) BytesLen() int { + return 1 + len(c.ADDR) + 2 +} + +const ( + ProtocolError = quic.ApplicationErrorCode(0xfffffff0) + AuthenticationFailed = quic.ApplicationErrorCode(0xfffffff1) + AuthenticationTimeout = quic.ApplicationErrorCode(0xfffffff2) + BadCommand = quic.ApplicationErrorCode(0xfffffff3) +) diff --git a/transport/tuic/v5/server.go b/transport/tuic/v5/server.go new file mode 100644 index 00000000..3e3dc52f --- /dev/null +++ b/transport/tuic/v5/server.go @@ -0,0 +1,303 @@ +package v5 + +import ( + "bufio" + "bytes" + "context" + "crypto/tls" + "fmt" + "net" + "sync" + "sync/atomic" + "time" + + "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/utils" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/transport/socks5" + "github.com/Dreamacro/clash/transport/tuic/common" + + "github.com/gofrs/uuid/v5" + "github.com/metacubex/quic-go" +) + +type ServerOption struct { + HandleTcpFn func(conn net.Conn, addr socks5.Addr, additions ...inbound.Addition) error + HandleUdpFn func(addr socks5.Addr, packet C.UDPPacket, additions ...inbound.Addition) error + + TlsConfig *tls.Config + QuicConfig *quic.Config + Users map[[16]byte]string + CongestionController string + AuthenticationTimeout time.Duration + MaxUdpRelayPacketSize int +} + +type Server struct { + *ServerOption + listener *quic.EarlyListener +} + +func NewServer(option *ServerOption, pc net.PacketConn) (*Server, error) { + listener, err := quic.ListenEarly(pc, option.TlsConfig, option.QuicConfig) + if err != nil { + return nil, err + } + return &Server{ + ServerOption: option, + listener: listener, + }, err +} + +func (s *Server) Serve() error { + for { + conn, err := s.listener.Accept(context.Background()) + if err != nil { + return err + } + common.SetCongestionController(conn, s.CongestionController) + h := &serverHandler{ + Server: s, + quicConn: conn, + uuid: utils.NewUUIDV4(), + authCh: make(chan struct{}), + } + go h.handle() + } +} + +func (s *Server) Close() error { + return s.listener.Close() +} + +type serverHandler struct { + *Server + quicConn quic.EarlyConnection + uuid uuid.UUID + + authCh chan struct{} + authOk bool + authUUID string + authOnce sync.Once + + udpInputMap sync.Map +} + +func (s *serverHandler) handle() { + go func() { + _ = s.handleUniStream() + }() + go func() { + _ = s.handleStream() + }() + go func() { + _ = s.handleMessage() + }() + + <-s.quicConn.HandshakeComplete() + time.AfterFunc(s.AuthenticationTimeout, func() { + s.authOnce.Do(func() { + _ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout") + s.authOk = false + close(s.authCh) + }) + }) +} + +func (s *serverHandler) handleMessage() (err error) { + for { + var message []byte + message, err = s.quicConn.ReceiveMessage() + if err != nil { + return err + } + go func() (err error) { + buffer := bytes.NewBuffer(message) + packet, err := ReadPacket(buffer) + if err != nil { + return + } + return s.parsePacket(packet, "native") + }() + } +} + +func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err error) { + <-s.authCh + if !s.authOk { + return + } + var assocId uint16 + + assocId = packet.ASSOC_ID + + v, _ := s.udpInputMap.LoadOrStore(assocId, &serverUDPInput{}) + input := v.(*serverUDPInput) + if input.writeClosed.Load() { + return nil + } + packetPtr := input.Feed(packet) + if packetPtr == nil { + return + } + + pc := &quicStreamPacketConn{ + connId: assocId, + quicConn: s.quicConn, + inputConn: nil, + udpRelayMode: udpRelayMode, + maxUdpRelayPacketSize: s.MaxUdpRelayPacketSize, + deferQuicConnFn: nil, + closeDeferFn: nil, + writeClosed: &input.writeClosed, + } + + return s.HandleUdpFn(packetPtr.ADDR.SocksAddr(), &serverUDPPacket{ + pc: pc, + packet: packetPtr, + rAddr: N.NewCustomAddr("tuic", fmt.Sprintf("tuic-%s-%d", s.uuid, assocId), s.quicConn.RemoteAddr()), // for tunnel's handleUDPConn + }, inbound.WithInUser(s.authUUID)) +} + +func (s *serverHandler) handleStream() (err error) { + for { + var quicStream quic.Stream + quicStream, err = s.quicConn.AcceptStream(context.Background()) + if err != nil { + return err + } + go func() (err error) { + stream := common.NewQuicStreamConn( + quicStream, + s.quicConn.LocalAddr(), + s.quicConn.RemoteAddr(), + nil, + ) + conn := N.NewBufferedConn(stream) + connect, err := ReadConnect(conn) + if err != nil { + return err + } + <-s.authCh + if !s.authOk { + return conn.Close() + } + + err = s.HandleTcpFn(conn, connect.ADDR.SocksAddr(), inbound.WithInUser(s.authUUID)) + if err != nil { + _ = conn.Close() + return err + } + return + }() + } +} + +func (s *serverHandler) handleUniStream() (err error) { + for { + var stream quic.ReceiveStream + stream, err = s.quicConn.AcceptUniStream(context.Background()) + if err != nil { + return err + } + go func() (err error) { + defer func() { + stream.CancelRead(0) + }() + reader := bufio.NewReader(stream) + commandHead, err := ReadCommandHead(reader) + if err != nil { + return + } + switch commandHead.TYPE { + case AuthenticateType: + var authenticate Authenticate + authenticate, err = ReadAuthenticateWithHead(commandHead, reader) + if err != nil { + return + } + authOk := false + var authUUID uuid.UUID + var token [32]byte + if password, ok := s.Users[authenticate.UUID]; ok { + token, err = GenToken(s.quicConn.ConnectionState(), authenticate.UUID, password) + if err != nil { + return + } + if token == authenticate.TOKEN { + authOk = true + authUUID = authenticate.UUID + } + } + s.authOnce.Do(func() { + if !authOk { + _ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed") + } + s.authOk = authOk + s.authUUID = authUUID.String() + close(s.authCh) + }) + case PacketType: + var packet Packet + packet, err = ReadPacketWithHead(commandHead, reader) + if err != nil { + return + } + return s.parsePacket(packet, "quic") + case DissociateType: + var disassociate Dissociate + disassociate, err = ReadDissociateWithHead(commandHead, reader) + if err != nil { + return + } + if v, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded { + input := v.(*serverUDPInput) + input.writeClosed.Store(true) + } + case HeartbeatType: + var heartbeat Heartbeat + heartbeat, err = ReadHeartbeatWithHead(commandHead, reader) + if err != nil { + return + } + heartbeat.BytesLen() + } + return + }() + } +} + +type serverUDPInput struct { + writeClosed atomic.Bool + deFragger +} + +type serverUDPPacket struct { + pc *quicStreamPacketConn + packet *Packet + rAddr net.Addr +} + +func (s *serverUDPPacket) InAddr() net.Addr { + return s.pc.LocalAddr() +} + +func (s *serverUDPPacket) LocalAddr() net.Addr { + return s.rAddr +} + +func (s *serverUDPPacket) Data() []byte { + return s.packet.DATA +} + +func (s *serverUDPPacket) WriteBack(b []byte, addr net.Addr) (n int, err error) { + return s.pc.WriteTo(b, addr) +} + +func (s *serverUDPPacket) Drop() { + s.packet.DATA = nil +} + +var _ C.UDPPacket = (*serverUDPPacket)(nil) +var _ C.UDPPacketInAddr = (*serverUDPPacket)(nil) From 183f2d974c7d15df48d950ffeca1545def432c77 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 12 Jun 2023 10:01:13 +0000 Subject: [PATCH 28/79] fix: dns concurrent not work --- dns/util.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dns/util.go b/dns/util.go index 2ba4d426..edd26a42 100644 --- a/dns/util.go +++ b/dns/util.go @@ -291,6 +291,7 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) domain := msgToDomain(m) for _, client := range clients { + client := client // shadow define client to ensure the value captured by the closure will not be changed in the next loop _, cache = client.(rcodeClient) cache = !cache fast.Go(func() (*D.Msg, error) { From 644abcf0717f1a382866da9044bc70e68ee35bb8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 13 Jun 2023 17:50:10 +0800 Subject: [PATCH 29/79] fix: tuicV5's heartbeat should be a datagram packet --- adapter/outbound/tuic.go | 7 +- transport/tuic/common/type.go | 7 ++ transport/tuic/tuic.go | 7 ++ transport/tuic/v4/client.go | 149 +++++++++++++++++++------------- transport/tuic/v4/packet.go | 11 +-- transport/tuic/v4/server.go | 6 +- transport/tuic/v5/client.go | 156 ++++++++++++++++++++-------------- transport/tuic/v5/packet.go | 5 +- transport/tuic/v5/protocol.go | 68 --------------- transport/tuic/v5/server.go | 33 ++++--- 10 files changed, 233 insertions(+), 216 deletions(-) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index e2aafca5..af0d3b30 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -175,8 +175,9 @@ func NewTuic(option TuicOption) (*Tuic, error) { option.HeartbeatInterval = 10000 } + udpRelayMode := tuic.QUIC if option.UdpRelayMode != "quic" { - option.UdpRelayMode = "native" + udpRelayMode = tuic.NATIVE } if option.MaxUdpRelayPacketSize == 0 { @@ -264,7 +265,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { TlsConfig: tlsConfig, QuicConfig: quicConfig, Token: tkn, - UdpRelayMode: option.UdpRelayMode, + UdpRelayMode: udpRelayMode, CongestionController: option.CongestionController, ReduceRtt: option.ReduceRtt, RequestTimeout: time.Duration(option.RequestTimeout) * time.Millisecond, @@ -280,7 +281,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { QuicConfig: quicConfig, Uuid: uuid.FromStringOrNil(option.UUID), Password: option.Password, - UdpRelayMode: option.UdpRelayMode, + UdpRelayMode: udpRelayMode, CongestionController: option.CongestionController, ReduceRtt: option.ReduceRtt, MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, diff --git a/transport/tuic/common/type.go b/transport/tuic/common/type.go index 16c6f49e..a5a60986 100644 --- a/transport/tuic/common/type.go +++ b/transport/tuic/common/type.go @@ -32,3 +32,10 @@ type Server interface { Serve() error Close() error } + +type UdpRelayMode uint8 + +const ( + QUIC UdpRelayMode = iota + NATIVE +) diff --git a/transport/tuic/tuic.go b/transport/tuic/tuic.go index 279cec95..7be6f450 100644 --- a/transport/tuic/tuic.go +++ b/transport/tuic/tuic.go @@ -45,3 +45,10 @@ const DefaultConnectionReceiveWindow = common.DefaultConnectionReceiveWindow var GenTKN = v4.GenTKN var PacketOverHeadV4 = v4.PacketOverHead var PacketOverHeadV5 = v5.PacketOverHead + +type UdpRelayMode = common.UdpRelayMode + +const ( + QUIC = common.QUIC + NATIVE = common.NATIVE +) diff --git a/transport/tuic/v4/client.go b/transport/tuic/v4/client.go index ae0cf473..7e5ed7e0 100644 --- a/transport/tuic/v4/client.go +++ b/transport/tuic/v4/client.go @@ -29,7 +29,7 @@ type ClientOption struct { TlsConfig *tls.Config QuicConfig *quic.Config Token [32]byte - UdpRelayMode string + UdpRelayMode common.UdpRelayMode CongestionController string ReduceRtt bool RequestTimeout time.Duration @@ -99,7 +99,12 @@ func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn co if t.udp { go func() { - _ = t.parseUDP(quicConn) + switch t.UdpRelayMode { + case common.QUIC: + _ = t.handleUniStream(quicConn) + default: // native + _ = t.handleMessage(quicConn) + } }() } @@ -133,80 +138,102 @@ func (t *clientImpl) sendAuthentication(quicConn quic.Connection) (err error) { return nil } -func (t *clientImpl) parseUDP(quicConn quic.Connection) (err error) { +func (t *clientImpl) handleUniStream(quicConn quic.Connection) (err error) { defer func() { t.deferQuicConn(quicConn, err) }() - switch t.UdpRelayMode { - case "quic": - for { - var stream quic.ReceiveStream - stream, err = quicConn.AcceptUniStream(context.Background()) - if err != nil { - return err - } - go func() (err error) { - var assocId uint32 - defer func() { - t.deferQuicConn(quicConn, err) - if err != nil && assocId != 0 { - if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { - if conn, ok := val.(net.Conn); ok { - _ = conn.Close() - } + for { + var stream quic.ReceiveStream + stream, err = quicConn.AcceptUniStream(context.Background()) + if err != nil { + return err + } + go func() (err error) { + var assocId uint32 + defer func() { + t.deferQuicConn(quicConn, err) + if err != nil && assocId != 0 { + if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { + if conn, ok := val.(net.Conn); ok { + _ = conn.Close() } } - stream.CancelRead(0) - }() - reader := bufio.NewReader(stream) - packet, err := ReadPacket(reader) + } + stream.CancelRead(0) + }() + reader := bufio.NewReader(stream) + commandHead, err := ReadCommandHead(reader) + if err != nil { + return + } + switch commandHead.TYPE { + case PacketType: + var packet Packet + packet, err = ReadPacketWithHead(commandHead, reader) if err != nil { return } - assocId = packet.ASSOC_ID - if val, ok := t.udpInputMap.Load(assocId); ok { - if conn, ok := val.(net.Conn); ok { - writer := bufio.NewWriterSize(conn, packet.BytesLen()) - _ = packet.WriteTo(writer) - _ = writer.Flush() - } - } - return - }() - } - default: // native - for { - var message []byte - message, err = quicConn.ReceiveMessage() - if err != nil { - return err - } - go func() (err error) { - var assocId uint32 - defer func() { - t.deferQuicConn(quicConn, err) - if err != nil && assocId != 0 { - if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { - if conn, ok := val.(net.Conn); ok { - _ = conn.Close() - } + if t.udp && t.UdpRelayMode == common.QUIC { + assocId = packet.ASSOC_ID + if val, ok := t.udpInputMap.Load(assocId); ok { + if conn, ok := val.(net.Conn); ok { + writer := bufio.NewWriterSize(conn, packet.BytesLen()) + _ = packet.WriteTo(writer) + _ = writer.Flush() } } - }() - buffer := bytes.NewBuffer(message) - packet, err := ReadPacket(buffer) + } + } + return + }() + } +} + +func (t *clientImpl) handleMessage(quicConn quic.Connection) (err error) { + defer func() { + t.deferQuicConn(quicConn, err) + }() + for { + var message []byte + message, err = quicConn.ReceiveMessage() + if err != nil { + return err + } + go func() (err error) { + var assocId uint32 + defer func() { + t.deferQuicConn(quicConn, err) + if err != nil && assocId != 0 { + if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { + if conn, ok := val.(net.Conn); ok { + _ = conn.Close() + } + } + } + }() + reader := bytes.NewBuffer(message) + commandHead, err := ReadCommandHead(reader) + if err != nil { + return + } + switch commandHead.TYPE { + case PacketType: + var packet Packet + packet, err = ReadPacketWithHead(commandHead, reader) if err != nil { return } - assocId = packet.ASSOC_ID - if val, ok := t.udpInputMap.Load(assocId); ok { - if conn, ok := val.(net.Conn); ok { - _, _ = conn.Write(message) + if t.udp && t.UdpRelayMode == common.NATIVE { + assocId = packet.ASSOC_ID + if val, ok := t.udpInputMap.Load(assocId); ok { + if conn, ok := val.(net.Conn); ok { + _, _ = conn.Write(message) + } } } - return - }() - } + } + return + }() } } diff --git a/transport/tuic/v4/packet.go b/transport/tuic/v4/packet.go index edd872cc..2f808bef 100644 --- a/transport/tuic/v4/packet.go +++ b/transport/tuic/v4/packet.go @@ -6,10 +6,11 @@ import ( "sync/atomic" "time" - "github.com/metacubex/quic-go" - N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" + "github.com/Dreamacro/clash/transport/tuic/common" + + "github.com/metacubex/quic-go" ) type quicStreamPacketConn struct { @@ -17,7 +18,7 @@ type quicStreamPacketConn struct { quicConn quic.Connection inputConn *N.BufferedConn - udpRelayMode string + udpRelayMode common.UdpRelayMode maxUdpRelayPacketSize int deferQuicConnFn func(quicConn quic.Connection, err error) @@ -121,7 +122,7 @@ func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net } func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { - if q.udpRelayMode != "quic" && len(p) > q.maxUdpRelayPacketSize { + if q.udpRelayMode != common.QUIC && len(p) > q.maxUdpRelayPacketSize { return 0, quic.ErrMessageTooLarge(q.maxUdpRelayPacketSize) } if q.closed { @@ -147,7 +148,7 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro return } switch q.udpRelayMode { - case "quic": + case common.QUIC: var stream quic.SendStream stream, err = q.quicConn.OpenUniStream() if err != nil { diff --git a/transport/tuic/v4/server.go b/transport/tuic/v4/server.go index 525ead17..017494ea 100644 --- a/transport/tuic/v4/server.go +++ b/transport/tuic/v4/server.go @@ -118,12 +118,12 @@ func (s *serverHandler) handleMessage() (err error) { if err != nil { return } - return s.parsePacket(packet, "native") + return s.parsePacket(packet, common.NATIVE) }() } } -func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err error) { +func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayMode) (err error) { <-s.authCh if !s.authOk { return @@ -247,7 +247,7 @@ func (s *serverHandler) handleUniStream() (err error) { if err != nil { return } - return s.parsePacket(packet, "quic") + return s.parsePacket(packet, common.QUIC) case DissociateType: var disassociate Dissociate disassociate, err = ReadDissociateWithHead(commandHead, reader) diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go index 9b878177..7bc1c360 100644 --- a/transport/tuic/v5/client.go +++ b/transport/tuic/v5/client.go @@ -28,7 +28,7 @@ type ClientOption struct { QuicConfig *quic.Config Uuid [16]byte Password string - UdpRelayMode string + UdpRelayMode common.UdpRelayMode CongestionController string ReduceRtt bool MaxUdpRelayPacketSize int @@ -94,11 +94,14 @@ func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn co _ = t.sendAuthentication(quicConn) }() - if t.udp { + if t.udp && t.UdpRelayMode == common.QUIC { go func() { - _ = t.parseUDP(quicConn) + _ = t.handleUniStream(quicConn) }() } + go func() { + _ = t.handleMessage(quicConn) // always handleMessage because tuicV5 using datagram to send the Heartbeat + }() t.quicConn = quicConn t.openStreams.Store(0) @@ -134,80 +137,109 @@ func (t *clientImpl) sendAuthentication(quicConn quic.Connection) (err error) { return nil } -func (t *clientImpl) parseUDP(quicConn quic.Connection) (err error) { +func (t *clientImpl) handleUniStream(quicConn quic.Connection) (err error) { defer func() { t.deferQuicConn(quicConn, err) }() - switch t.UdpRelayMode { - case "quic": - for { - var stream quic.ReceiveStream - stream, err = quicConn.AcceptUniStream(context.Background()) - if err != nil { - return err - } - go func() (err error) { - var assocId uint16 - defer func() { - t.deferQuicConn(quicConn, err) - if err != nil && assocId != 0 { - if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { - if conn, ok := val.(net.Conn); ok { - _ = conn.Close() - } + for { + var stream quic.ReceiveStream + stream, err = quicConn.AcceptUniStream(context.Background()) + if err != nil { + return err + } + go func() (err error) { + var assocId uint16 + defer func() { + t.deferQuicConn(quicConn, err) + if err != nil && assocId != 0 { + if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { + if conn, ok := val.(net.Conn); ok { + _ = conn.Close() } } - stream.CancelRead(0) - }() - reader := bufio.NewReader(stream) - packet, err := ReadPacket(reader) + } + stream.CancelRead(0) + }() + reader := bufio.NewReader(stream) + commandHead, err := ReadCommandHead(reader) + if err != nil { + return + } + switch commandHead.TYPE { + case PacketType: + var packet Packet + packet, err = ReadPacketWithHead(commandHead, reader) if err != nil { return } - assocId = packet.ASSOC_ID - if val, ok := t.udpInputMap.Load(assocId); ok { - if conn, ok := val.(net.Conn); ok { - writer := bufio.NewWriterSize(conn, packet.BytesLen()) - _ = packet.WriteTo(writer) - _ = writer.Flush() - } - } - return - }() - } - default: // native - for { - var message []byte - message, err = quicConn.ReceiveMessage() - if err != nil { - return err - } - go func() (err error) { - var assocId uint16 - defer func() { - t.deferQuicConn(quicConn, err) - if err != nil && assocId != 0 { - if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { - if conn, ok := val.(net.Conn); ok { - _ = conn.Close() - } + if t.udp && t.UdpRelayMode == common.QUIC { + assocId = packet.ASSOC_ID + if val, ok := t.udpInputMap.Load(assocId); ok { + if conn, ok := val.(net.Conn); ok { + writer := bufio.NewWriterSize(conn, packet.BytesLen()) + _ = packet.WriteTo(writer) + _ = writer.Flush() } } - }() - buffer := bytes.NewBuffer(message) - packet, err := ReadPacket(buffer) + } + } + return + }() + } +} + +func (t *clientImpl) handleMessage(quicConn quic.Connection) (err error) { + defer func() { + t.deferQuicConn(quicConn, err) + }() + for { + var message []byte + message, err = quicConn.ReceiveMessage() + if err != nil { + return err + } + go func() (err error) { + var assocId uint16 + defer func() { + t.deferQuicConn(quicConn, err) + if err != nil && assocId != 0 { + if val, ok := t.udpInputMap.LoadAndDelete(assocId); ok { + if conn, ok := val.(net.Conn); ok { + _ = conn.Close() + } + } + } + }() + reader := bytes.NewBuffer(message) + commandHead, err := ReadCommandHead(reader) + if err != nil { + return + } + switch commandHead.TYPE { + case PacketType: + var packet Packet + packet, err = ReadPacketWithHead(commandHead, reader) if err != nil { return } - assocId = packet.ASSOC_ID - if val, ok := t.udpInputMap.Load(assocId); ok { - if conn, ok := val.(net.Conn); ok { - _, _ = conn.Write(message) + if t.udp && t.UdpRelayMode == common.NATIVE { + assocId = packet.ASSOC_ID + if val, ok := t.udpInputMap.Load(assocId); ok { + if conn, ok := val.(net.Conn); ok { + _, _ = conn.Write(message) + } } } - return - }() - } + case HeartbeatType: + var heartbeat Heartbeat + heartbeat, err = ReadHeartbeatWithHead(commandHead, reader) + if err != nil { + return + } + heartbeat.BytesLen() + } + return + }() } } diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go index 50c602eb..9f546400 100644 --- a/transport/tuic/v5/packet.go +++ b/transport/tuic/v5/packet.go @@ -9,6 +9,7 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" + "github.com/Dreamacro/clash/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/zhangyunhao116/fastrand" @@ -19,7 +20,7 @@ type quicStreamPacketConn struct { quicConn quic.Connection inputConn *N.BufferedConn - udpRelayMode string + udpRelayMode common.UdpRelayMode maxUdpRelayPacketSize int deferQuicConnFn func(quicConn quic.Connection, err error) @@ -159,7 +160,7 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro pktId := uint16(fastrand.Uint32()) packet := NewPacket(q.connId, pktId, 1, 0, uint16(len(p)), address, p) switch q.udpRelayMode { - case "quic": + case common.QUIC: err = packet.WriteTo(buf) if err != nil { return diff --git a/transport/tuic/v5/protocol.go b/transport/tuic/v5/protocol.go index f2849746..dc7062ea 100644 --- a/transport/tuic/v5/protocol.go +++ b/transport/tuic/v5/protocol.go @@ -33,7 +33,6 @@ const ( PacketType = CommandType(0x02) DissociateType = CommandType(0x03) HeartbeatType = CommandType(0x04) - ResponseType = CommandType(0xff) ) func (c CommandType) String() string { @@ -48,8 +47,6 @@ func (c CommandType) String() string { return "Dissociate" case HeartbeatType: return "Heartbeat" - case ResponseType: - return "Response" default: return fmt.Sprintf("UnknowCommand: %#x", byte(c)) } @@ -406,71 +403,6 @@ func ReadHeartbeat(reader BufferedReader) (c Heartbeat, err error) { return ReadHeartbeatWithHead(head, reader) } -type Response struct { - CommandHead - REP byte -} - -func NewResponse(REP byte) Response { - return Response{ - CommandHead: NewCommandHead(ResponseType), - REP: REP, - } -} - -func NewResponseSucceed() Response { - return NewResponse(0x00) -} - -func NewResponseFailed() Response { - return NewResponse(0xff) -} - -func ReadResponseWithHead(head CommandHead, reader BufferedReader) (c Response, err error) { - c.CommandHead = head - if c.CommandHead.TYPE != ResponseType { - err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) - return - } - c.REP, err = reader.ReadByte() - if err != nil { - return - } - return -} - -func ReadResponse(reader BufferedReader) (c Response, err error) { - head, err := ReadCommandHead(reader) - if err != nil { - return - } - return ReadResponseWithHead(head, reader) -} - -func (c Response) WriteTo(writer BufferedWriter) (err error) { - err = c.CommandHead.WriteTo(writer) - if err != nil { - return - } - err = writer.WriteByte(c.REP) - if err != nil { - return - } - return -} - -func (c Response) IsSucceed() bool { - return c.REP == 0x00 -} - -func (c Response) IsFailed() bool { - return c.REP == 0xff -} - -func (c Response) BytesLen() int { - return c.CommandHead.BytesLen() + 1 -} - // Addr types const ( AtypDomainName byte = 0 diff --git a/transport/tuic/v5/server.go b/transport/tuic/v5/server.go index 3e3dc52f..26965436 100644 --- a/transport/tuic/v5/server.go +++ b/transport/tuic/v5/server.go @@ -113,17 +113,33 @@ func (s *serverHandler) handleMessage() (err error) { return err } go func() (err error) { - buffer := bytes.NewBuffer(message) - packet, err := ReadPacket(buffer) + reader := bytes.NewBuffer(message) + commandHead, err := ReadCommandHead(reader) if err != nil { return } - return s.parsePacket(packet, "native") + switch commandHead.TYPE { + case PacketType: + var packet Packet + packet, err = ReadPacketWithHead(commandHead, reader) + if err != nil { + return + } + return s.parsePacket(packet, common.NATIVE) + case HeartbeatType: + var heartbeat Heartbeat + heartbeat, err = ReadHeartbeatWithHead(commandHead, reader) + if err != nil { + return + } + heartbeat.BytesLen() + } + return }() } } -func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err error) { +func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayMode) (err error) { <-s.authCh if !s.authOk { return @@ -244,7 +260,7 @@ func (s *serverHandler) handleUniStream() (err error) { if err != nil { return } - return s.parsePacket(packet, "quic") + return s.parsePacket(packet, common.QUIC) case DissociateType: var disassociate Dissociate disassociate, err = ReadDissociateWithHead(commandHead, reader) @@ -255,13 +271,6 @@ func (s *serverHandler) handleUniStream() (err error) { input := v.(*serverUDPInput) input.writeClosed.Store(true) } - case HeartbeatType: - var heartbeat Heartbeat - heartbeat, err = ReadHeartbeatWithHead(commandHead, reader) - if err != nil { - return - } - heartbeat.BytesLen() } return }() From 4f79bb7931cce8e0255b1b76e3421d53ea83270a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 14 Jun 2023 15:51:13 +0800 Subject: [PATCH 30/79] fix: singmux return wrong supportUDP value --- adapter/outbound/singmux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index 555a0ecb..9a977318 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -97,7 +97,7 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, func (s *SingMux) SupportUDP() bool { if s.onlyTcp { - return s.ProxyAdapter.SupportUOT() + return s.ProxyAdapter.SupportUDP() } return true } From af28b99b2ab38af36ce67af458621c298039ff4d Mon Sep 17 00:00:00 2001 From: H1JK Date: Wed, 14 Jun 2023 17:17:46 +0800 Subject: [PATCH 31/79] Add REALITY ChaCha20-Poly1305 auth mode support --- component/tls/reality.go | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index b8a7fa3a..265c584e 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -25,6 +25,7 @@ import ( utls "github.com/sagernet/utls" "github.com/zhangyunhao116/fastrand" + "golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/curve25519" "golang.org/x/crypto/hkdf" "golang.org/x/net/http2" @@ -37,6 +38,9 @@ type RealityConfig struct { ShortID [RealityMaxShortIDLen]byte } +//go:linkname aesgcmPreferred crypto/tls.aesgcmPreferred +func aesgcmPreferred(ciphers []uint16) bool + func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) { if fingerprint, exists := GetFingerprint(ClientFingerprint); exists { verifier := &realityVerifier{ @@ -61,17 +65,17 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string } hello := uConn.HandshakeState.Hello - for i := range hello.SessionId { // https://github.com/golang/go/issues/5373 - hello.SessionId[i] = 0 + rawSessionID := hello.Raw[39 : 39+32] // the location of session ID + for i := range rawSessionID { // https://github.com/golang/go/issues/5373 + rawSessionID[i] = 0 } - copy(hello.Raw[39:], hello.SessionId) binary.BigEndian.PutUint64(hello.SessionId, uint64(time.Now().Unix())) + copy(hello.SessionId[8:], realityConfig.ShortID[:]) hello.SessionId[0] = 1 hello.SessionId[1] = 8 - hello.SessionId[2] = 0 - copy(hello.SessionId[8:], realityConfig.ShortID[:]) + hello.SessionId[2] = 2 //log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16]) @@ -84,9 +88,14 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string if err != nil { return nil, err } - aesBlock, _ := aes.NewCipher(authKey) - aesGcmCipher, _ := cipher.NewGCM(aesBlock) - aesGcmCipher.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw) + var aeadCipher cipher.AEAD + if aesgcmPreferred(hello.CipherSuites) { + aesBlock, _ := aes.NewCipher(authKey) + aeadCipher, _ = cipher.NewGCM(aesBlock) + } else { + aeadCipher, _ = chacha20poly1305.New(authKey) + } + aeadCipher.Seal(hello.SessionId[:0], hello.Random[20:], hello.SessionId[:16], hello.Raw) copy(hello.Raw[39:], hello.SessionId) //log.Debugln("REALITY hello.sessionId: %v", hello.SessionId) //log.Debugln("REALITY uConn.AuthKey: %v", authKey) @@ -96,7 +105,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string return nil, err } - log.Debugln("REALITY Authentication: %v", verifier.verified) + log.Debugln("REALITY Authentication: %v, AEAD: %T", verifier.verified, aeadCipher) if !verifier.verified { go realityClientFallback(uConn, uConfig.ServerName, clientID) @@ -137,7 +146,7 @@ type realityVerifier struct { verified bool } -var pOffset = utils.MustOK(reflect.TypeOf((*utls.UConn)(nil)).Elem().FieldByName("peerCertificates")).Offset +var pOffset = utils.MustOK(reflect.TypeOf((*utls.Conn)(nil)).Elem().FieldByName("peerCertificates")).Offset func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { //p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates") From 77fb9a9c017059037f353b401877c5658489d3c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=90=E6=AE=87?= <95160953+xishang0128@users.noreply.github.com> Date: Thu, 15 Jun 2023 22:45:02 +0800 Subject: [PATCH 32/79] feat: optional provider path (#624) --- adapter/provider/parser.go | 17 +++++++++++------ constant/path.go | 8 ++++++++ rules/provider/parse.go | 24 ++++++++++++++++++++---- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index 2281c89b..f04bb77a 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -27,7 +27,7 @@ type healthCheckSchema struct { type proxyProviderSchema struct { Type string `provider:"type"` - Path string `provider:"path"` + Path string `provider:"path,omitempty"` URL string `provider:"url,omitempty"` Interval int `provider:"interval,omitempty"` Filter string `provider:"filter,omitempty"` @@ -60,17 +60,22 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide } hc := NewHealthCheck([]C.Proxy{}, schema.HealthCheck.URL, hcInterval, schema.HealthCheck.Lazy, expectedStatus) - path := C.Path.Resolve(schema.Path) - var vehicle types.Vehicle switch schema.Type { case "file": + path := C.Path.Resolve(schema.Path) vehicle = resource.NewFileVehicle(path) case "http": - if !C.Path.IsSafePath(path) { - return nil, fmt.Errorf("%w: %s", errSubPath, path) + if schema.Path != "" { + path := C.Path.Resolve(schema.Path) + if !C.Path.IsSafePath(path) { + return nil, fmt.Errorf("%w: %s", errSubPath, path) + } + vehicle = resource.NewHTTPVehicle(schema.URL, path) + } else { + path := C.Path.GetRandomPath("proxies", schema.URL) + vehicle = resource.NewHTTPVehicle(schema.URL, path) } - vehicle = resource.NewHTTPVehicle(schema.URL, path) default: return nil, fmt.Errorf("%w: %s", errVehicleType, schema.Type) } diff --git a/constant/path.go b/constant/path.go index a3124b24..68129838 100644 --- a/constant/path.go +++ b/constant/path.go @@ -1,6 +1,8 @@ package constant import ( + "crypto/md5" + "encoding/hex" "os" P "path" "path/filepath" @@ -72,6 +74,12 @@ func (p *path) IsSafePath(path string) bool { return !strings.Contains(rel, "..") } +func (p *path) GetRandomPath(prefix, name string) string { + hash := md5.Sum([]byte(name)) + filename := hex.EncodeToString(hash[:]) + return filepath.Join(p.HomeDir(), prefix, filename) +} + func (p *path) MMDB() string { files, err := os.ReadDir(p.homeDir) if err != nil { diff --git a/rules/provider/parse.go b/rules/provider/parse.go index 6a001b50..ef7beec5 100644 --- a/rules/provider/parse.go +++ b/rules/provider/parse.go @@ -1,18 +1,24 @@ package provider import ( + "errors" "fmt" + "time" + "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/resource" C "github.com/Dreamacro/clash/constant" P "github.com/Dreamacro/clash/constant/provider" - "time" +) + +var ( + errSubPath = errors.New("path is not subpath of home directory") ) type ruleProviderSchema struct { Type string `provider:"type"` Behavior string `provider:"behavior"` - Path string `provider:"path"` + Path string `provider:"path,omitempty"` URL string `provider:"url,omitempty"` Format string `provider:"format,omitempty"` Interval int `provider:"interval,omitempty"` @@ -48,13 +54,23 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t return nil, fmt.Errorf("unsupported format type: %s", schema.Format) } - path := C.Path.Resolve(schema.Path) var vehicle P.Vehicle switch schema.Type { case "file": + path := C.Path.Resolve(schema.Path) vehicle = resource.NewFileVehicle(path) case "http": - vehicle = resource.NewHTTPVehicle(schema.URL, path) + if schema.Path != "" { + path := C.Path.Resolve(schema.Path) + if !C.Path.IsSafePath(path) { + return nil, fmt.Errorf("%w: %s", errSubPath, path) + } + vehicle = resource.NewHTTPVehicle(schema.URL, path) + } else { + path := C.Path.GetRandomPath("rules", schema.URL) + vehicle = resource.NewHTTPVehicle(schema.URL, path) + } + default: return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type) } From 61734e5cac16904d07ec96a179c2613daf760ff1 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 17 Jun 2023 00:05:03 +0800 Subject: [PATCH 33/79] chore: Refine adapter type name --- constant/adapters.go | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/constant/adapters.go b/constant/adapters.go index a3796ef7..43398352 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -182,6 +182,7 @@ func (at AdapterType) String() string { return "Compatible" case Pass: return "Pass" + case Shadowsocks: return "Shadowsocks" case ShadowsocksR: @@ -189,13 +190,13 @@ func (at AdapterType) String() string { case Snell: return "Snell" case Socks5: - return "Socks5" + return "SOCKS5" case Http: - return "Http" + return "HTTP" case Vmess: - return "Vmess" + return "VMess" case Vless: - return "Vless" + return "VLESS" case Trojan: return "Trojan" case Hysteria: @@ -203,7 +204,7 @@ func (at AdapterType) String() string { case WireGuard: return "WireGuard" case Tuic: - return "Tuic" + return "TUIC" case Relay: return "Relay" From 6c8631d5cc1d4b2ddc8ab2b8c7784ceb361caa49 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 18 Jun 2023 00:47:26 +0800 Subject: [PATCH 34/79] chore: adjustable cwnd for cc in quic --- adapter/outbound/tuic.go | 7 ++ docs/config.yaml | 161 ++++++++++++++-------------- transport/tuic/common/congestion.go | 6 +- transport/tuic/v4/client.go | 3 +- transport/tuic/v4/server.go | 3 +- transport/tuic/v5/client.go | 3 +- transport/tuic/v5/server.go | 4 +- 7 files changed, 101 insertions(+), 86 deletions(-) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index af0d3b30..86b34dc8 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -49,6 +49,7 @@ type TuicOption struct { FastOpen bool `proxy:"fast-open,omitempty"` MaxOpenStreams int `proxy:"max-open-streams,omitempty"` + CWND int `proxy:"cwnd,omitempty"` SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` Fingerprint string `proxy:"fingerprint,omitempty"` CustomCA string `proxy:"ca,omitempty"` @@ -188,6 +189,10 @@ func NewTuic(option TuicOption) (*Tuic, error) { option.MaxOpenStreams = 100 } + if option.CWND == 0 { + option.CWND = 32 + } + packetOverHead := tuic.PacketOverHeadV4 if len(option.Token) == 0 { packetOverHead = tuic.PacketOverHeadV5 @@ -272,6 +277,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, FastOpen: option.FastOpen, MaxOpenStreams: clientMaxOpenStreams, + CWND: option.CWND, } t.client = tuic.NewPoolClientV4(clientOption) @@ -286,6 +292,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { ReduceRtt: option.ReduceRtt, MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, MaxOpenStreams: clientMaxOpenStreams, + CWND: option.CWND, } t.client = tuic.NewPoolClientV5(clientOption) diff --git a/docs/config.yaml b/docs/config.yaml index a8207917..1a86497d 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -64,7 +64,7 @@ hosts: profile: # 存储 select 选择记录 store-selected: false - + # 持久化 fake-ip store-fake-ip: true @@ -93,10 +93,10 @@ tun: #- 1000 # exclude-uid-range: # 排除路由的的用户范围 # - 1000-99999 - + # Android 用户和应用规则仅在 Android 下被支持 # 并且需要 auto-route - + # include-android-user: # 限制被路由的 Android 用户 # - 0 # - 10 @@ -126,10 +126,9 @@ sniffer: sniff: # TLS 默认如果不配置 ports 默认嗅探 443 TLS: # ports: [443, 8443] - + # 默认嗅探 80 HTTP: # 需要嗅探的端口 - ports: [80, 8080-8880] # 可覆盖 sniffer.override-destination override-destination: true @@ -144,7 +143,7 @@ sniffer: - tls - http # 强制对此域名进行嗅探 - + # 仅对白名单中的端口进行嗅探,默认为 443,80 # 已废弃,若 sniffer.sniff 配置则此项无效 port-whitelist: @@ -152,7 +151,6 @@ sniffer: - "443" # - 8000-9999 - tunnels: # one line config - tcp/udp,127.0.0.1:6553,114.114.114.114:53,proxy - tcp,127.0.0.1:6666,rds.mysql.com:3306,vpn @@ -162,7 +160,6 @@ tunnels: # one line config target: target.com proxy: proxy - # DNS配置 dns: enable: false # 关闭将使用系统 DNS @@ -177,18 +174,18 @@ dns: - 8.8.8.8 - tls://1.12.12.12:853 - tls://223.5.5.5:853 - - system # append DNS server from system configuration. If not found, it would print an error log and skip. + - system # append DNS server from system configuration. If not found, it would print an error log and skip. enhanced-mode: fake-ip # or redir-host - + fake-ip-range: 198.18.0.1/16 # fake-ip 池设置 - + # use-hosts: true # 查询 hosts - + # 配置不使用fake-ip的域名 # fake-ip-filter: # - '*.lan' # - localhost.ptlogin2.qq.com - + # DNS主要域名配置 # 支持 UDP,TCP,DoT,DoH,DoQ # 这部分为主要 DNS 配置,影响所有直连,确保使用对大陆解析精准的 DNS @@ -202,20 +199,20 @@ dns: - dhcp://en0 # dns from dhcp - quic://dns.adguard.com:784 # DNS over QUIC # - '8.8.8.8#en0' # 兼容指定DNS出口网卡 - + # 当配置 fallback 时,会查询 nameserver 中返回的 IP 是否为 CN,非必要配置 # 当不是 CN,则使用 fallback 中的 DNS 查询结果 # 确保配置 fallback 时能够正常查询 # fallback: # - tcp://1.1.1.1 # - 'tcp://1.1.1.1#ProxyGroupName' # 指定 DNS 过代理查询,ProxyGroupName 为策略组名或节点名,过代理配置优先于配置出口网卡,当找不到策略组或节点名则设置为出口网卡 - + # 专用于节点域名解析的 DNS 服务器,非必要配置项 # 配置服务器若查询失败将使用 nameserver,非并发查询 # proxy-server-nameserver: # - https://dns.google/dns-query # - tls://one.one.one.one - + # 配置 fallback 使用条件 # fallback-filter: # geoip: true # 配置是否使用 geoip @@ -230,7 +227,7 @@ dns: # - '+.google.com' # - '+.facebook.com' # - '+.youtube.com' - + # 配置查询域名使用的 DNS 服务器 nameserver-policy: # 'www.baidu.com': '114.114.114.114' @@ -241,7 +238,7 @@ dns: "geosite:category-ads-all": rcode://success "www.baidu.com,+.google.cn": [223.5.5.5, https://dns.alidns.com/dns-query] ## global,dns 为 rule-providers 中的名为 global 和 dns 规则订阅, - ## 且 behavior 必须为 domain/classical,当为 classical 时仅会生效域名类规则 + ## 且 behavior 必须为 domain/classical,当为 classical 时仅会生效域名类规则 # "rule-set:global,dns": 8.8.8.8 proxies: # socks5 @@ -256,7 +253,7 @@ proxies: # socks5 # skip-cert-verify: true # udp: true # ip-version: ipv6 - + # http - name: "http" type: http @@ -269,7 +266,7 @@ proxies: # socks5 # sni: custom.com # fingerprint: xxxx # 同 experimental.fingerprints 使用 sha256 指纹,配置协议独立的指纹,将忽略 experimental.fingerprints # ip-version: dual - + # Snell # Beware that there's currently no UDP support yet - name: "snell" @@ -281,7 +278,7 @@ proxies: # socks5 # obfs-opts: # mode: http # or tls # host: bing.com - + # Shadowsocks # cipher支持: # aes-128-gcm aes-192-gcm aes-256-gcm @@ -313,7 +310,7 @@ proxies: # socks5 # padding: false # Enable padding. Requires sing-box server version 1.3-beta9 or later. # statistic: false # 控制是否将底层连接显示在面板中,方便打断底层连接 # only-tcp: false # 如果设置为true, smux的设置将不会对udp生效,udp连接会直接走底层协议 - + - name: "ss2" type: ss server: server @@ -324,7 +321,7 @@ proxies: # socks5 plugin-opts: mode: tls # or http # host: bing.com - + - name: "ss3" type: ss server: server @@ -344,7 +341,7 @@ proxies: # socks5 # mux: true # headers: # custom: value - + - name: "ss4-shadow-tls" type: ss server: server @@ -364,20 +361,22 @@ proxies: # socks5 port: 443 cipher: chacha20-ietf-poly1305 password: [YOUR_SS_PASSWORD] - client-fingerprint: chrome # One of: chrome, ios, firefox or safari - # 可以是chrome, ios, firefox, safari中的一个 + client-fingerprint: + chrome # One of: chrome, ios, firefox or safari + # 可以是chrome, ios, firefox, safari中的一个 plugin: restls plugin-opts: - host: "www.microsoft.com" # Must be a TLS 1.3 server - # 应当是一个TLS 1.3 服务器 - password: [YOUR_RESTLS_PASSWORD] - version-hint: "tls13" - # Control your post-handshake traffic through restls-script - # Hide proxy behaviors like "tls in tls". - # see https://github.com/3andne/restls/blob/main/Restls-Script:%20Hide%20Your%20Proxy%20Traffic%20Behavior.md - # 用restls剧本来控制握手后的行为,隐藏"tls in tls"等特征 - # 详情:https://github.com/3andne/restls/blob/main/Restls-Script:%20%E9%9A%90%E8%97%8F%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%90%86%E8%A1%8C%E4%B8%BA.md - restls-script: "300?100<1,400~100,350~100,600~100,300~200,300~100" + host: + "www.microsoft.com" # Must be a TLS 1.3 server + # 应当是一个TLS 1.3 服务器 + password: [YOUR_RESTLS_PASSWORD] + version-hint: "tls13" + # Control your post-handshake traffic through restls-script + # Hide proxy behaviors like "tls in tls". + # see https://github.com/3andne/restls/blob/main/Restls-Script:%20Hide%20Your%20Proxy%20Traffic%20Behavior.md + # 用restls剧本来控制握手后的行为,隐藏"tls in tls"等特征 + # 详情:https://github.com/3andne/restls/blob/main/Restls-Script:%20%E9%9A%90%E8%97%8F%E4%BD%A0%E7%9A%84%E4%BB%A3%E7%90%86%E8%A1%8C%E4%B8%BA.md + restls-script: "300?100<1,400~100,350~100,600~100,300~200,300~100" - name: "ss-restls-tls12" type: ss @@ -385,16 +384,18 @@ proxies: # socks5 port: 443 cipher: chacha20-ietf-poly1305 password: [YOUR_SS_PASSWORD] - client-fingerprint: chrome # One of: chrome, ios, firefox or safari - # 可以是chrome, ios, firefox, safari中的一个 + client-fingerprint: + chrome # One of: chrome, ios, firefox or safari + # 可以是chrome, ios, firefox, safari中的一个 plugin: restls plugin-opts: - host: "vscode.dev" # Must be a TLS 1.2 server - # 应当是一个TLS 1.2 服务器 - password: [YOUR_RESTLS_PASSWORD] - version-hint: "tls12" - restls-script: "1000?100<1,500~100,350~100,600~100,400~200" - + host: + "vscode.dev" # Must be a TLS 1.2 server + # 应当是一个TLS 1.2 服务器 + password: [YOUR_RESTLS_PASSWORD] + version-hint: "tls12" + restls-script: "1000?100<1,500~100,350~100,600~100,400~200" + # vmess # cipher支持 auto/aes-128-gcm/chacha20-poly1305/none - name: "vmess" @@ -417,7 +418,7 @@ proxies: # socks5 # Host: v2ray.com # max-early-data: 2048 # early-data-header-name: Sec-WebSocket-Protocol - + - name: "vmess-h2" type: vmess server: server @@ -433,7 +434,7 @@ proxies: # socks5 - http.example.com - http-alt.example.com path: / - + - name: "vmess-http" type: vmess server: server @@ -452,7 +453,7 @@ proxies: # socks5 # Connection: # - keep-alive # ip-version: ipv4 # 设置使用 IP 类型偏好,可选:ipv4,ipv6,dual,默认值:dual - + - name: vmess-grpc server: server port: 443 @@ -468,7 +469,7 @@ proxies: # socks5 grpc-opts: grpc-service-name: "example" # ip-version: ipv4 - + # vless - name: "vless-tcp" type: vless @@ -481,7 +482,7 @@ proxies: # socks5 # skip-cert-verify: true # fingerprint: xxxx # client-fingerprint: random # Available: "chrome","firefox","safari","random","none" - + - name: "vless-vision" type: vless server: server @@ -494,7 +495,7 @@ proxies: # socks5 client-fingerprint: chrome # fingerprint: xxxx # skip-cert-verify: true - + - name: "vless-reality-vision" type: vless server: server @@ -509,7 +510,7 @@ proxies: # socks5 public-key: xxx short-id: xxx # optional client-fingerprint: chrome # cannot be empty - + - name: "vless-reality-grpc" type: vless server: server @@ -527,7 +528,7 @@ proxies: # socks5 reality-opts: public-key: CrrQSjAG_YkHLwvM2M-7XkKJilgL5upBKCp0od0tLhE short-id: 10f897e26c4b9478 - + - name: "vless-ws" type: vless server: server @@ -544,7 +545,7 @@ proxies: # socks5 path: "/" headers: Host: example.com - + # Trojan - name: "trojan" type: trojan @@ -559,7 +560,7 @@ proxies: # socks5 # - h2 # - http/1.1 # skip-cert-verify: true - + - name: trojan-grpc server: server port: 443 @@ -572,7 +573,7 @@ proxies: # socks5 udp: true grpc-opts: grpc-service-name: "example" - + - name: trojan-ws server: server port: 443 @@ -587,7 +588,7 @@ proxies: # socks5 # path: /path # headers: # Host: example.com - + - name: "trojan-xtls" type: trojan server: server @@ -599,7 +600,7 @@ proxies: # socks5 # sni: example.com # aka server name # skip-cert-verify: true # fingerprint: xxxx - + #hysteria - name: "hysteria" type: hysteria @@ -626,7 +627,7 @@ proxies: # socks5 # disable_mtu_discovery: false # fingerprint: xxxx # fast-open: true # 支持 TCP 快速打开,默认为 false - + # wireguard - name: "wg" type: wireguard @@ -655,7 +656,7 @@ proxies: # socks5 # # pre-shared-key: 31aIhAPwktDGpH4JDhA8GNvjFXEf/a6+UaQRyOAiyfM= # allowed_ips: ['0.0.0.0/0'] # reserved: [209,98,59] - + # tuic - name: tuic server: www.example.com @@ -674,12 +675,13 @@ proxies: # socks5 request-timeout: 8000 udp-relay-mode: native # Available: "native", "quic". Default: "native" # congestion-controller: bbr # Available: "cubic", "new_reno", "bbr". Default: "cubic" + # cwnd: 10 # default: 32 # max-udp-relay-packet-size: 1500 # fast-open: true # skip-cert-verify: true # max-open-streams: 20 # default 100, too many open streams may hurt performance # sni: example.com - + # ShadowsocksR # The supported ciphers (encryption methods): all stream ciphers in ss # The supported obfses: @@ -711,7 +713,7 @@ proxy-groups: - vmess - ss1 - ss2 - + # url-test 将按照 url 测试结果使用延迟最低节点 - name: "auto" type: url-test @@ -723,7 +725,7 @@ proxy-groups: # lazy: true url: "https://cp.cloudflare.com/generate_204" interval: 300 - + # fallback 将按照 url 测试结果按照节点顺序选择 - name: "fallback-auto" type: fallback @@ -733,7 +735,7 @@ proxy-groups: - vmess1 url: "https://cp.cloudflare.com/generate_204" interval: 300 - + # load-balance 将按照算法随机选择节点 - name: "load-balance" type: load-balance @@ -744,7 +746,7 @@ proxy-groups: url: "https://cp.cloudflare.com/generate_204" interval: 300 # strategy: consistent-hashing # 可选 round-robin 和 sticky-sessions - + # select 用户自行选择节点 - name: Proxy type: select @@ -754,7 +756,7 @@ proxy-groups: - ss2 - vmess1 - auto - + # 配置指定 interface-name 和 fwmark 的 DIRECT - name: en1 type: select @@ -762,7 +764,7 @@ proxy-groups: routing-mark: 6667 proxies: - DIRECT - + - name: UseProvider type: select filter: "HK|TW" # 正则表达式,过滤 provider1 中节点名包含 HK 或 TW @@ -778,7 +780,7 @@ proxy-providers: type: http url: "url" interval: 3600 - path: ./provider1.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 + path: ./provider1.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 health-check: enable: true interval: 600 @@ -795,7 +797,7 @@ rule-providers: rule1: behavior: classical # domain ipcidr interval: 259200 - path: /path/to/save/file.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 + path: /path/to/save/file.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 type: http url: "url" rule2: @@ -846,14 +848,14 @@ listeners: # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理 # udp: false # 默认 true - + - name: http-in-1 type: http port: 10809 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - + - name: mixed-in-1 type: mixed # HTTP(S) 和 SOCKS 代理混合 port: 10810 @@ -861,14 +863,14 @@ listeners: # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) # udp: false # 默认 true - + - name: reidr-in-1 type: redir port: 10811 listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - + - name: tproxy-in-1 type: tproxy port: 10812 @@ -876,7 +878,7 @@ listeners: # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) # udp: false # 默认 true - + - name: shadowsocks-in-1 type: shadowsocks port: 10813 @@ -885,7 +887,7 @@ listeners: # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) password: vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg= cipher: 2022-blake3-aes-256-gcm - + - name: vmess-in-1 type: vmess port: 10814 @@ -896,7 +898,7 @@ listeners: - username: 1 uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 alterId: 1 - + - name: tuic-in-1 type: tuic port: 10815 @@ -916,7 +918,7 @@ listeners: # alpn: # - h3 # max-udp-relay-packet-size: 1500 - + - name: tunnel-in-1 type: tunnel port: 10816 @@ -925,7 +927,7 @@ listeners: # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) network: [tcp, udp] target: target.com - + - name: tun-in-1 type: tun # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules @@ -956,10 +958,10 @@ listeners: # - 1000 # exclude_uid_range: # 排除路由的的用户范围 # - 1000-99999 - + # Android 用户和应用规则仅在 Android 下被支持 # 并且需要 auto_route - + # include_android_user: # 限制被路由的 Android 用户 # - 0 # - 10 @@ -967,7 +969,6 @@ listeners: # - com.android.chrome # exclude_package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin - # 入口配置与 Listener 等价,传入流量将和 socks,mixed 等入口一样按照 mode 所指定的方式进行匹配处理 # shadowsocks,vmess 入口配置(传入流量将和socks,mixed等入口一样按照mode所指定的方式进行匹配处理) # ss-config: ss://2022-blake3-aes-256-gcm:vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg=@:23456 diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index e2f7d867..8b8018b5 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -4,6 +4,7 @@ import ( "github.com/Dreamacro/clash/transport/tuic/congestion" "github.com/metacubex/quic-go" + c "github.com/metacubex/quic-go/congestion" ) const ( @@ -11,7 +12,8 @@ const ( DefaultConnectionReceiveWindow = 67108864 // 64 MB/s ) -func SetCongestionController(quicConn quic.Connection, cc string) { +func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { + CWND := c.ByteCount(cwnd) switch cc { case "cubic": quicConn.SetCongestionControl( @@ -36,7 +38,7 @@ func SetCongestionController(quicConn quic.Connection, cc string) { congestion.NewBBRSender( congestion.DefaultClock{}, congestion.GetInitialPacketSize(quicConn.RemoteAddr()), - congestion.InitialCongestionWindow*congestion.InitialMaxDatagramSize, + CWND*congestion.InitialMaxDatagramSize, congestion.DefaultBBRMaxCongestionWindow*congestion.InitialMaxDatagramSize, ), ) diff --git a/transport/tuic/v4/client.go b/transport/tuic/v4/client.go index 7e5ed7e0..e1a334e5 100644 --- a/transport/tuic/v4/client.go +++ b/transport/tuic/v4/client.go @@ -36,6 +36,7 @@ type ClientOption struct { MaxUdpRelayPacketSize int FastOpen bool MaxOpenStreams int64 + CWND int } type clientImpl struct { @@ -91,7 +92,7 @@ func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn co return nil, err } - common.SetCongestionController(quicConn, t.CongestionController) + common.SetCongestionController(quicConn, t.CongestionController, t.CWND) go func() { _ = t.sendAuthentication(quicConn) diff --git a/transport/tuic/v4/server.go b/transport/tuic/v4/server.go index 017494ea..37b311b0 100644 --- a/transport/tuic/v4/server.go +++ b/transport/tuic/v4/server.go @@ -33,6 +33,7 @@ type ServerOption struct { CongestionController string AuthenticationTimeout time.Duration MaxUdpRelayPacketSize int + CWND int } type Server struct { @@ -57,7 +58,7 @@ func (s *Server) Serve() error { if err != nil { return err } - common.SetCongestionController(conn, s.CongestionController) + common.SetCongestionController(conn, s.CongestionController, s.CWND) h := &serverHandler{ Server: s, quicConn: conn, diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go index 7bc1c360..cb1d538c 100644 --- a/transport/tuic/v5/client.go +++ b/transport/tuic/v5/client.go @@ -33,6 +33,7 @@ type ClientOption struct { ReduceRtt bool MaxUdpRelayPacketSize int MaxOpenStreams int64 + CWND int } type clientImpl struct { @@ -88,7 +89,7 @@ func (t *clientImpl) getQuicConn(ctx context.Context, dialer C.Dialer, dialFn co return nil, err } - common.SetCongestionController(quicConn, t.CongestionController) + common.SetCongestionController(quicConn, t.CongestionController, t.CWND) go func() { _ = t.sendAuthentication(quicConn) diff --git a/transport/tuic/v5/server.go b/transport/tuic/v5/server.go index 26965436..7b21ee6c 100644 --- a/transport/tuic/v5/server.go +++ b/transport/tuic/v5/server.go @@ -6,6 +6,7 @@ import ( "context" "crypto/tls" "fmt" + "net" "sync" "sync/atomic" @@ -32,6 +33,7 @@ type ServerOption struct { CongestionController string AuthenticationTimeout time.Duration MaxUdpRelayPacketSize int + CWND int } type Server struct { @@ -56,7 +58,7 @@ func (s *Server) Serve() error { if err != nil { return err } - common.SetCongestionController(conn, s.CongestionController) + common.SetCongestionController(conn, s.CongestionController, s.CWND) h := &serverHandler{ Server: s, quicConn: conn, From b9110c164d1c5a689ca39a3a5e77c369a1d7f613 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sun, 18 Jun 2023 01:50:32 +0800 Subject: [PATCH 35/79] update docs --- docs/config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 1a86497d..4e1b3a18 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -777,7 +777,7 @@ proxy-groups: # Clash 格式的节点或支持 *ray 的分享格式 proxy-providers: provider1: - type: http + type: http # http 的 path 可空置,默认储存路径为 homedir的proxies文件夹,文件名为url的md5 url: "url" interval: 3600 path: ./provider1.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 @@ -798,7 +798,7 @@ rule-providers: behavior: classical # domain ipcidr interval: 259200 path: /path/to/save/file.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 - type: http + type: http # http 的 path 可空置,默认储存路径为 homedir的rules文件夹,文件名为url的md5 url: "url" rule2: behavior: classical From fe0f2d9ef901da0eaefb171307553ae1734b15fc Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 19 Jun 2023 08:23:48 +0800 Subject: [PATCH 36/79] chore: Update dependencies --- adapter/outbound/vless.go | 4 ++-- adapter/outbound/vmess.go | 4 ++-- go.mod | 26 ++++++++++----------- go.sum | 43 ++++++++++++++++++----------------- listener/sing/sing.go | 2 +- listener/sing_vmess/server.go | 2 +- 6 files changed, 40 insertions(+), 41 deletions(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 325ccccd..803e0f57 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -26,8 +26,8 @@ import ( "github.com/Dreamacro/clash/transport/vless" "github.com/Dreamacro/clash/transport/vmess" - vmessSing "github.com/sagernet/sing-vmess" - "github.com/sagernet/sing-vmess/packetaddr" + vmessSing "github.com/metacubex/sing-vmess" + "github.com/metacubex/sing-vmess/packetaddr" M "github.com/sagernet/sing/common/metadata" ) diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index e9409aa4..acf6de75 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -21,8 +21,8 @@ import ( "github.com/Dreamacro/clash/transport/gun" clashVMess "github.com/Dreamacro/clash/transport/vmess" - vmess "github.com/sagernet/sing-vmess" - "github.com/sagernet/sing-vmess/packetaddr" + vmess "github.com/metacubex/sing-vmess" + "github.com/metacubex/sing-vmess/packetaddr" M "github.com/sagernet/sing/common/metadata" ) diff --git a/go.mod b/go.mod index 7e67d5bb..f3b1f731 100644 --- a/go.mod +++ b/go.mod @@ -21,19 +21,19 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb - github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c - github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca - github.com/metacubex/sing-tun v0.1.5-0.20230611154506-9fe2c0dc331d + github.com/metacubex/sing-shadowsocks v0.2.2 + github.com/metacubex/sing-shadowsocks2 v0.1.0 + github.com/metacubex/sing-tun v0.1.5-0.20230618235243-65051e73b018 + github.com/metacubex/sing-vmess v0.1.5 github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 github.com/miekg/dns v1.1.54 github.com/mroth/weightedrand/v2 v2.0.1 github.com/openacid/low v0.1.21 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c - github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 - github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3 - github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 + github.com/sagernet/sing v0.2.5 + github.com/sagernet/sing-mux v0.1.0 + github.com/sagernet/sing-shadowtls v0.1.2 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 @@ -45,11 +45,11 @@ require ( github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.2 - golang.org/x/crypto v0.9.0 + golang.org/x/crypto v0.10.0 golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 - golang.org/x/net v0.10.0 + golang.org/x/net v0.11.0 golang.org/x/sync v0.2.0 - golang.org/x/sys v0.8.0 + golang.org/x/sys v0.9.0 google.golang.org/protobuf v1.30.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 @@ -101,11 +101,9 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect golang.org/x/mod v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.6.0 // indirect ) -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.20230607134851-17f84aec22a1 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b diff --git a/go.sum b/go.sum index f503e205..933c39bd 100644 --- a/go.sum +++ b/go.sum @@ -95,16 +95,16 @@ github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggF github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb h1:92YTNmYXCSycERjKn/zPbeK5DiW3dd80j3+oVTEWTE8= github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb/go.mod h1:6pg8+Tje9KOltnj1whuvB2i5KFUMPp1TAF3oPhc5axM= -github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b h1:Bw4j3ktf5vivi5qm/ZQGtyRAgybRKSGJaMV1t3rtC+I= -github.com/metacubex/sing v0.0.0-20230530121223-b768faae5c6b/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c h1:LpVNvlW/xE+mR8z76xJeYZlYznZXEmU4TeWeuygYdJg= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca h1:10qc50Q1hHrfGO4NjEJpIAgHX63Y256tHE0dFCTN8J4= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca/go.mod h1:jVDD4N22bDPPKA73NvB7aqdlLWiAwv8D+jx7HwhcWak= -github.com/metacubex/sing-tun v0.1.5-0.20230611154506-9fe2c0dc331d h1:S4Oms2FG+IGhvup1LvgOCk0mW5i0Gn/VZ7JOXoXhTjg= -github.com/metacubex/sing-tun v0.1.5-0.20230611154506-9fe2c0dc331d/go.mod h1:6U1GUU8C2WzS9B2185K3wIE20gBF6gRmdpydqTesr18= -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 v0.0.0-20230618234508-ce8816d0274b h1:mVd3v+zMQq61rJe/pJJSh0/Iin9UnkQaZTH2NOg/2Vg= +github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/metacubex/sing-shadowsocks v0.2.2 h1:prciO78IwtR4Sp+/CnP+aZSzpBRfL7zKaYez1S4EOnI= +github.com/metacubex/sing-shadowsocks v0.2.2/go.mod h1:haolI+8Yc8MhNDqNuoRP4X5vaquXWNYeL1YxrQZ5kCU= +github.com/metacubex/sing-shadowsocks2 v0.1.0 h1:ZxPEToY1RaRtG6ljz2n13ASMVqyAM7Bh11TmWoExYu4= +github.com/metacubex/sing-shadowsocks2 v0.1.0/go.mod h1:6C4EkvqMz5h7jECKrQeIByoLDHxiepsgPajIrxqxj/s= +github.com/metacubex/sing-tun v0.1.5-0.20230618235243-65051e73b018 h1:M7vBGA4RL4BBLSYfi15u/9QdVSqPkhuL4KRCuRhxuQY= +github.com/metacubex/sing-tun v0.1.5-0.20230618235243-65051e73b018/go.mod h1:DSVNjWT0rkkg8zn2+wpDvxgXuXRmMiNFDnVmnUctbAc= +github.com/metacubex/sing-vmess v0.1.5 h1:wODu17P27aGw0GhSIb/rIZWNh3/F5ghF/1PDDt95CQY= +github.com/metacubex/sing-vmess v0.1.5/go.mod h1:s00xTd3c/zOMQHyPec0G/pbUklndleiH0QaHZRd4Ykg= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= @@ -144,10 +144,10 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= 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-mux v0.0.0-20230517134606-1ebe6bb26646 h1:X3ADfMqeGns1Q1FlXc9kaL9FwW1UM6D6tEQo8jFstpc= -github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= -github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3 h1:PNwJs1F+3e/iZguYQR7YzxsH8Sm0Eu7vVuHawD89r34= -github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI= +github.com/sagernet/sing-mux v0.1.0 h1:xihlDRNs1J+hYwmvW9/ZmaghjDx7O0Y5dty0pOLQGB4= +github.com/sagernet/sing-mux v0.1.0/go.mod h1:i3jKjV4pRTFTV/ly5V3oa2JMPy0SAZ5X8X4tDU9Hw94= +github.com/sagernet/sing-shadowtls v0.1.2 h1:wkPf4gF+cmaP0cIbArpyq+mc6GcwbMx60CssmmhEQ0s= +github.com/sagernet/sing-shadowtls v0.1.2/go.mod h1:rTxhbSY8jGWZOWjdeOe1vP3E+hkgen8aRA2p7YccM88= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= @@ -211,8 +211,8 @@ go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME= go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= 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.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -223,8 +223,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= 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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= @@ -246,13 +246,14 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.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= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index c60bbe67..f59fd613 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -14,8 +14,8 @@ import ( "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" + vmess "github.com/metacubex/sing-vmess" mux "github.com/sagernet/sing-mux" - vmess "github.com/sagernet/sing-vmess" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/bufio/deadline" diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index bb89ba99..f6a279c1 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -11,7 +11,7 @@ import ( LC "github.com/Dreamacro/clash/listener/config" "github.com/Dreamacro/clash/listener/sing" - vmess "github.com/sagernet/sing-vmess" + vmess "github.com/metacubex/sing-vmess" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/metadata" ) From d391fda051f415c211bdb7fd5f280f4f0a7aedc4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 19 Jun 2023 08:32:11 +0800 Subject: [PATCH 37/79] chore: function rename --- adapter/provider/parser.go | 2 +- constant/path.go | 2 +- rules/provider/parse.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index f04bb77a..d885a546 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -73,7 +73,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide } vehicle = resource.NewHTTPVehicle(schema.URL, path) } else { - path := C.Path.GetRandomPath("proxies", schema.URL) + path := C.Path.GetPathByHash("proxies", schema.URL) vehicle = resource.NewHTTPVehicle(schema.URL, path) } default: diff --git a/constant/path.go b/constant/path.go index 68129838..897dcfdc 100644 --- a/constant/path.go +++ b/constant/path.go @@ -74,7 +74,7 @@ func (p *path) IsSafePath(path string) bool { return !strings.Contains(rel, "..") } -func (p *path) GetRandomPath(prefix, name string) string { +func (p *path) GetPathByHash(prefix, name string) string { hash := md5.Sum([]byte(name)) filename := hex.EncodeToString(hash[:]) return filepath.Join(p.HomeDir(), prefix, filename) diff --git a/rules/provider/parse.go b/rules/provider/parse.go index ef7beec5..0fbfb2cc 100644 --- a/rules/provider/parse.go +++ b/rules/provider/parse.go @@ -67,7 +67,7 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t } vehicle = resource.NewHTTPVehicle(schema.URL, path) } else { - path := C.Path.GetRandomPath("rules", schema.URL) + path := C.Path.GetPathByHash("rules", schema.URL) vehicle = resource.NewHTTPVehicle(schema.URL, path) } From ad7508f2035e93f179d7989ee65add6e41a1e731 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 19 Jun 2023 14:28:06 +0800 Subject: [PATCH 38/79] Revert "chore: Refine adapter type name" This reverts commit 61734e5cac16904d07ec96a179c2613daf760ff1. --- constant/adapters.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/constant/adapters.go b/constant/adapters.go index 43398352..a3796ef7 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -182,7 +182,6 @@ func (at AdapterType) String() string { return "Compatible" case Pass: return "Pass" - case Shadowsocks: return "Shadowsocks" case ShadowsocksR: @@ -190,13 +189,13 @@ func (at AdapterType) String() string { case Snell: return "Snell" case Socks5: - return "SOCKS5" + return "Socks5" case Http: - return "HTTP" + return "Http" case Vmess: - return "VMess" + return "Vmess" case Vless: - return "VLESS" + return "Vless" case Trojan: return "Trojan" case Hysteria: @@ -204,7 +203,7 @@ func (at AdapterType) String() string { case WireGuard: return "WireGuard" case Tuic: - return "TUIC" + return "Tuic" case Relay: return "Relay" From 1d94546902a1b2ac35b016422838c09eb5b1ebfd Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 21 Jun 2023 00:40:33 +0800 Subject: [PATCH 39/79] chore: fix TUIC cwnd parsing --- listener/config/tuic.go | 1 + listener/tuic/server.go | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/listener/config/tuic.go b/listener/config/tuic.go index 30c99054..191cb59c 100644 --- a/listener/config/tuic.go +++ b/listener/config/tuic.go @@ -17,6 +17,7 @@ type TuicServer struct { ALPN []string `yaml:"alpn" json:"alpn,omitempty"` MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` MaxDatagramFrameSize int `yaml:"max-datagram-frame-size" json:"max-datagram-frame-size,omitempty"` + CWND int `yaml:"cwnd" json:"cwnd,omitempty"` } func (t TuicServer) String() string { diff --git a/listener/tuic/server.go b/listener/tuic/server.go index e1d8175c..742d8ac9 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -66,6 +66,10 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet packetOverHead = tuic.PacketOverHeadV5 } + if config.CWND == 0 { + config.CWND = 32 + } + if config.MaxUdpRelayPacketSize == 0 { config.MaxUdpRelayPacketSize = 1500 } @@ -115,6 +119,7 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet CongestionController: config.CongestionController, AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond, MaxUdpRelayPacketSize: config.MaxUdpRelayPacketSize, + CWND: config.CWND, } } else { users := make(map[[16]byte]string) @@ -131,6 +136,7 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet CongestionController: config.CongestionController, AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond, MaxUdpRelayPacketSize: config.MaxUdpRelayPacketSize, + CWND: config.CWND, } } From 6d824c8745b11236b6f00cfecb4ae8528fcd999b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 21 Jun 2023 13:53:37 +0800 Subject: [PATCH 40/79] chore: tuic server can handle V4 and V5 in same port --- docs/config.yaml | 8 +- listener/tuic/server.go | 51 ++---- transport/tuic/common/type.go | 11 +- transport/tuic/server.go | 234 +++++++++++++++++++++++++++ transport/tuic/tuic.go | 15 -- transport/tuic/v4/packet.go | 2 +- transport/tuic/v4/protocol.go | 4 +- transport/tuic/v4/server.go | 290 ++++++++++++---------------------- transport/tuic/v5/packet.go | 2 +- transport/tuic/v5/protocol.go | 4 +- transport/tuic/v5/server.go | 285 ++++++++++++--------------------- 11 files changed, 474 insertions(+), 432 deletions(-) create mode 100644 transport/tuic/server.go diff --git a/docs/config.yaml b/docs/config.yaml index 4e1b3a18..0cec9a04 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -905,9 +905,9 @@ listeners: listen: 0.0.0.0 # rule: sub-rule-name1 # 默认使用 rules,如果未找到 sub-rule 则直接使用 rules # proxy: proxy # 如果不为空则直接将该入站流量交由指定proxy处理(当proxy不为空时,这里的proxy名称必须合法,否则会出错) - # token: # tuicV4填写(不可同时填写users) + # token: # tuicV4填写(可以同时填写users) # - TOKEN - # users: # tuicV5填写(不可同时填写token) + # users: # tuicV5填写(可以同时填写token) # 00000000-0000-0000-0000-000000000000: PASSWORD_0 # 00000000-0000-0000-0000-000000000001: PASSWORD_1 # certificate: ./server.crt @@ -978,9 +978,9 @@ listeners: # tuic-server: # enable: true # listen: 127.0.0.1:10443 -# token: # tuicV4填写(不可同时填写users) +# token: # tuicV4填写(可以同时填写users) # - TOKEN -# users: # tuicV5填写(不可同时填写token) +# users: # tuicV5填写(可以同时填写token) # 00000000-0000-0000-0000-000000000000: PASSWORD_0 # 00000000-0000-0000-0000-000000000001: PASSWORD_1 # certificate: ./server.crt diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 742d8ac9..76996b27 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -26,7 +26,7 @@ type Listener struct { closed bool config LC.TuicServer udpListeners []net.PacketConn - servers []tuic.Server + servers []*tuic.Server } func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (*Listener, error) { @@ -102,42 +102,29 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet return nil } - var optionV4 *tuic.ServerOptionV4 - var optionV5 *tuic.ServerOptionV5 + option := &tuic.ServerOption{ + HandleTcpFn: handleTcpFn, + HandleUdpFn: handleUdpFn, + TlsConfig: tlsConfig, + QuicConfig: quicConfig, + CongestionController: config.CongestionController, + AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond, + MaxUdpRelayPacketSize: config.MaxUdpRelayPacketSize, + CWND: config.CWND, + } if len(config.Token) > 0 { tokens := make([][32]byte, len(config.Token)) for i, token := range config.Token { tokens[i] = tuic.GenTKN(token) } - - optionV4 = &tuic.ServerOptionV4{ - HandleTcpFn: handleTcpFn, - HandleUdpFn: handleUdpFn, - TlsConfig: tlsConfig, - QuicConfig: quicConfig, - Tokens: tokens, - CongestionController: config.CongestionController, - AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond, - MaxUdpRelayPacketSize: config.MaxUdpRelayPacketSize, - CWND: config.CWND, - } - } else { + option.Tokens = tokens + } + if len(config.Users) > 0 { users := make(map[[16]byte]string) for _uuid, password := range config.Users { users[uuid.FromStringOrNil(_uuid)] = password } - - optionV5 = &tuic.ServerOptionV5{ - HandleTcpFn: handleTcpFn, - HandleUdpFn: handleUdpFn, - TlsConfig: tlsConfig, - QuicConfig: quicConfig, - Users: users, - CongestionController: config.CongestionController, - AuthenticationTimeout: time.Duration(config.AuthenticationTimeout) * time.Millisecond, - MaxUdpRelayPacketSize: config.MaxUdpRelayPacketSize, - CWND: config.CWND, - } + option.Users = users } sl := &Listener{false, config, nil, nil} @@ -157,12 +144,8 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet sl.udpListeners = append(sl.udpListeners, ul) - var server tuic.Server - if optionV4 != nil { - server, err = tuic.NewServerV4(optionV4, ul) - } else { - server, err = tuic.NewServerV5(optionV5, ul) - } + var server *tuic.Server + server, err = tuic.NewServer(option, ul) if err != nil { return nil, err } diff --git a/transport/tuic/common/type.go b/transport/tuic/common/type.go index a5a60986..9a568dd7 100644 --- a/transport/tuic/common/type.go +++ b/transport/tuic/common/type.go @@ -1,11 +1,13 @@ package common import ( + "bufio" "context" "errors" "net" "time" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" "github.com/metacubex/quic-go" @@ -28,9 +30,12 @@ type Client interface { Close() } -type Server interface { - Serve() error - Close() error +type ServerHandler interface { + AuthOk() bool + HandleTimeout() + HandleStream(conn *N.BufferedConn) (err error) + HandleMessage(message []byte) (err error) + HandleUniStream(reader *bufio.Reader) (err error) } type UdpRelayMode uint8 diff --git a/transport/tuic/server.go b/transport/tuic/server.go new file mode 100644 index 00000000..47850107 --- /dev/null +++ b/transport/tuic/server.go @@ -0,0 +1,234 @@ +package tuic + +import ( + "bufio" + "context" + "crypto/tls" + "net" + "time" + + "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/utils" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/transport/socks5" + "github.com/Dreamacro/clash/transport/tuic/common" + v4 "github.com/Dreamacro/clash/transport/tuic/v4" + v5 "github.com/Dreamacro/clash/transport/tuic/v5" + + "github.com/gofrs/uuid/v5" + "github.com/metacubex/quic-go" +) + +type ServerOption struct { + HandleTcpFn func(conn net.Conn, addr socks5.Addr, additions ...inbound.Addition) error + HandleUdpFn func(addr socks5.Addr, packet C.UDPPacket, additions ...inbound.Addition) error + + TlsConfig *tls.Config + QuicConfig *quic.Config + Tokens [][32]byte // V4 special + Users map[[16]byte]string // V5 special + CongestionController string + AuthenticationTimeout time.Duration + MaxUdpRelayPacketSize int + CWND int +} + +type Server struct { + *ServerOption + optionV4 *v4.ServerOption + optionV5 *v5.ServerOption + listener *quic.EarlyListener +} + +func (s *Server) Serve() error { + for { + conn, err := s.listener.Accept(context.Background()) + if err != nil { + return err + } + common.SetCongestionController(conn, s.CongestionController, s.CWND) + h := &serverHandler{ + Server: s, + quicConn: conn, + uuid: utils.NewUUIDV4(), + } + if h.optionV4 != nil { + h.v4Handler = v4.NewServerHandler(h.optionV4, conn, h.uuid) + } + if h.optionV5 != nil { + h.v5Handler = v5.NewServerHandler(h.optionV5, conn, h.uuid) + } + go h.handle() + } +} + +func (s *Server) Close() error { + return s.listener.Close() +} + +type serverHandler struct { + *Server + quicConn quic.EarlyConnection + uuid uuid.UUID + + v4Handler common.ServerHandler + v5Handler common.ServerHandler +} + +func (s *serverHandler) handle() { + go func() { + _ = s.handleUniStream() + }() + go func() { + _ = s.handleStream() + }() + go func() { + _ = s.handleMessage() + }() + + <-s.quicConn.HandshakeComplete() + time.AfterFunc(s.AuthenticationTimeout, func() { + if s.v4Handler != nil { + if s.v4Handler.AuthOk() { + return + } + } + + if s.v5Handler != nil { + if s.v5Handler.AuthOk() { + return + } + } + + if s.v4Handler != nil { + s.v4Handler.HandleTimeout() + } + + if s.v5Handler != nil { + s.v5Handler.HandleTimeout() + } + }) +} + +func (s *serverHandler) handleMessage() (err error) { + for { + var message []byte + message, err = s.quicConn.ReceiveMessage() + if err != nil { + return err + } + go func() (err error) { + if len(message) > 0 { + switch message[0] { + case v4.VER: + if s.v4Handler != nil { + return s.v4Handler.HandleMessage(message) + } + case v5.VER: + if s.v5Handler != nil { + return s.v5Handler.HandleMessage(message) + } + } + } + return + }() + } +} + +func (s *serverHandler) handleStream() (err error) { + for { + var quicStream quic.Stream + quicStream, err = s.quicConn.AcceptStream(context.Background()) + if err != nil { + return err + } + go func() (err error) { + stream := common.NewQuicStreamConn( + quicStream, + s.quicConn.LocalAddr(), + s.quicConn.RemoteAddr(), + nil, + ) + conn := N.NewBufferedConn(stream) + + verBytes, err := conn.Peek(1) + if err != nil { + _ = conn.Close() + return err + } + + switch verBytes[0] { + case v4.VER: + if s.v4Handler != nil { + return s.v4Handler.HandleStream(conn) + } + case v5.VER: + if s.v5Handler != nil { + return s.v5Handler.HandleStream(conn) + } + } + return + }() + } +} + +func (s *serverHandler) handleUniStream() (err error) { + for { + var stream quic.ReceiveStream + stream, err = s.quicConn.AcceptUniStream(context.Background()) + if err != nil { + return err + } + go func() (err error) { + defer func() { + stream.CancelRead(0) + }() + reader := bufio.NewReader(stream) + verBytes, err := reader.Peek(1) + if err != nil { + return err + } + + switch verBytes[0] { + case v4.VER: + if s.v4Handler != nil { + return s.v4Handler.HandleUniStream(reader) + } + case v5.VER: + if s.v5Handler != nil { + return s.v5Handler.HandleUniStream(reader) + } + } + return + }() + } +} + +func NewServer(option *ServerOption, pc net.PacketConn) (*Server, error) { + listener, err := quic.ListenEarly(pc, option.TlsConfig, option.QuicConfig) + if err != nil { + return nil, err + } + server := &Server{ + ServerOption: option, + listener: listener, + } + if len(option.Tokens) > 0 { + server.optionV4 = &v4.ServerOption{ + HandleTcpFn: option.HandleTcpFn, + HandleUdpFn: option.HandleUdpFn, + Tokens: option.Tokens, + MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, + } + } + if len(option.Users) > 0 { + server.optionV5 = &v5.ServerOption{ + HandleTcpFn: option.HandleTcpFn, + HandleUdpFn: option.HandleUdpFn, + Users: option.Users, + MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, + } + } + return server, nil +} diff --git a/transport/tuic/tuic.go b/transport/tuic/tuic.go index 7be6f450..8832ef91 100644 --- a/transport/tuic/tuic.go +++ b/transport/tuic/tuic.go @@ -1,8 +1,6 @@ package tuic import ( - "net" - C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/tuic/common" v4 "github.com/Dreamacro/clash/transport/tuic/v4" @@ -26,19 +24,6 @@ type DialFunc = common.DialFunc var TooManyOpenStreams = common.TooManyOpenStreams -type ServerOptionV4 = v4.ServerOption -type ServerOptionV5 = v5.ServerOption - -type Server = common.Server - -func NewServerV4(option *ServerOptionV4, pc net.PacketConn) (Server, error) { - return v4.NewServer(option, pc) -} - -func NewServerV5(option *ServerOptionV5, pc net.PacketConn) (Server, error) { - return v5.NewServer(option, pc) -} - const DefaultStreamReceiveWindow = common.DefaultStreamReceiveWindow const DefaultConnectionReceiveWindow = common.DefaultConnectionReceiveWindow diff --git a/transport/tuic/v4/packet.go b/transport/tuic/v4/packet.go index 2f808bef..2066ceb7 100644 --- a/transport/tuic/v4/packet.go +++ b/transport/tuic/v4/packet.go @@ -3,9 +3,9 @@ package v4 import ( "net" "sync" - "sync/atomic" "time" + "github.com/Dreamacro/clash/common/atomic" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/transport/tuic/common" diff --git a/transport/tuic/v4/protocol.go b/transport/tuic/v4/protocol.go index 65f0f9d5..11ac3b4e 100644 --- a/transport/tuic/v4/protocol.go +++ b/transport/tuic/v4/protocol.go @@ -36,6 +36,8 @@ const ( ResponseType = CommandType(0xff) ) +const VER byte = 0x04 + func (c CommandType) String() string { switch c { case AuthenticateType: @@ -66,7 +68,7 @@ type CommandHead struct { func NewCommandHead(TYPE CommandType) CommandHead { return CommandHead{ - VER: 0x04, + VER: VER, TYPE: TYPE, } } diff --git a/transport/tuic/v4/server.go b/transport/tuic/v4/server.go index 37b311b0..9513ccfd 100644 --- a/transport/tuic/v4/server.go +++ b/transport/tuic/v4/server.go @@ -3,18 +3,14 @@ package v4 import ( "bufio" "bytes" - "context" - "crypto/tls" "fmt" "net" "sync" - "sync/atomic" - "time" "github.com/Dreamacro/clash/adapter/inbound" + "github.com/Dreamacro/clash/common/atomic" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/tuic/common" @@ -27,106 +23,55 @@ type ServerOption struct { HandleTcpFn func(conn net.Conn, addr socks5.Addr, additions ...inbound.Addition) error HandleUdpFn func(addr socks5.Addr, packet C.UDPPacket, additions ...inbound.Addition) error - TlsConfig *tls.Config - QuicConfig *quic.Config Tokens [][32]byte - CongestionController string - AuthenticationTimeout time.Duration MaxUdpRelayPacketSize int - CWND int } -type Server struct { - *ServerOption - listener *quic.EarlyListener -} - -func NewServer(option *ServerOption, pc net.PacketConn) (*Server, error) { - listener, err := quic.ListenEarly(pc, option.TlsConfig, option.QuicConfig) - if err != nil { - return nil, err - } - return &Server{ +func NewServerHandler(option *ServerOption, quicConn quic.EarlyConnection, uuid uuid.UUID) common.ServerHandler { + return &serverHandler{ ServerOption: option, - listener: listener, - }, err -} - -func (s *Server) Serve() error { - for { - conn, err := s.listener.Accept(context.Background()) - if err != nil { - return err - } - common.SetCongestionController(conn, s.CongestionController, s.CWND) - h := &serverHandler{ - Server: s, - quicConn: conn, - uuid: utils.NewUUIDV4(), - authCh: make(chan struct{}), - } - go h.handle() + quicConn: quicConn, + uuid: uuid, + authCh: make(chan struct{}), } } -func (s *Server) Close() error { - return s.listener.Close() -} - type serverHandler struct { - *Server + *ServerOption quicConn quic.EarlyConnection uuid uuid.UUID authCh chan struct{} - authOk bool + authOk atomic.Bool authOnce sync.Once udpInputMap sync.Map } -func (s *serverHandler) handle() { - go func() { - _ = s.handleUniStream() - }() - go func() { - _ = s.handleStream() - }() - go func() { - _ = s.handleMessage() - }() +func (s *serverHandler) AuthOk() bool { + return s.authOk.Load() +} - <-s.quicConn.HandshakeComplete() - time.AfterFunc(s.AuthenticationTimeout, func() { - s.authOnce.Do(func() { - _ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout") - s.authOk = false - close(s.authCh) - }) +func (s *serverHandler) HandleTimeout() { + s.authOnce.Do(func() { + _ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout") + s.authOk.Store(false) + close(s.authCh) }) } -func (s *serverHandler) handleMessage() (err error) { - for { - var message []byte - message, err = s.quicConn.ReceiveMessage() - if err != nil { - return err - } - go func() (err error) { - buffer := bytes.NewBuffer(message) - packet, err := ReadPacket(buffer) - if err != nil { - return - } - return s.parsePacket(packet, common.NATIVE) - }() +func (s *serverHandler) HandleMessage(message []byte) (err error) { + buffer := bytes.NewBuffer(message) + packet, err := ReadPacket(buffer) + if err != nil { + return } + return s.parsePacket(packet, common.NATIVE) } func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayMode) (err error) { <-s.authCh - if !s.authOk { + if !s.authOk.Load() { return } var assocId uint32 @@ -157,119 +102,90 @@ func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayM }) } -func (s *serverHandler) handleStream() (err error) { - for { - var quicStream quic.Stream - quicStream, err = s.quicConn.AcceptStream(context.Background()) - if err != nil { - return err - } - go func() (err error) { - stream := common.NewQuicStreamConn( - quicStream, - s.quicConn.LocalAddr(), - s.quicConn.RemoteAddr(), - nil, - ) - conn := N.NewBufferedConn(stream) - connect, err := ReadConnect(conn) - if err != nil { - return err - } - <-s.authCh - if !s.authOk { - return conn.Close() - } - - buf := pool.GetBuffer() - defer pool.PutBuffer(buf) - err = s.HandleTcpFn(conn, connect.ADDR.SocksAddr()) - if err != nil { - err = NewResponseFailed().WriteTo(buf) - defer conn.Close() - } else { - err = NewResponseSucceed().WriteTo(buf) - } - if err != nil { - _ = conn.Close() - return err - } - _, err = buf.WriteTo(stream) - if err != nil { - _ = conn.Close() - return err - } - - return - }() +func (s *serverHandler) HandleStream(conn *N.BufferedConn) (err error) { + connect, err := ReadConnect(conn) + if err != nil { + return err } + <-s.authCh + if !s.authOk.Load() { + return conn.Close() + } + + buf := pool.GetBuffer() + defer pool.PutBuffer(buf) + err = s.HandleTcpFn(conn, connect.ADDR.SocksAddr()) + if err != nil { + err = NewResponseFailed().WriteTo(buf) + defer conn.Close() + } else { + err = NewResponseSucceed().WriteTo(buf) + } + if err != nil { + _ = conn.Close() + return err + } + _, err = buf.WriteTo(conn) + if err != nil { + _ = conn.Close() + return err + } + + return } -func (s *serverHandler) handleUniStream() (err error) { - for { - var stream quic.ReceiveStream - stream, err = s.quicConn.AcceptUniStream(context.Background()) - if err != nil { - return err - } - go func() (err error) { - defer func() { - stream.CancelRead(0) - }() - reader := bufio.NewReader(stream) - commandHead, err := ReadCommandHead(reader) - if err != nil { - return - } - switch commandHead.TYPE { - case AuthenticateType: - var authenticate Authenticate - authenticate, err = ReadAuthenticateWithHead(commandHead, reader) - if err != nil { - return - } - authOk := false - for _, tkn := range s.Tokens { - if authenticate.TKN == tkn { - authOk = true - break - } - } - s.authOnce.Do(func() { - if !authOk { - _ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed") - } - s.authOk = authOk - close(s.authCh) - }) - case PacketType: - var packet Packet - packet, err = ReadPacketWithHead(commandHead, reader) - if err != nil { - return - } - return s.parsePacket(packet, common.QUIC) - case DissociateType: - var disassociate Dissociate - disassociate, err = ReadDissociateWithHead(commandHead, reader) - if err != nil { - return - } - if v, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded { - writeClosed := v.(*atomic.Bool) - writeClosed.Store(true) - } - case HeartbeatType: - var heartbeat Heartbeat - heartbeat, err = ReadHeartbeatWithHead(commandHead, reader) - if err != nil { - return - } - heartbeat.BytesLen() - } - return - }() +func (s *serverHandler) HandleUniStream(reader *bufio.Reader) (err error) { + commandHead, err := ReadCommandHead(reader) + if err != nil { + return } + switch commandHead.TYPE { + case AuthenticateType: + var authenticate Authenticate + authenticate, err = ReadAuthenticateWithHead(commandHead, reader) + if err != nil { + return + } + authOk := false + for _, tkn := range s.Tokens { + if authenticate.TKN == tkn { + authOk = true + break + } + } + s.authOnce.Do(func() { + if !authOk { + _ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed") + } + s.authOk.Store(authOk) + close(s.authCh) + }) + case PacketType: + var packet Packet + packet, err = ReadPacketWithHead(commandHead, reader) + if err != nil { + return + } + return s.parsePacket(packet, common.QUIC) + case DissociateType: + var disassociate Dissociate + disassociate, err = ReadDissociateWithHead(commandHead, reader) + if err != nil { + return + } + if v, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded { + writeClosed := v.(*atomic.Bool) + writeClosed.Store(true) + } + case HeartbeatType: + var heartbeat Heartbeat + heartbeat, err = ReadHeartbeatWithHead(commandHead, reader) + if err != nil { + return + } + heartbeat.BytesLen() + } + return } type serverUDPPacket struct { diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go index 9f546400..4a11d671 100644 --- a/transport/tuic/v5/packet.go +++ b/transport/tuic/v5/packet.go @@ -4,9 +4,9 @@ import ( "errors" "net" "sync" - "sync/atomic" "time" + "github.com/Dreamacro/clash/common/atomic" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/transport/tuic/common" diff --git a/transport/tuic/v5/protocol.go b/transport/tuic/v5/protocol.go index dc7062ea..83b44146 100644 --- a/transport/tuic/v5/protocol.go +++ b/transport/tuic/v5/protocol.go @@ -35,6 +35,8 @@ const ( HeartbeatType = CommandType(0x04) ) +const VER byte = 0x05 + func (c CommandType) String() string { switch c { case AuthenticateType: @@ -63,7 +65,7 @@ type CommandHead struct { func NewCommandHead(TYPE CommandType) CommandHead { return CommandHead{ - VER: 0x05, + VER: VER, TYPE: TYPE, } } diff --git a/transport/tuic/v5/server.go b/transport/tuic/v5/server.go index 7b21ee6c..96b3d24f 100644 --- a/transport/tuic/v5/server.go +++ b/transport/tuic/v5/server.go @@ -3,18 +3,13 @@ package v5 import ( "bufio" "bytes" - "context" - "crypto/tls" "fmt" - "net" "sync" - "sync/atomic" - "time" "github.com/Dreamacro/clash/adapter/inbound" + "github.com/Dreamacro/clash/common/atomic" N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/tuic/common" @@ -27,123 +22,72 @@ type ServerOption struct { HandleTcpFn func(conn net.Conn, addr socks5.Addr, additions ...inbound.Addition) error HandleUdpFn func(addr socks5.Addr, packet C.UDPPacket, additions ...inbound.Addition) error - TlsConfig *tls.Config - QuicConfig *quic.Config Users map[[16]byte]string - CongestionController string - AuthenticationTimeout time.Duration MaxUdpRelayPacketSize int - CWND int } -type Server struct { - *ServerOption - listener *quic.EarlyListener -} - -func NewServer(option *ServerOption, pc net.PacketConn) (*Server, error) { - listener, err := quic.ListenEarly(pc, option.TlsConfig, option.QuicConfig) - if err != nil { - return nil, err - } - return &Server{ +func NewServerHandler(option *ServerOption, quicConn quic.EarlyConnection, uuid uuid.UUID) common.ServerHandler { + return &serverHandler{ ServerOption: option, - listener: listener, - }, err -} - -func (s *Server) Serve() error { - for { - conn, err := s.listener.Accept(context.Background()) - if err != nil { - return err - } - common.SetCongestionController(conn, s.CongestionController, s.CWND) - h := &serverHandler{ - Server: s, - quicConn: conn, - uuid: utils.NewUUIDV4(), - authCh: make(chan struct{}), - } - go h.handle() + quicConn: quicConn, + uuid: uuid, + authCh: make(chan struct{}), } } -func (s *Server) Close() error { - return s.listener.Close() -} - type serverHandler struct { - *Server + *ServerOption quicConn quic.EarlyConnection uuid uuid.UUID authCh chan struct{} - authOk bool - authUUID string + authOk atomic.Bool + authUUID atomic.TypedValue[string] authOnce sync.Once udpInputMap sync.Map } -func (s *serverHandler) handle() { - go func() { - _ = s.handleUniStream() - }() - go func() { - _ = s.handleStream() - }() - go func() { - _ = s.handleMessage() - }() +func (s *serverHandler) AuthOk() bool { + return s.authOk.Load() +} - <-s.quicConn.HandshakeComplete() - time.AfterFunc(s.AuthenticationTimeout, func() { - s.authOnce.Do(func() { - _ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout") - s.authOk = false - close(s.authCh) - }) +func (s *serverHandler) HandleTimeout() { + s.authOnce.Do(func() { + _ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout") + s.authOk.Store(false) + close(s.authCh) }) } -func (s *serverHandler) handleMessage() (err error) { - for { - var message []byte - message, err = s.quicConn.ReceiveMessage() - if err != nil { - return err - } - go func() (err error) { - reader := bytes.NewBuffer(message) - commandHead, err := ReadCommandHead(reader) - if err != nil { - return - } - switch commandHead.TYPE { - case PacketType: - var packet Packet - packet, err = ReadPacketWithHead(commandHead, reader) - if err != nil { - return - } - return s.parsePacket(packet, common.NATIVE) - case HeartbeatType: - var heartbeat Heartbeat - heartbeat, err = ReadHeartbeatWithHead(commandHead, reader) - if err != nil { - return - } - heartbeat.BytesLen() - } - return - }() +func (s *serverHandler) HandleMessage(message []byte) (err error) { + reader := bytes.NewBuffer(message) + commandHead, err := ReadCommandHead(reader) + if err != nil { + return } + switch commandHead.TYPE { + case PacketType: + var packet Packet + packet, err = ReadPacketWithHead(commandHead, reader) + if err != nil { + return + } + return s.parsePacket(packet, common.NATIVE) + case HeartbeatType: + var heartbeat Heartbeat + heartbeat, err = ReadHeartbeatWithHead(commandHead, reader) + if err != nil { + return + } + heartbeat.BytesLen() + } + return } func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayMode) (err error) { <-s.authCh - if !s.authOk { + if !s.authOk.Load() { return } var assocId uint16 @@ -175,108 +119,79 @@ func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayM pc: pc, packet: packetPtr, rAddr: N.NewCustomAddr("tuic", fmt.Sprintf("tuic-%s-%d", s.uuid, assocId), s.quicConn.RemoteAddr()), // for tunnel's handleUDPConn - }, inbound.WithInUser(s.authUUID)) + }, inbound.WithInUser(s.authUUID.Load())) } -func (s *serverHandler) handleStream() (err error) { - for { - var quicStream quic.Stream - quicStream, err = s.quicConn.AcceptStream(context.Background()) - if err != nil { - return err - } - go func() (err error) { - stream := common.NewQuicStreamConn( - quicStream, - s.quicConn.LocalAddr(), - s.quicConn.RemoteAddr(), - nil, - ) - conn := N.NewBufferedConn(stream) - connect, err := ReadConnect(conn) - if err != nil { - return err - } - <-s.authCh - if !s.authOk { - return conn.Close() - } - - err = s.HandleTcpFn(conn, connect.ADDR.SocksAddr(), inbound.WithInUser(s.authUUID)) - if err != nil { - _ = conn.Close() - return err - } - return - }() +func (s *serverHandler) HandleStream(conn *N.BufferedConn) (err error) { + connect, err := ReadConnect(conn) + if err != nil { + return err } + <-s.authCh + if !s.authOk.Load() { + return conn.Close() + } + + err = s.HandleTcpFn(conn, connect.ADDR.SocksAddr(), inbound.WithInUser(s.authUUID.Load())) + if err != nil { + _ = conn.Close() + return err + } + return } -func (s *serverHandler) handleUniStream() (err error) { - for { - var stream quic.ReceiveStream - stream, err = s.quicConn.AcceptUniStream(context.Background()) +func (s *serverHandler) HandleUniStream(reader *bufio.Reader) (err error) { + commandHead, err := ReadCommandHead(reader) + if err != nil { + return + } + switch commandHead.TYPE { + case AuthenticateType: + var authenticate Authenticate + authenticate, err = ReadAuthenticateWithHead(commandHead, reader) if err != nil { - return err + return } - go func() (err error) { - defer func() { - stream.CancelRead(0) - }() - reader := bufio.NewReader(stream) - commandHead, err := ReadCommandHead(reader) + authOk := false + var authUUID uuid.UUID + var token [32]byte + if password, ok := s.Users[authenticate.UUID]; ok { + token, err = GenToken(s.quicConn.ConnectionState(), authenticate.UUID, password) if err != nil { return } - switch commandHead.TYPE { - case AuthenticateType: - var authenticate Authenticate - authenticate, err = ReadAuthenticateWithHead(commandHead, reader) - if err != nil { - return - } - authOk := false - var authUUID uuid.UUID - var token [32]byte - if password, ok := s.Users[authenticate.UUID]; ok { - token, err = GenToken(s.quicConn.ConnectionState(), authenticate.UUID, password) - if err != nil { - return - } - if token == authenticate.TOKEN { - authOk = true - authUUID = authenticate.UUID - } - } - s.authOnce.Do(func() { - if !authOk { - _ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed") - } - s.authOk = authOk - s.authUUID = authUUID.String() - close(s.authCh) - }) - case PacketType: - var packet Packet - packet, err = ReadPacketWithHead(commandHead, reader) - if err != nil { - return - } - return s.parsePacket(packet, common.QUIC) - case DissociateType: - var disassociate Dissociate - disassociate, err = ReadDissociateWithHead(commandHead, reader) - if err != nil { - return - } - if v, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded { - input := v.(*serverUDPInput) - input.writeClosed.Store(true) - } + if token == authenticate.TOKEN { + authOk = true + authUUID = authenticate.UUID } + } + s.authOnce.Do(func() { + if !authOk { + _ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed") + } + s.authOk.Store(authOk) + s.authUUID.Store(authUUID.String()) + close(s.authCh) + }) + case PacketType: + var packet Packet + packet, err = ReadPacketWithHead(commandHead, reader) + if err != nil { return - }() + } + return s.parsePacket(packet, common.QUIC) + case DissociateType: + var disassociate Dissociate + disassociate, err = ReadDissociateWithHead(commandHead, reader) + if err != nil { + return + } + if v, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded { + input := v.(*serverUDPInput) + input.writeClosed.Store(true) + } } + return } type serverUDPInput struct { From 919daf0dbb7cf3b50b725384f8d6102f317426fe Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 21 Jun 2023 14:00:49 +0800 Subject: [PATCH 41/79] fix: tuic server cwnd parsing --- config/config.go | 2 ++ hub/route/configs.go | 4 ++++ listener/inbound/tuic.go | 2 ++ 3 files changed, 8 insertions(+) diff --git a/config/config.go b/config/config.go index 0e161ddd..e2e96936 100644 --- a/config/config.go +++ b/config/config.go @@ -230,6 +230,7 @@ type RawTuicServer struct { AuthenticationTimeout int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"` ALPN []string `yaml:"alpn" json:"alpn,omitempty"` MaxUdpRelayPacketSize int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` + CWND int `yaml:"cwnd" json:"cwnd,omitempty"` } type RawConfig struct { @@ -1304,6 +1305,7 @@ func parseTuicServer(rawTuic RawTuicServer, general *General) error { AuthenticationTimeout: rawTuic.AuthenticationTimeout, ALPN: rawTuic.ALPN, MaxUdpRelayPacketSize: rawTuic.MaxUdpRelayPacketSize, + CWND: rawTuic.CWND, } return nil } diff --git a/hub/route/configs.go b/hub/route/configs.go index a8c24f90..cb7c93f6 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -95,6 +95,7 @@ type tuicServerSchema struct { AuthenticationTimeout *int `yaml:"authentication-timeout" json:"authentication-timeout,omitempty"` ALPN *[]string `yaml:"alpn" json:"alpn,omitempty"` MaxUdpRelayPacketSize *int `yaml:"max-udp-relay-packet-size" json:"max-udp-relay-packet-size,omitempty"` + CWND *int `yaml:"cwnd" json:"cwnd,omitempty"` } func getConfigs(w http.ResponseWriter, r *http.Request) { @@ -211,6 +212,9 @@ func pointerOrDefaultTuicServer(p *tuicServerSchema, def LC.TuicServer) LC.TuicS if p.MaxUdpRelayPacketSize != nil { def.MaxUdpRelayPacketSize = *p.MaxUdpRelayPacketSize } + if p.CWND != nil { + def.CWND = *p.CWND + } } return def } diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index 2e234e2d..bf448d31 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -18,6 +18,7 @@ type TuicOption struct { AuthenticationTimeout int `inbound:"authentication-timeout,omitempty"` ALPN []string `inbound:"alpn,omitempty"` MaxUdpRelayPacketSize int `inbound:"max-udp-relay-packet-size,omitempty"` + CWND int `inbound:"cwnd,omitempty"` } func (o TuicOption) Equal(config C.InboundConfig) bool { @@ -51,6 +52,7 @@ func NewTuic(options *TuicOption) (*Tuic, error) { AuthenticationTimeout: options.AuthenticationTimeout, ALPN: options.ALPN, MaxUdpRelayPacketSize: options.MaxUdpRelayPacketSize, + CWND: options.CWND, }, }, nil } From 2284acce9498fe0c588f6dcd0576c4cabe67367f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 26 Jun 2023 12:08:38 +0800 Subject: [PATCH 42/79] chore: update quic-go to 0.36.0 --- go.mod | 10 ++++----- go.sum | 27 +++++++++++------------ transport/hysteria/congestion/brutal.go | 4 ++-- transport/tuic/congestion/bbr_sender.go | 4 ++-- transport/tuic/congestion/cubic_sender.go | 4 ++-- 5 files changed, 24 insertions(+), 25 deletions(-) diff --git a/go.mod b/go.mod index f3b1f731..d3586419 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb + github.com/metacubex/quic-go v0.36.1-0.20230626040200-6396910a557f github.com/metacubex/sing-shadowsocks v0.2.2 github.com/metacubex/sing-shadowsocks2 v0.1.0 github.com/metacubex/sing-tun v0.1.5-0.20230618235243-65051e73b018 @@ -67,7 +67,7 @@ require ( github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/golang/mock v1.6.0 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect @@ -79,7 +79,7 @@ require ( github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect - github.com/onsi/ginkgo/v2 v2.2.0 // indirect + github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -100,10 +100,10 @@ require ( github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect - golang.org/x/mod v0.8.0 // indirect + golang.org/x/mod v0.10.0 // indirect golang.org/x/text v0.10.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.6.0 // indirect + golang.org/x/tools v0.9.1 // indirect ) replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b diff --git a/go.sum b/go.sum index 933c39bd..6992e575 100644 --- a/go.sum +++ b/go.sum @@ -41,17 +41,18 @@ github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg= github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -93,8 +94,8 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb h1:92YTNmYXCSycERjKn/zPbeK5DiW3dd80j3+oVTEWTE8= -github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb/go.mod h1:6pg8+Tje9KOltnj1whuvB2i5KFUMPp1TAF3oPhc5axM= +github.com/metacubex/quic-go v0.36.1-0.20230626040200-6396910a557f h1:w4SyW/AoLVvHN3YRiOU/Jb159r8fOBDiVA5e5XVLzM4= +github.com/metacubex/quic-go v0.36.1-0.20230626040200-6396910a557f/go.mod h1:mnMWBbeYt+xTvFQrAWu9IJH0h++EjnAS2B/aj+VEXzQ= github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b h1:mVd3v+zMQq61rJe/pJJSh0/Iin9UnkQaZTH2NOg/2Vg= github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/metacubex/sing-shadowsocks v0.2.2 h1:prciO78IwtR4Sp+/CnP+aZSzpBRfL7zKaYez1S4EOnI= @@ -113,9 +114,9 @@ github.com/mroth/weightedrand/v2 v2.0.1 h1:zrEVDIaau/E4QLOKu02kpg8T8myweFlMGikIg github.com/mroth/weightedrand/v2 v2.0.1/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= -github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= -github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= -github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0= github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= @@ -178,7 +179,6 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -218,8 +218,8 @@ golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnL golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= +golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -260,8 +260,8 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -271,7 +271,6 @@ google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cn google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 8f02ef14..9992f6a0 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -49,8 +49,8 @@ func (b *BrutalSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Ti return b.pacer.TimeUntilSend() } -func (b *BrutalSender) HasPacingBudget() bool { - return b.pacer.Budget(time.Now()) >= b.maxDatagramSize +func (b *BrutalSender) HasPacingBudget(now time.Time) bool { + return b.pacer.Budget(now) >= b.maxDatagramSize } func (b *BrutalSender) CanSend(bytesInFlight congestion.ByteCount) bool { diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index 17368386..e78819c7 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -293,8 +293,8 @@ func (b *bbrSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Time return b.pacer.TimeUntilSend() } -func (b *bbrSender) HasPacingBudget() bool { - return b.pacer.Budget(b.clock.Now()) >= b.maxDatagramSize +func (b *bbrSender) HasPacingBudget(now time.Time) bool { + return b.pacer.Budget(now) >= b.maxDatagramSize } func (b *bbrSender) SetMaxDatagramSize(s congestion.ByteCount) { diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go index c55db7bd..ca20b420 100644 --- a/transport/tuic/congestion/cubic_sender.go +++ b/transport/tuic/congestion/cubic_sender.go @@ -119,8 +119,8 @@ func (c *cubicSender) TimeUntilSend(_ congestion.ByteCount) time.Time { return c.pacer.TimeUntilSend() } -func (c *cubicSender) HasPacingBudget() bool { - return c.pacer.Budget(c.clock.Now()) >= c.maxDatagramSize +func (c *cubicSender) HasPacingBudget(now time.Time) bool { + return c.pacer.Budget(now) >= c.maxDatagramSize } func (c *cubicSender) maxCongestionWindow() congestion.ByteCount { From 42ef4fedfa583bbb0ef7a0d2fe9200930942dc31 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 26 Jun 2023 17:46:14 +0800 Subject: [PATCH 43/79] chore: avoid unneeded map copy when close connection in restful api --- adapter/provider/provider.go | 6 +++--- hub/route/connections.go | 18 +++++++++--------- tunnel/statistic/manager.go | 16 +++++++++++----- tunnel/statistic/tracker.go | 2 +- 4 files changed, 24 insertions(+), 18 deletions(-) diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 60fbb5f0..7a5f5853 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -147,15 +147,15 @@ func (pp *proxySetProvider) getSubscriptionInfo() { } func (pp *proxySetProvider) closeAllConnections() { - snapshot := statistic.DefaultManager.Snapshot() - for _, c := range snapshot.Connections { + statistic.DefaultManager.ConnectionsRange(func(c statistic.Tracker) bool { for _, chain := range c.Chains() { if chain == pp.Name() { _ = c.Close() break } } - } + return true + }) } func stopProxyProvider(pd *ProxySetProvider) { diff --git a/hub/route/connections.go b/hub/route/connections.go index bfe3b42d..927fdefd 100644 --- a/hub/route/connections.go +++ b/hub/route/connections.go @@ -73,20 +73,20 @@ func getConnections(w http.ResponseWriter, r *http.Request) { func closeConnection(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") - snapshot := statistic.DefaultManager.Snapshot() - for _, c := range snapshot.Connections { + statistic.DefaultManager.ConnectionsRange(func(c statistic.Tracker) bool { if id == c.ID() { - c.Close() - break + _ = c.Close() + return false } - } + return true + }) render.NoContent(w, r) } func closeAllConnections(w http.ResponseWriter, r *http.Request) { - snapshot := statistic.DefaultManager.Snapshot() - for _, c := range snapshot.Connections { - c.Close() - } + statistic.DefaultManager.ConnectionsRange(func(c statistic.Tracker) bool { + _ = c.Close() + return true + }) render.NoContent(w, r) } diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index ba2e1298..8218472c 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -38,11 +38,11 @@ type Manager struct { memory uint64 } -func (m *Manager) Join(c tracker) { +func (m *Manager) Join(c Tracker) { m.connections.Store(c.ID(), c) } -func (m *Manager) Leave(c tracker) { +func (m *Manager) Leave(c Tracker) { m.connections.Delete(c.ID()) } @@ -66,9 +66,9 @@ func (m *Manager) Memory() uint64 { } func (m *Manager) Snapshot() *Snapshot { - connections := []tracker{} + connections := []Tracker{} m.connections.Range(func(key, value any) bool { - connections = append(connections, value.(tracker)) + connections = append(connections, value.(Tracker)) return true }) return &Snapshot{ @@ -79,6 +79,12 @@ func (m *Manager) Snapshot() *Snapshot { } } +func (m *Manager) ConnectionsRange(f func(c Tracker) bool) { + m.connections.Range(func(key, value any) bool { + return f(value.(Tracker)) + }) +} + func (m *Manager) updateMemory() { stat, err := m.process.MemoryInfo() if err != nil { @@ -110,6 +116,6 @@ func (m *Manager) handle() { type Snapshot struct { DownloadTotal int64 `json:"downloadTotal"` UploadTotal int64 `json:"uploadTotal"` - Connections []tracker `json:"connections"` + Connections []Tracker `json:"connections"` Memory uint64 `json:"memory"` } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index a2a921ac..332be13d 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -15,7 +15,7 @@ import ( "github.com/gofrs/uuid/v5" ) -type tracker interface { +type Tracker interface { ID() string Close() error C.Connection From 1cb75350e2dc5d7ba83d54e836eb9a6992a10fa9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 26 Jun 2023 18:13:17 +0800 Subject: [PATCH 44/79] chore: statistic's Snapshot only contains TrackerInfo --- tunnel/statistic/manager.go | 10 +++++----- tunnel/statistic/tracker.go | 27 ++++++++++++++++++--------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 8218472c..575649f5 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -66,9 +66,9 @@ func (m *Manager) Memory() uint64 { } func (m *Manager) Snapshot() *Snapshot { - connections := []Tracker{} + var connections []*TrackerInfo m.connections.Range(func(key, value any) bool { - connections = append(connections, value.(Tracker)) + connections = append(connections, value.(Tracker).Info()) return true }) return &Snapshot{ @@ -114,8 +114,8 @@ func (m *Manager) handle() { } type Snapshot struct { - DownloadTotal int64 `json:"downloadTotal"` - UploadTotal int64 `json:"uploadTotal"` - Connections []Tracker `json:"connections"` + DownloadTotal int64 `json:"downloadTotal"` + UploadTotal int64 `json:"uploadTotal"` + Connections []*TrackerInfo `json:"connections"` Memory uint64 `json:"memory"` } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 332be13d..f0f868de 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -18,10 +18,11 @@ import ( type Tracker interface { ID() string Close() error + Info() *TrackerInfo C.Connection } -type trackerInfo struct { +type TrackerInfo struct { UUID uuid.UUID `json:"id"` Metadata *C.Metadata `json:"metadata"` UploadTotal *atomic.Int64 `json:"upload"` @@ -34,7 +35,7 @@ type trackerInfo struct { type tcpTracker struct { C.Conn `json:"-"` - *trackerInfo + *TrackerInfo manager *Manager pushToManager bool `json:"-"` @@ -44,6 +45,10 @@ func (tt *tcpTracker) ID() string { return tt.UUID.String() } +func (tt *tcpTracker) Info() *TrackerInfo { + return tt.TrackerInfo +} + func (tt *tcpTracker) Read(b []byte) (int, error) { n, err := tt.Conn.Read(b) download := int64(n) @@ -134,7 +139,7 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R t := &tcpTracker{ Conn: conn, manager: manager, - trackerInfo: &trackerInfo{ + TrackerInfo: &TrackerInfo{ UUID: utils.NewUUIDV4(), Start: time.Now(), Metadata: metadata, @@ -156,8 +161,8 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R } if rule != nil { - t.trackerInfo.Rule = rule.RuleType().String() - t.trackerInfo.RulePayload = rule.Payload() + t.TrackerInfo.Rule = rule.RuleType().String() + t.TrackerInfo.RulePayload = rule.Payload() } manager.Join(t) @@ -166,7 +171,7 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R type udpTracker struct { C.PacketConn `json:"-"` - *trackerInfo + *TrackerInfo manager *Manager pushToManager bool `json:"-"` @@ -176,6 +181,10 @@ func (ut *udpTracker) ID() string { return ut.UUID.String() } +func (ut *udpTracker) Info() *TrackerInfo { + return ut.TrackerInfo +} + func (ut *udpTracker) ReadFrom(b []byte) (int, net.Addr, error) { n, addr, err := ut.PacketConn.ReadFrom(b) download := int64(n) @@ -221,7 +230,7 @@ func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, ru ut := &udpTracker{ PacketConn: conn, manager: manager, - trackerInfo: &trackerInfo{ + TrackerInfo: &TrackerInfo{ UUID: utils.NewUUIDV4(), Start: time.Now(), Metadata: metadata, @@ -243,8 +252,8 @@ func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, ru } if rule != nil { - ut.trackerInfo.Rule = rule.RuleType().String() - ut.trackerInfo.RulePayload = rule.Payload() + ut.TrackerInfo.Rule = rule.RuleType().String() + ut.TrackerInfo.RulePayload = rule.Payload() } manager.Join(ut) From 614cc93cacf496b05ea9f514cf3cb5fff42c8e7f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 26 Jun 2023 18:25:36 +0800 Subject: [PATCH 45/79] chore: better close single connection in restful api --- adapter/provider/provider.go | 2 +- hub/route/connections.go | 12 ++++-------- tunnel/statistic/manager.go | 25 ++++++++++++++++--------- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 7a5f5853..10861217 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -147,7 +147,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() { } func (pp *proxySetProvider) closeAllConnections() { - statistic.DefaultManager.ConnectionsRange(func(c statistic.Tracker) bool { + statistic.DefaultManager.Range(func(c statistic.Tracker) bool { for _, chain := range c.Chains() { if chain == pp.Name() { _ = c.Close() diff --git a/hub/route/connections.go b/hub/route/connections.go index 927fdefd..b123ecae 100644 --- a/hub/route/connections.go +++ b/hub/route/connections.go @@ -73,18 +73,14 @@ func getConnections(w http.ResponseWriter, r *http.Request) { func closeConnection(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") - statistic.DefaultManager.ConnectionsRange(func(c statistic.Tracker) bool { - if id == c.ID() { - _ = c.Close() - return false - } - return true - }) + if c := statistic.DefaultManager.Get(id); c != nil { + _ = c.Close() + } render.NoContent(w, r) } func closeAllConnections(w http.ResponseWriter, r *http.Request) { - statistic.DefaultManager.ConnectionsRange(func(c statistic.Tracker) bool { + statistic.DefaultManager.Range(func(c statistic.Tracker) bool { _ = c.Close() return true }) diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 575649f5..2358d0bd 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -46,6 +46,19 @@ func (m *Manager) Leave(c Tracker) { m.connections.Delete(c.ID()) } +func (m *Manager) Get(id string) (c Tracker) { + if value, ok := m.connections.Load(id); ok { + c = value.(Tracker) + } + return +} + +func (m *Manager) Range(f func(c Tracker) bool) { + m.connections.Range(func(key, value any) bool { + return f(value.(Tracker)) + }) +} + func (m *Manager) PushUploaded(size int64) { m.uploadTemp.Add(size) m.uploadTotal.Add(size) @@ -67,8 +80,8 @@ func (m *Manager) Memory() uint64 { func (m *Manager) Snapshot() *Snapshot { var connections []*TrackerInfo - m.connections.Range(func(key, value any) bool { - connections = append(connections, value.(Tracker).Info()) + m.Range(func(c Tracker) bool { + connections = append(connections, c.Info()) return true }) return &Snapshot{ @@ -79,12 +92,6 @@ func (m *Manager) Snapshot() *Snapshot { } } -func (m *Manager) ConnectionsRange(f func(c Tracker) bool) { - m.connections.Range(func(key, value any) bool { - return f(value.(Tracker)) - }) -} - func (m *Manager) updateMemory() { stat, err := m.process.MemoryInfo() if err != nil { @@ -117,5 +124,5 @@ type Snapshot struct { DownloadTotal int64 `json:"downloadTotal"` UploadTotal int64 `json:"uploadTotal"` Connections []*TrackerInfo `json:"connections"` - Memory uint64 `json:"memory"` + Memory uint64 `json:"memory"` } From 603d0809b408ada1d08d373836da556dd96b8a5b Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 26 Jun 2023 21:04:26 +0800 Subject: [PATCH 46/79] fix: panic when add 4in6 ipcidr --- component/trie/ipcidr_trie.go | 34 ++++++++++++---------------------- component/trie/trie_test.go | 11 +++++++++-- 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/component/trie/ipcidr_trie.go b/component/trie/ipcidr_trie.go index a3a63f95..08edbbeb 100644 --- a/component/trie/ipcidr_trie.go +++ b/component/trie/ipcidr_trie.go @@ -1,8 +1,9 @@ package trie import ( - "github.com/Dreamacro/clash/log" "net" + + "github.com/Dreamacro/clash/log" ) type IPV6 bool @@ -47,11 +48,10 @@ func (trie *IpCidrTrie) AddIpCidrForString(ipCidr string) error { } func (trie *IpCidrTrie) IsContain(ip net.IP) bool { - ip, isIpv4 := checkAndConverterIp(ip) if ip == nil { return false } - + isIpv4 := len(ip) == net.IPv4len var groupValues []uint32 var ipCidrNode *IpCidrNode @@ -71,7 +71,13 @@ func (trie *IpCidrTrie) IsContain(ip net.IP) bool { } func (trie *IpCidrTrie) IsContainForString(ipString string) bool { - return trie.IsContain(net.ParseIP(ipString)) + ip := net.ParseIP(ipString) + // deal with 4in6 + actualIp := ip.To4() + if actualIp == nil { + actualIp = ip + } + return trie.IsContain(actualIp) } func ipCidrToSubIpCidr(ipNet *net.IPNet) ([]net.IP, int, bool, error) { @@ -82,9 +88,8 @@ func ipCidrToSubIpCidr(ipNet *net.IPNet) ([]net.IP, int, bool, error) { isIpv4 bool err error ) - - ip, isIpv4 := checkAndConverterIp(ipNet.IP) - ipList, newMaskSize, err = subIpCidr(ip, maskSize, isIpv4) + isIpv4 = len(ipNet.IP) == net.IPv4len + ipList, newMaskSize, err = subIpCidr(ipNet.IP, maskSize, isIpv4) return ipList, newMaskSize, isIpv4, err } @@ -238,18 +243,3 @@ func search(root *IpCidrNode, groupValues []uint32) *IpCidrNode { return nil } - -// return net.IP To4 or To16 and is ipv4 -func checkAndConverterIp(ip net.IP) (net.IP, bool) { - ipResult := ip.To4() - if ipResult == nil { - ipResult = ip.To16() - if ipResult == nil { - return nil, false - } - - return ipResult, false - } - - return ipResult, true -} diff --git a/component/trie/trie_test.go b/component/trie/trie_test.go index dca77c05..e1b20103 100644 --- a/component/trie/trie_test.go +++ b/component/trie/trie_test.go @@ -3,8 +3,9 @@ package trie import ( "net" "testing" + + "github.com/stretchr/testify/assert" ) -import "github.com/stretchr/testify/assert" func TestIpv4AddSuccess(t *testing.T) { trie := NewIpCidrTrie() @@ -96,5 +97,11 @@ func TestIpv6Search(t *testing.T) { assert.Equal(t, true, trie.IsContainForString("2001:67c:4e8:9666::1213")) assert.Equal(t, false, trie.IsContain(net.ParseIP("22233:22"))) - +} + +func TestIpv4InIpv6(t *testing.T) { + trie := NewIpCidrTrie() + + // Boundary testing + assert.NoError(t, trie.AddIpCidrForString("::ffff:198.18.5.138/128")) } From db6b2b77027a3b0433912502c7ae7b71d64e7b3e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 28 Jun 2023 09:17:40 +0800 Subject: [PATCH 47/79] chore: better resolv.conf parsing --- dns/system_posix.go | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/dns/system_posix.go b/dns/system_posix.go index d486b4fb..4d07d4ec 100644 --- a/dns/system_posix.go +++ b/dns/system_posix.go @@ -3,25 +3,41 @@ package dns import ( + "bufio" "fmt" + "net/netip" "os" - "regexp" + "strings" ) -var ( - // nameserver xxx.xxx.xxx.xxx - nameserverPattern = regexp.MustCompile(`nameserver\s+(?P\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`) -) +const resolvConf = "/etc/resolv.conf" func dnsReadConfig() (servers []string, err error) { - content, err := os.ReadFile("/etc/resolv.conf") + file, err := os.Open(resolvConf) if err != nil { - err = fmt.Errorf("failed to read /etc/resolv.conf: %w", err) + err = fmt.Errorf("failed to read %s: %w", resolvConf, err) return } - for _, line := range nameserverPattern.FindAllStringSubmatch(string(content), -1) { - addr := line[1] - servers = append(servers, addr) + defer func() { _ = file.Close() }() + scanner := bufio.NewScanner(file) + for scanner.Scan() { + line := scanner.Text() + if len(line) > 0 && (line[0] == ';' || line[0] == '#') { + // comment. + continue + } + f := strings.Fields(line) + if len(f) < 1 { + continue + } + switch f[0] { + case "nameserver": // add one name server + if len(f) > 1 { + if addr, err := netip.ParseAddr(f[1]); err == nil { + servers = append(servers, addr.String()) + } + } + } } return } From 8e16738465b04a0a53e0c16c8374a3e5930079b8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 29 Jun 2023 16:40:08 +0800 Subject: [PATCH 48/79] chore: better env parsing --- constant/path.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/constant/path.go b/constant/path.go index 897dcfdc..10d143d7 100644 --- a/constant/path.go +++ b/constant/path.go @@ -6,6 +6,7 @@ import ( "os" P "path" "path/filepath" + "strconv" "strings" ) @@ -22,7 +23,7 @@ var Path = func() *path { if err != nil { homeDir, _ = os.Getwd() } - allowUnsafePath := strings.TrimSpace(os.Getenv("SKIP_SAFE_PATH_CHECK")) == "1" + allowUnsafePath, _ := strconv.ParseBool(os.Getenv("SKIP_SAFE_PATH_CHECK")) homeDir = P.Join(homeDir, ".config", Name) return &path{homeDir: homeDir, configFile: "config.yaml", allowUnsafePath: allowUnsafePath} }() From 57db8dfe239d056c7f0020549218fb7ac201aa1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=BF=E3=82=A4=E3=83=A0=E3=83=A9=E3=82=A4=E3=83=B3?= <53483352+Nep-Timeline@users.noreply.github.com> Date: Fri, 30 Jun 2023 17:36:43 +0800 Subject: [PATCH 49/79] Chore: Something update from clash (#639) Chore: add alive for proxy api Improve: alloc using make if alloc size > 65536 --- adapter/adapter.go | 1 + common/pool/alloc.go | 25 +++++++++++++++++-------- common/pool/alloc_test.go | 6 +++--- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 32b6bae0..20de5f29 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -176,6 +176,7 @@ func (p *Proxy) MarshalJSON() ([]byte, error) { _ = json.Unmarshal(inner, &mapping) mapping["history"] = p.DelayHistory() mapping["extra"] = p.ExtraDelayHistory() + mapping["alive"] = p.Alive() mapping["name"] = p.Name() mapping["udp"] = p.SupportUDP() mapping["xudp"] = p.SupportXUDP() diff --git a/common/pool/alloc.go b/common/pool/alloc.go index 25f79897..5722b047 100644 --- a/common/pool/alloc.go +++ b/common/pool/alloc.go @@ -32,23 +32,32 @@ func NewAllocator() *Allocator { // Get a []byte from pool with most appropriate cap func (alloc *Allocator) Get(size int) []byte { - if size <= 0 || size > 65536 { + switch { + case size < 0: + panic("alloc.Get: len out of range") + case size == 0: return nil - } + case size > 65536: + return make([]byte, size) + default: + bits := msb(size) + if size == 1< 65536 { + return nil + } + bits := msb(cap(buf)) - if cap(buf) == 0 || cap(buf) > 65536 || cap(buf) != 1< Date: Fri, 30 Jun 2023 02:38:50 -0700 Subject: [PATCH 50/79] chore: change geodata download url to fastly.jsdelivr.net (#636) --- config/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index e2e96936..ae2ebbde 100644 --- a/config/config.go +++ b/config/config.go @@ -419,9 +419,9 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { StoreSelected: true, }, GeoXUrl: RawGeoXUrl{ - Mmdb: "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/country.mmdb", - GeoIp: "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat", - GeoSite: "https://testingcf.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat", + Mmdb: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/country.mmdb", + GeoIp: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat", + GeoSite: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat", }, } From c6b84b0f20b634e60ea00e0b5d1b6e0623205d3a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 2 Jul 2023 09:05:16 +0800 Subject: [PATCH 51/79] chore: update quic-go to 0.36.1 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d3586419..7f22b51f 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.36.1-0.20230626040200-6396910a557f + github.com/metacubex/quic-go v0.36.2-0.20230702005921-2ded1deb0eed github.com/metacubex/sing-shadowsocks v0.2.2 github.com/metacubex/sing-shadowsocks2 v0.1.0 github.com/metacubex/sing-tun v0.1.5-0.20230618235243-65051e73b018 diff --git a/go.sum b/go.sum index 6992e575..cc37ff70 100644 --- a/go.sum +++ b/go.sum @@ -94,8 +94,8 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.36.1-0.20230626040200-6396910a557f h1:w4SyW/AoLVvHN3YRiOU/Jb159r8fOBDiVA5e5XVLzM4= -github.com/metacubex/quic-go v0.36.1-0.20230626040200-6396910a557f/go.mod h1:mnMWBbeYt+xTvFQrAWu9IJH0h++EjnAS2B/aj+VEXzQ= +github.com/metacubex/quic-go v0.36.2-0.20230702005921-2ded1deb0eed h1:qciZMbuG8vlL6PIwBIayAiaiRPdcnr0SQOmd3/a0mto= +github.com/metacubex/quic-go v0.36.2-0.20230702005921-2ded1deb0eed/go.mod h1:mnMWBbeYt+xTvFQrAWu9IJH0h++EjnAS2B/aj+VEXzQ= github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b h1:mVd3v+zMQq61rJe/pJJSh0/Iin9UnkQaZTH2NOg/2Vg= github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/metacubex/sing-shadowsocks v0.2.2 h1:prciO78IwtR4Sp+/CnP+aZSzpBRfL7zKaYez1S4EOnI= From 8f1475d5d07c20a10a1c4e1cb8724940821478d7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 2 Jul 2023 09:59:18 +0800 Subject: [PATCH 52/79] chore: update to go1.21rc2, drop support for go1.19 --- .github/workflows/build.yml | 2 +- adapter/provider/provider.go | 2 +- common/utils/string_unsafe.go | 40 +++++-------------------------- component/dialer/control.go | 17 +++++++++++++ component/dialer/control_go119.go | 22 ----------------- component/dialer/control_go120.go | 26 -------------------- component/dialer/dialer.go | 7 +++--- component/dialer/error.go | 8 ------- component/iface/iface.go | 4 +--- dns/util.go | 2 +- go.mod | 9 ++++--- go.sum | 14 +++++------ rules/common/port.go | 2 +- rules/common/uid.go | 2 +- transport/hysteria/core/client.go | 2 +- transport/tuic/server.go | 2 +- transport/tuic/v4/client.go | 2 +- transport/tuic/v5/client.go | 2 +- 18 files changed, 47 insertions(+), 118 deletions(-) delete mode 100644 component/dialer/control_go119.go delete mode 100644 component/dialer/control_go120.go diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 26dc455b..1957e9bf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,7 +128,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.20" + go-version: "1.21.0-rc.2" check-latest: true - name: Test diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 10861217..d547dcb7 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -299,7 +299,7 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray if err := yaml.Unmarshal(buf, schema); err != nil { proxies, err1 := convert.ConvertsV2Ray(buf) if err1 != nil { - return nil, fmt.Errorf("%s, %w", err.Error(), err1) + return nil, fmt.Errorf("%w, %w", err, err1) } schema.Proxies = proxies } diff --git a/common/utils/string_unsafe.go b/common/utils/string_unsafe.go index 7733df39..e427d299 100644 --- a/common/utils/string_unsafe.go +++ b/common/utils/string_unsafe.go @@ -2,48 +2,20 @@ package utils import "unsafe" -// sliceHeader is equivalent to reflect.SliceHeader, but represents the pointer -// to the underlying array as unsafe.Pointer rather than uintptr, allowing -// sliceHeaders to be directly converted to slice objects. -type sliceHeader struct { - Data unsafe.Pointer - Len int - Cap int -} - -// slice returns a slice whose underlying array starts at ptr an which length -// and capacity are len. -func slice[T any](ptr *T, length int) []T { - var s []T - hdr := (*sliceHeader)(unsafe.Pointer(&s)) - hdr.Data = unsafe.Pointer(ptr) - hdr.Len = length - hdr.Cap = length - return s -} - -// stringHeader is equivalent to reflect.StringHeader, but represents the -// pointer to the underlying array as unsafe.Pointer rather than uintptr, -// allowing StringHeaders to be directly converted to strings. -type stringHeader struct { - Data unsafe.Pointer - Len int -} - // ImmutableBytesFromString is equivalent to []byte(s), except that it uses the // same memory backing s instead of making a heap-allocated copy. This is only // valid if the returned slice is never mutated. func ImmutableBytesFromString(s string) []byte { - shdr := (*stringHeader)(unsafe.Pointer(&s)) - return slice((*byte)(shdr.Data), shdr.Len) + b := unsafe.StringData(s) + return unsafe.Slice(b, len(s)) } // StringFromImmutableBytes is equivalent to string(bs), except that it uses // the same memory backing bs instead of making a heap-allocated copy. This is // only valid if bs is never mutated after StringFromImmutableBytes returns. func StringFromImmutableBytes(bs []byte) string { - // This is cheaper than messing with StringHeader and SliceHeader, which as - // of this writing produces many dead stores of zeroes. Compare - // strings.Builder.String(). - return *(*string)(unsafe.Pointer(&bs)) + if len(bs) == 0 { + return "" + } + return unsafe.String(&bs[0], len(bs)) } diff --git a/component/dialer/control.go b/component/dialer/control.go index 26b1db76..18ed84e4 100644 --- a/component/dialer/control.go +++ b/component/dialer/control.go @@ -20,3 +20,20 @@ func addControlToListenConfig(lc *net.ListenConfig, fn controlFn) { return fn(context.Background(), network, address, c) } } + +func addControlToDialer(d *net.Dialer, fn controlFn) { + ld := *d + d.ControlContext = func(ctx context.Context, network, address string, c syscall.RawConn) (err error) { + switch { + case ld.ControlContext != nil: + if err = ld.ControlContext(ctx, network, address, c); err != nil { + return + } + case ld.Control != nil: + if err = ld.Control(network, address, c); err != nil { + return + } + } + return fn(ctx, network, address, c) + } +} diff --git a/component/dialer/control_go119.go b/component/dialer/control_go119.go deleted file mode 100644 index ec980586..00000000 --- a/component/dialer/control_go119.go +++ /dev/null @@ -1,22 +0,0 @@ -//go:build !go1.20 - -package dialer - -import ( - "context" - "net" - "syscall" -) - -func addControlToDialer(d *net.Dialer, fn controlFn) { - ld := *d - d.Control = func(network, address string, c syscall.RawConn) (err error) { - switch { - case ld.Control != nil: - if err = ld.Control(network, address, c); err != nil { - return - } - } - return fn(context.Background(), network, address, c) - } -} diff --git a/component/dialer/control_go120.go b/component/dialer/control_go120.go deleted file mode 100644 index 65e33f9c..00000000 --- a/component/dialer/control_go120.go +++ /dev/null @@ -1,26 +0,0 @@ -//go:build go1.20 - -package dialer - -import ( - "context" - "net" - "syscall" -) - -func addControlToDialer(d *net.Dialer, fn controlFn) { - ld := *d - d.ControlContext = func(ctx context.Context, network, address string, c syscall.RawConn) (err error) { - switch { - case ld.ControlContext != nil: - if err = ld.ControlContext(ctx, network, address, c); err != nil { - return - } - case ld.Control != nil: - if err = ld.Control(network, address, c); err != nil { - return - } - } - return fn(ctx, network, address, c) - } -} diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 5a55cd22..5e19046c 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -2,6 +2,7 @@ package dialer import ( "context" + "errors" "fmt" "net" "net/netip" @@ -207,7 +208,7 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, if fallback.error == nil && fallback.Conn != nil { return fallback.Conn, nil } - return nil, errorsJoin(errs...) + return nil, errors.Join(errs...) } func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { @@ -244,7 +245,7 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, } if len(errs) > 0 { - return nil, errorsJoin(errs...) + return nil, errors.Join(errs...) } return nil, os.ErrDeadlineExceeded } @@ -261,7 +262,7 @@ func serialDialContext(ctx context.Context, network string, ips []netip.Addr, po errs = append(errs, err) } } - return nil, errorsJoin(errs...) + return nil, errors.Join(errs...) } type dialResult struct { diff --git a/component/dialer/error.go b/component/dialer/error.go index f2f6b4b7..035baa03 100644 --- a/component/dialer/error.go +++ b/component/dialer/error.go @@ -2,17 +2,9 @@ package dialer import ( "errors" - - E "github.com/sagernet/sing/common/exceptions" ) var ( ErrorNoIpAddress = errors.New("no ip address") ErrorInvalidedNetworkStack = errors.New("invalided network stack") ) - -func errorsJoin(errs ...error) error { - // compatibility with golang<1.20 - // maybe use errors.Join(errs...) is better after we drop the old version's support - return E.Errors(errs...) -} diff --git a/component/iface/iface.go b/component/iface/iface.go index dca6cca1..c32b65ab 100644 --- a/component/iface/iface.go +++ b/component/iface/iface.go @@ -24,8 +24,6 @@ var ( var interfaces = singledo.NewSingle[map[string]*Interface](time.Second * 20) -const FlagRunning = 32 // interface is in running state, compatibility with golang<1.20 - func ResolveInterface(name string) (*Interface, error) { value, err, _ := interfaces.Do(func() (map[string]*Interface, error) { ifaces, err := net.Interfaces() @@ -41,7 +39,7 @@ func ResolveInterface(name string) (*Interface, error) { continue } // if not available device like Meta, dummy0, docker0, etc. - if (iface.Flags&net.FlagMulticast == 0) || (iface.Flags&net.FlagPointToPoint != 0) || (iface.Flags&FlagRunning == 0) { + if (iface.Flags&net.FlagMulticast == 0) || (iface.Flags&net.FlagPointToPoint != 0) || (iface.Flags&net.FlagRunning == 0) { continue } diff --git a/dns/util.go b/dns/util.go index edd26a42..73d117b8 100644 --- a/dns/util.go +++ b/dns/util.go @@ -313,7 +313,7 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M if elm == nil { err := errors.New("all DNS requests failed") if fErr := fast.Error(); fErr != nil { - err = fmt.Errorf("%w, first error: %s", err, fErr.Error()) + err = fmt.Errorf("%w, first error: %w", err, fErr) } return nil, true, err } diff --git a/go.mod b/go.mod index 7f22b51f..b9a855ab 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Dreamacro/clash -go 1.19 +go 1.20 require ( github.com/3andne/restls-client-go v0.1.4 @@ -20,7 +20,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.36.2-0.20230702005921-2ded1deb0eed + github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d github.com/metacubex/sing-shadowsocks v0.2.2 github.com/metacubex/sing-shadowsocks2 v0.1.0 github.com/metacubex/sing-tun v0.1.5-0.20230618235243-65051e73b018 @@ -85,8 +85,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect + github.com/quic-go/qtls-go1-20 v0.3.0 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect @@ -106,4 +105,4 @@ require ( golang.org/x/tools v0.9.1 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230702015813-e4a7ce9ea42c diff --git a/go.sum b/go.sum index cc37ff70..35f46b74 100644 --- a/go.sum +++ b/go.sum @@ -94,10 +94,10 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.36.2-0.20230702005921-2ded1deb0eed h1:qciZMbuG8vlL6PIwBIayAiaiRPdcnr0SQOmd3/a0mto= -github.com/metacubex/quic-go v0.36.2-0.20230702005921-2ded1deb0eed/go.mod h1:mnMWBbeYt+xTvFQrAWu9IJH0h++EjnAS2B/aj+VEXzQ= -github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b h1:mVd3v+zMQq61rJe/pJJSh0/Iin9UnkQaZTH2NOg/2Vg= -github.com/metacubex/sing v0.0.0-20230618234508-ce8816d0274b/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d h1:LCMD4JnahhgImBdfsGe0PAQiYNx2UlqvrGpYbZ0CVHs= +github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d/go.mod h1:runF6UZHW4A/P/VU+PtfQKKD85YgaZgrgbvCTs5Nwbk= +github.com/metacubex/sing v0.0.0-20230702015813-e4a7ce9ea42c h1:mdtRHbznkJGnjgJ/yLCRtX3oD9nfqTrJ/VkisTRbqNg= +github.com/metacubex/sing v0.0.0-20230702015813-e4a7ce9ea42c/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/metacubex/sing-shadowsocks v0.2.2 h1:prciO78IwtR4Sp+/CnP+aZSzpBRfL7zKaYez1S4EOnI= github.com/metacubex/sing-shadowsocks v0.2.2/go.mod h1:haolI+8Yc8MhNDqNuoRP4X5vaquXWNYeL1YxrQZ5kCU= github.com/metacubex/sing-shadowsocks2 v0.1.0 h1:ZxPEToY1RaRtG6ljz2n13ASMVqyAM7Bh11TmWoExYu4= @@ -136,10 +136,8 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/qtls-go1-20 v0.3.0 h1:NrCXmDl8BddZwO67vlvEpBTwT89bJfKYygxv4HQvuDk= +github.com/quic-go/qtls-go1-20 v0.3.0/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= diff --git a/rules/common/port.go b/rules/common/port.go index e3949f51..aeacc4dc 100644 --- a/rules/common/port.go +++ b/rules/common/port.go @@ -48,7 +48,7 @@ func (p *Port) matchPortReal(portRef string) bool { func NewPort(port string, adapter string, ruleType C.RuleType) (*Port, error) { portRanges, err := utils.NewIntRanges[uint16](port) if err != nil { - return nil, fmt.Errorf("%w, %s", errPayload, err.Error()) + return nil, fmt.Errorf("%w, %w", errPayload, err) } if len(portRanges) == 0 { diff --git a/rules/common/uid.go b/rules/common/uid.go index b191a55f..3b20928f 100644 --- a/rules/common/uid.go +++ b/rules/common/uid.go @@ -23,7 +23,7 @@ func NewUid(oUid, adapter string) (*Uid, error) { uidRange, err := utils.NewIntRanges[uint32](oUid) if err != nil { - return nil, fmt.Errorf("%w, %s", errPayload, err.Error()) + return nil, fmt.Errorf("%w, %w", errPayload, err) } if len(uidRange) == 0 { diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index e0f3a0dd..a219e76c 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -135,7 +135,7 @@ func (c *Client) handleControlStream(qs quic.Connection, stream quic.Stream) (bo func (c *Client) handleMessage(qs quic.Connection) { for { - msg, err := qs.ReceiveMessage() + msg, err := qs.ReceiveMessage(context.Background()) if err != nil { break } diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 47850107..a6f91b88 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -114,7 +114,7 @@ func (s *serverHandler) handle() { func (s *serverHandler) handleMessage() (err error) { for { var message []byte - message, err = s.quicConn.ReceiveMessage() + message, err = s.quicConn.ReceiveMessage(context.Background()) if err != nil { return err } diff --git a/transport/tuic/v4/client.go b/transport/tuic/v4/client.go index e1a334e5..fd3bf54a 100644 --- a/transport/tuic/v4/client.go +++ b/transport/tuic/v4/client.go @@ -196,7 +196,7 @@ func (t *clientImpl) handleMessage(quicConn quic.Connection) (err error) { }() for { var message []byte - message, err = quicConn.ReceiveMessage() + message, err = quicConn.ReceiveMessage(context.Background()) if err != nil { return err } diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go index cb1d538c..74dfd581 100644 --- a/transport/tuic/v5/client.go +++ b/transport/tuic/v5/client.go @@ -195,7 +195,7 @@ func (t *clientImpl) handleMessage(quicConn quic.Connection) (err error) { }() for { var message []byte - message, err = quicConn.ReceiveMessage() + message, err = quicConn.ReceiveMessage(context.Background()) if err != nil { return err } From 0b1aff575990ea5816cd24b64757b75dc7368db1 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 2 Jul 2023 10:41:02 +0800 Subject: [PATCH 53/79] chore: Update dependencies --- go.mod | 24 ++++++++++++------------ go.sum | 37 ++++++++++++++++++++++--------------- 2 files changed, 34 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index b9a855ab..648f567c 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/gofrs/uuid/v5 v5.0.0 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/golang-lru v0.5.4 - github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb + github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df github.com/jpillora/backoff v1.0.0 github.com/klauspost/cpuid/v2 v2.2.5 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 @@ -23,34 +23,34 @@ require ( github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d github.com/metacubex/sing-shadowsocks v0.2.2 github.com/metacubex/sing-shadowsocks2 v0.1.0 - github.com/metacubex/sing-tun v0.1.5-0.20230618235243-65051e73b018 + github.com/metacubex/sing-tun v0.1.8 github.com/metacubex/sing-vmess v0.1.5 github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 - github.com/miekg/dns v1.1.54 + github.com/miekg/dns v1.1.55 github.com/mroth/weightedrand/v2 v2.0.1 github.com/openacid/low v0.1.21 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.5 + github.com/sagernet/sing v0.2.7 github.com/sagernet/sing-mux v0.1.0 github.com/sagernet/sing-shadowtls v0.1.2 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 github.com/samber/lo v1.38.1 - github.com/shirou/gopsutil/v3 v3.23.5 - github.com/sirupsen/logrus v1.9.2 - github.com/stretchr/testify v1.8.3 + github.com/shirou/gopsutil/v3 v3.23.6 + github.com/sirupsen/logrus v1.9.3 + github.com/stretchr/testify v1.8.4 github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.10.0 - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 + golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df golang.org/x/net v0.11.0 - golang.org/x/sync v0.2.0 + golang.org/x/sync v0.3.0 golang.org/x/sys v0.9.0 - google.golang.org/protobuf v1.30.0 + google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 ) @@ -99,10 +99,10 @@ require ( github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect - golang.org/x/mod v0.10.0 // indirect + golang.org/x/mod v0.11.0 // indirect golang.org/x/text v0.10.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.9.1 // indirect + golang.org/x/tools v0.10.0 // indirect ) replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230702015813-e4a7ce9ea42c diff --git a/go.sum b/go.sum index 35f46b74..e635facc 100644 --- a/go.sum +++ b/go.sum @@ -71,6 +71,8 @@ github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbg github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb h1:6fDKEAXwe3rsfS4khW3EZ8kEqmSiV9szhMPcDrD+Y7Q= github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= +github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df h1:pF1MMIzEJzJ/MyI4bXYXVYyN8CJgoQ2PPKT2z3O/Cl4= +github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -102,14 +104,16 @@ github.com/metacubex/sing-shadowsocks v0.2.2 h1:prciO78IwtR4Sp+/CnP+aZSzpBRfL7zK github.com/metacubex/sing-shadowsocks v0.2.2/go.mod h1:haolI+8Yc8MhNDqNuoRP4X5vaquXWNYeL1YxrQZ5kCU= github.com/metacubex/sing-shadowsocks2 v0.1.0 h1:ZxPEToY1RaRtG6ljz2n13ASMVqyAM7Bh11TmWoExYu4= github.com/metacubex/sing-shadowsocks2 v0.1.0/go.mod h1:6C4EkvqMz5h7jECKrQeIByoLDHxiepsgPajIrxqxj/s= -github.com/metacubex/sing-tun v0.1.5-0.20230618235243-65051e73b018 h1:M7vBGA4RL4BBLSYfi15u/9QdVSqPkhuL4KRCuRhxuQY= -github.com/metacubex/sing-tun v0.1.5-0.20230618235243-65051e73b018/go.mod h1:DSVNjWT0rkkg8zn2+wpDvxgXuXRmMiNFDnVmnUctbAc= +github.com/metacubex/sing-tun v0.1.8 h1:NEtr46q9ZcI47NWuLpMpILOTJTmLqtSOxflyblll95I= +github.com/metacubex/sing-tun v0.1.8/go.mod h1:QPHW3t9RiuxIfeuO1Doj8O690HlLUzllVuqo87/Y+bI= github.com/metacubex/sing-vmess v0.1.5 h1:wODu17P27aGw0GhSIb/rIZWNh3/F5ghF/1PDDt95CQY= github.com/metacubex/sing-vmess v0.1.5/go.mod h1:s00xTd3c/zOMQHyPec0G/pbUklndleiH0QaHZRd4Ykg= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= +github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mroth/weightedrand/v2 v2.0.1 h1:zrEVDIaau/E4QLOKu02kpg8T8myweFlMGikIgbIdrRA= github.com/mroth/weightedrand/v2 v2.0.1/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= @@ -159,8 +163,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y= -github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY= +github.com/shirou/gopsutil/v3 v3.23.6 h1:5y46WPI9QBKBbK7EEccUPNXpJpNrvPuTD0O2zHEHT08= +github.com/shirou/gopsutil/v3 v3.23.6/go.mod h1:j7QX50DrXYggrpN30W0Mo+I4/8U2UUIQrnrhqUeWrAU= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -171,8 +175,8 @@ github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6y github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c/go.mod h1:NV/a66PhhWYVmUMaotlXJ8fIEFB98u+c8l/CQIEFLrU= github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIFG3i4Gi093BQITvwH9znsz2VUZmnmwHvpIo= github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8= -github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= -github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= @@ -181,8 +185,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= @@ -211,13 +215,13 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk= -golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= @@ -225,8 +229,8 @@ golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= 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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -244,7 +248,6 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= @@ -260,6 +263,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= +golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= +golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -267,6 +272,8 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= From 492a731ec165c48f376986a49adef795a056a5ac Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 14 Jul 2023 09:55:43 +0800 Subject: [PATCH 54/79] fix: DNS cache --- common/picker/picker.go | 12 ++++++++++++ dns/util.go | 18 ++++++++++-------- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/common/picker/picker.go b/common/picker/picker.go index 97004460..3a7688ca 100644 --- a/common/picker/picker.go +++ b/common/picker/picker.go @@ -47,6 +47,7 @@ func (p *Picker[T]) Wait() T { p.wg.Wait() if p.cancel != nil { p.cancel() + p.cancel = nil } return p.result } @@ -69,6 +70,7 @@ func (p *Picker[T]) Go(f func() (T, error)) { p.result = ret if p.cancel != nil { p.cancel() + p.cancel = nil } }) } else { @@ -78,3 +80,13 @@ func (p *Picker[T]) Go(f func() (T, error)) { } }() } + +// Close cancels the picker context and releases resources associated with it. +// If Wait has been called, then there is no need to call Close. +func (p *Picker[T]) Close() error { + if p.cancel != nil { + p.cancel() + p.cancel = nil + } + return nil +} diff --git a/dns/util.go b/dns/util.go index 73d117b8..739fd16b 100644 --- a/dns/util.go +++ b/dns/util.go @@ -288,12 +288,16 @@ func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName st } func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, cache bool, err error) { + cache = true fast, ctx := picker.WithTimeout[*D.Msg](ctx, resolver.DefaultDNSTimeout) + defer fast.Close() domain := msgToDomain(m) for _, client := range clients { + if _, isRCodeClient := client.(rcodeClient); isRCodeClient { + msg, err = client.Exchange(m) + return msg, false, err + } client := client // shadow define client to ensure the value captured by the closure will not be changed in the next loop - _, cache = client.(rcodeClient) - cache = !cache fast.Go(func() (*D.Msg, error) { log.Debugln("[DNS] resolve %s from %s", domain, client.Address()) m, err := client.ExchangeContext(ctx, m) @@ -302,21 +306,19 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M } else if cache && (m.Rcode == D.RcodeServerFailure || m.Rcode == D.RcodeRefused) { // currently, cache indicates whether this msg was from a RCode client, // so we would ignore RCode errors from RCode clients. - return nil, errors.New("server failure") + return nil, errors.New("server failure: " + D.RcodeToString[m.Rcode]) } log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), client.Address()) return m, nil }) } - elm := fast.Wait() - if elm == nil { - err := errors.New("all DNS requests failed") + msg = fast.Wait() + if msg == nil { + err = errors.New("all DNS requests failed") if fErr := fast.Error(); fErr != nil { err = fmt.Errorf("%w, first error: %w", err, fErr) } - return nil, true, err } - msg = elm return } From 5dd57bab6727dc3de990a0c3341ddd4ec6fd4c09 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 14 Jul 2023 11:37:15 +0800 Subject: [PATCH 55/79] chore: Update dependencies --- common/buf/sing.go | 2 - go.mod | 34 ++++++++--------- go.sum | 69 +++++++++++++++------------------- transport/vless/conn.go | 8 +--- transport/vless/vision/conn.go | 4 +- 5 files changed, 51 insertions(+), 66 deletions(-) diff --git a/common/buf/sing.go b/common/buf/sing.go index 93140887..4585bf74 100644 --- a/common/buf/sing.go +++ b/common/buf/sing.go @@ -11,8 +11,6 @@ type Buffer = buf.Buffer var New = buf.New var NewSize = buf.NewSize -var StackNew = buf.StackNew -var StackNewSize = buf.StackNewSize var With = buf.With var As = buf.As diff --git a/go.mod b/go.mod index 648f567c..d3206598 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/3andne/restls-client-go v0.1.4 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da - github.com/cilium/ebpf v0.10.0 + github.com/cilium/ebpf v0.11.0 github.com/coreos/go-iptables v0.6.0 github.com/dlclark/regexp2 v1.10.0 github.com/go-chi/chi/v5 v5.0.8 @@ -21,19 +21,19 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d - github.com/metacubex/sing-shadowsocks v0.2.2 - github.com/metacubex/sing-shadowsocks2 v0.1.0 - github.com/metacubex/sing-tun v0.1.8 - github.com/metacubex/sing-vmess v0.1.5 + github.com/metacubex/sing-shadowsocks v0.2.3-0.20230714014829-3669e0591014 + github.com/metacubex/sing-shadowsocks2 v0.1.1-0.20230714014119-27b8d12c6d0b + github.com/metacubex/sing-tun v0.1.9-0.20230714030349-b6aed664150f + github.com/metacubex/sing-vmess v0.1.5-0.20230713151521-79843393b710 github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 github.com/miekg/dns v1.1.55 github.com/mroth/weightedrand/v2 v2.0.1 github.com/openacid/low v0.1.21 - github.com/oschwald/geoip2-golang v1.8.0 + github.com/oschwald/geoip2-golang v1.9.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.7 - github.com/sagernet/sing-mux v0.1.0 - github.com/sagernet/sing-shadowtls v0.1.2 + github.com/sagernet/sing v0.2.8-0.20230703002104-c68251b6d059 + github.com/sagernet/sing-mux v0.1.1-0.20230703132253-2cedde0fbc90 + github.com/sagernet/sing-shadowtls v0.1.3-0.20230703132509-93bbad3057e4 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 @@ -45,11 +45,11 @@ require ( github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.2 - golang.org/x/crypto v0.10.0 - golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df - golang.org/x/net v0.11.0 + golang.org/x/crypto v0.11.0 + golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb + golang.org/x/net v0.12.0 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.9.0 + golang.org/x/sys v0.10.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 @@ -80,7 +80,7 @@ require ( github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect - github.com/oschwald/maxminddb-golang v1.10.0 // indirect + github.com/oschwald/maxminddb-golang v1.11.0 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect @@ -100,9 +100,9 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect golang.org/x/mod v0.11.0 // indirect - golang.org/x/text v0.10.0 // indirect + golang.org/x/text v0.11.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.10.0 // indirect + golang.org/x/tools v0.9.1 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230702015813-e4a7ce9ea42c +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7 diff --git a/go.sum b/go.sum index e635facc..77508629 100644 --- a/go.sum +++ b/go.sum @@ -14,8 +14,8 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ= -github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE= +github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= +github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -32,7 +32,7 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBE github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= @@ -69,8 +69,6 @@ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb h1:6fDKEAXwe3rsfS4khW3EZ8kEqmSiV9szhMPcDrD+Y7Q= -github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df h1:pF1MMIzEJzJ/MyI4bXYXVYyN8CJgoQ2PPKT2z3O/Cl4= github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -98,20 +96,18 @@ github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggF github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d h1:LCMD4JnahhgImBdfsGe0PAQiYNx2UlqvrGpYbZ0CVHs= github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d/go.mod h1:runF6UZHW4A/P/VU+PtfQKKD85YgaZgrgbvCTs5Nwbk= -github.com/metacubex/sing v0.0.0-20230702015813-e4a7ce9ea42c h1:mdtRHbznkJGnjgJ/yLCRtX3oD9nfqTrJ/VkisTRbqNg= -github.com/metacubex/sing v0.0.0-20230702015813-e4a7ce9ea42c/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/metacubex/sing-shadowsocks v0.2.2 h1:prciO78IwtR4Sp+/CnP+aZSzpBRfL7zKaYez1S4EOnI= -github.com/metacubex/sing-shadowsocks v0.2.2/go.mod h1:haolI+8Yc8MhNDqNuoRP4X5vaquXWNYeL1YxrQZ5kCU= -github.com/metacubex/sing-shadowsocks2 v0.1.0 h1:ZxPEToY1RaRtG6ljz2n13ASMVqyAM7Bh11TmWoExYu4= -github.com/metacubex/sing-shadowsocks2 v0.1.0/go.mod h1:6C4EkvqMz5h7jECKrQeIByoLDHxiepsgPajIrxqxj/s= -github.com/metacubex/sing-tun v0.1.8 h1:NEtr46q9ZcI47NWuLpMpILOTJTmLqtSOxflyblll95I= -github.com/metacubex/sing-tun v0.1.8/go.mod h1:QPHW3t9RiuxIfeuO1Doj8O690HlLUzllVuqo87/Y+bI= -github.com/metacubex/sing-vmess v0.1.5 h1:wODu17P27aGw0GhSIb/rIZWNh3/F5ghF/1PDDt95CQY= -github.com/metacubex/sing-vmess v0.1.5/go.mod h1:s00xTd3c/zOMQHyPec0G/pbUklndleiH0QaHZRd4Ykg= +github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7 h1:XY3Y6nPL45XuN/k3rDXJ1TJknLo8rTo1SVuDOmOEf4E= +github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/metacubex/sing-shadowsocks v0.2.3-0.20230714014829-3669e0591014 h1:KRMv2Q0Fa69chRsNr0RVTqh99POzYQi/OJ9p6FRcXfQ= +github.com/metacubex/sing-shadowsocks v0.2.3-0.20230714014829-3669e0591014/go.mod h1:UeQCECVevysZhVYeSs1w8dN2MLJrt9RVAC4qhdLorm0= +github.com/metacubex/sing-shadowsocks2 v0.1.1-0.20230714014119-27b8d12c6d0b h1:cTDNDaqSoSOfhepLfc05Tl6gMMnLDxUApc/RcCzfHwE= +github.com/metacubex/sing-shadowsocks2 v0.1.1-0.20230714014119-27b8d12c6d0b/go.mod h1:YC5UDPqtDifY0jed5iYYcp3RsSDtzv5fJ9wQYtRrCaU= +github.com/metacubex/sing-tun v0.1.9-0.20230714030349-b6aed664150f h1:IA7kBQN/ShhszhCMBDke1Y0fWnxnRBdHJR+gOTeOjZM= +github.com/metacubex/sing-tun v0.1.9-0.20230714030349-b6aed664150f/go.mod h1:yhMxm3aiwfc8HRv429QqO+8gWXMeCDQw/bh5CGKbCYM= +github.com/metacubex/sing-vmess v0.1.5-0.20230713151521-79843393b710 h1:8zXxMXgG5HaLG43RT1j1fsmDZTwhElaFk+Dj7wmdb9k= +github.com/metacubex/sing-vmess v0.1.5-0.20230713151521-79843393b710/go.mod h1:i20X8MiR+bordyMPhp16Swl7Rycr9qf+gkYQiUTMzsY= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= -github.com/miekg/dns v1.1.54 h1:5jon9mWcb0sFJGpnI99tOMhCPyJ+RPVz5b63MQG0VWI= -github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mroth/weightedrand/v2 v2.0.1 h1:zrEVDIaau/E4QLOKu02kpg8T8myweFlMGikIgbIdrRA= @@ -126,10 +122,10 @@ github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= github.com/openacid/must v0.1.3/go.mod h1:luPiXCuJlEo3UUFQngVQokV0MPGryeYvtCbQPs3U1+I= github.com/openacid/testkeys v0.1.6/go.mod h1:MfA7cACzBpbiwekivj8StqX0WIRmqlMsci1c37CA3Do= -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= -github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0= +github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= +github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= +github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0= +github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -147,10 +143,10 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= 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-mux v0.1.0 h1:xihlDRNs1J+hYwmvW9/ZmaghjDx7O0Y5dty0pOLQGB4= -github.com/sagernet/sing-mux v0.1.0/go.mod h1:i3jKjV4pRTFTV/ly5V3oa2JMPy0SAZ5X8X4tDU9Hw94= -github.com/sagernet/sing-shadowtls v0.1.2 h1:wkPf4gF+cmaP0cIbArpyq+mc6GcwbMx60CssmmhEQ0s= -github.com/sagernet/sing-shadowtls v0.1.2/go.mod h1:rTxhbSY8jGWZOWjdeOe1vP3E+hkgen8aRA2p7YccM88= +github.com/sagernet/sing-mux v0.1.1-0.20230703132253-2cedde0fbc90 h1:aEe2HrRc9OTS7IZ8RHyh224OhltnwRQs4/y89UsHPo8= +github.com/sagernet/sing-mux v0.1.1-0.20230703132253-2cedde0fbc90/go.mod h1:sm126rB5EUi9HLf4jCSHTqo+XRPbh4BoEVeLbr2WRbE= +github.com/sagernet/sing-shadowtls v0.1.3-0.20230703132509-93bbad3057e4 h1:ZjLyCkEENqXzGp4PRZbQGk5wPzEq0Rg+/2jK82lmy3Q= +github.com/sagernet/sing-shadowtls v0.1.3-0.20230703132509-93bbad3057e4/go.mod h1:8ZSSHJSNOG7cUCUYJemZNH873EsKdFqABykTypoS/2M= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= @@ -213,10 +209,10 @@ go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME= go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= 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.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= -golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/crypto v0.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= +golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= +golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -225,8 +221,8 @@ golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= +golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= 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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= @@ -248,13 +244,14 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= +golang.org/x/sys v0.10.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= -golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= -golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -263,15 +260,11 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= -golang.org/x/tools v0.10.0 h1:tvDr/iQoUqNdohiYm0LmmKcBk+q86lb9EprIUFhHHGg= -golang.org/x/tools v0.10.0/go.mod h1:UJwyiVBsOA2uwvK/e5OY3GTpDUJriEd+/YlqAwLPmyM= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/transport/vless/conn.go b/transport/vless/conn.go index fb514367..3a2a6755 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -109,9 +109,7 @@ func (vc *Conn) sendRequest(p []byte) bool { var buffer *buf.Buffer if vc.IsXTLSVisionEnabled() { - _buffer := buf.StackNew() - defer buf.KeepAlive(_buffer) - buffer = buf.Dup(_buffer) + buffer = buf.New() defer buffer.Release() } else { requestLen := 1 // protocol version @@ -126,9 +124,7 @@ func (vc *Conn) sendRequest(p []byte) bool { } requestLen += len(p) - _buffer := buf.StackNewSize(requestLen) - defer buf.KeepAlive(_buffer) - buffer = buf.Dup(_buffer) + buffer = buf.NewSize(requestLen) defer buffer.Release() } diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go index 23721c0b..03f524aa 100644 --- a/transport/vless/vision/conn.go +++ b/transport/vless/vision/conn.go @@ -157,9 +157,7 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { func (vc *Conn) Write(p []byte) (int, error) { if vc.writeFilterApplicationData { - _buffer := buf.StackNew() - defer buf.KeepAlive(_buffer) - buffer := buf.Dup(_buffer) + buffer := buf.New() defer buffer.Release() buffer.Write(p) err := vc.WriteBuffer(buffer) From 081e94c73899386149537309a52aa65dd8cad063 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 14 Jul 2023 22:28:24 +0800 Subject: [PATCH 56/79] feat: Add sing-geoip database support --- component/mmdb/mmdb.go | 37 +++++++++++++++++++++++++++---------- component/mmdb/reader.go | 36 ++++++++++++++++++++++++++++++++++++ config/updateGeo.go | 4 ++-- constant/path.go | 3 ++- dns/filters.go | 6 +++--- go.mod | 2 +- rules/common/geoip.go | 4 ++-- 7 files changed, 73 insertions(+), 19 deletions(-) create mode 100644 component/mmdb/reader.go diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go index 14f6f997..16d4d2df 100644 --- a/component/mmdb/mmdb.go +++ b/component/mmdb/mmdb.go @@ -12,42 +12,59 @@ import ( C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - "github.com/oschwald/geoip2-golang" + "github.com/oschwald/maxminddb-golang" +) + +type databaseType = uint8 + +const ( + typeMaxmind databaseType = iota + typeSing ) var ( - mmdb *geoip2.Reader - once sync.Once + reader Reader + once sync.Once ) func LoadFromBytes(buffer []byte) { once.Do(func() { - var err error - mmdb, err = geoip2.FromBytes(buffer) + mmdb, err := maxminddb.FromBytes(buffer) if err != nil { log.Fatalln("Can't load mmdb: %s", err.Error()) } + reader = Reader{Reader: mmdb} + if mmdb.Metadata.DatabaseType == "sing-geoip" { + reader.databaseType = typeSing + } else { + reader.databaseType = typeMaxmind + } }) } func Verify() bool { - instance, err := geoip2.Open(C.Path.MMDB()) + instance, err := maxminddb.Open(C.Path.MMDB()) if err == nil { instance.Close() } return err == nil } -func Instance() *geoip2.Reader { +func Instance() Reader { once.Do(func() { - var err error - mmdb, err = geoip2.Open(C.Path.MMDB()) + mmdb, err := maxminddb.Open(C.Path.MMDB()) if err != nil { log.Fatalln("Can't load mmdb: %s", err.Error()) } + reader = Reader{Reader: mmdb} + if mmdb.Metadata.DatabaseType == "sing-geoip" { + reader.databaseType = typeSing + } else { + reader.databaseType = typeMaxmind + } }) - return mmdb + return reader } func DownloadMMDB(path string) (err error) { diff --git a/component/mmdb/reader.go b/component/mmdb/reader.go new file mode 100644 index 00000000..35040344 --- /dev/null +++ b/component/mmdb/reader.go @@ -0,0 +1,36 @@ +package mmdb + +import ( + "fmt" + "net" + + "github.com/oschwald/maxminddb-golang" +) + +type geoip2Country struct { + Country struct { + IsoCode string `maxminddb:"iso_code"` + } `maxminddb:"country"` +} + +type Reader struct { + *maxminddb.Reader + databaseType +} + +func (r Reader) LookupCode(ipAddress net.IP) string { + switch r.databaseType { + case typeMaxmind: + var country geoip2Country + _ = r.Lookup(ipAddress, &country) + return country.Country.IsoCode + + case typeSing: + var code string + _ = r.Lookup(ipAddress, &code) + return code + + default: + panic(fmt.Sprint("unknown geoip database type:", r.databaseType)) + } +} diff --git a/config/updateGeo.go b/config/updateGeo.go index e76301ba..b75d3184 100644 --- a/config/updateGeo.go +++ b/config/updateGeo.go @@ -14,7 +14,7 @@ import ( clashHttp "github.com/Dreamacro/clash/component/http" C "github.com/Dreamacro/clash/constant" - "github.com/oschwald/geoip2-golang" + "github.com/oschwald/maxminddb-golang" ) func UpdateGeoDatabases() error { @@ -44,7 +44,7 @@ func UpdateGeoDatabases() error { return fmt.Errorf("can't download MMDB database file: %w", err) } - instance, err := geoip2.FromBytes(data) + instance, err := maxminddb.FromBytes(data) if err != nil { return fmt.Errorf("invalid MMDB database file: %s", err) } diff --git a/constant/path.go b/constant/path.go index 10d143d7..09f1d89b 100644 --- a/constant/path.go +++ b/constant/path.go @@ -91,7 +91,8 @@ func (p *path) MMDB() string { // 目录则直接跳过 continue } else { - if strings.EqualFold(fi.Name(), "Country.mmdb") { + if strings.EqualFold(fi.Name(), "Country.mmdb") || + strings.EqualFold(fi.Name(), "geoip.db") { GeoipName = fi.Name() return P.Join(p.homeDir, fi.Name()) } diff --git a/dns/filters.go b/dns/filters.go index 58b261ac..811fc976 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -2,6 +2,7 @@ package dns import ( "net/netip" + "strings" "github.com/Dreamacro/clash/component/geodata" "github.com/Dreamacro/clash/component/geodata/router" @@ -9,7 +10,6 @@ import ( "github.com/Dreamacro/clash/component/trie" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - "strings" ) type fallbackIPFilter interface { @@ -24,8 +24,8 @@ var geoIPMatcher *router.GeoIPMatcher func (gf *geoipFilter) Match(ip netip.Addr) bool { if !C.GeodataMode { - record, _ := mmdb.Instance().Country(ip.AsSlice()) - return !strings.EqualFold(record.Country.IsoCode, gf.code) && !ip.IsPrivate() + code := mmdb.Instance().LookupCode(ip.AsSlice()) + return !strings.EqualFold(code, gf.code) && !ip.IsPrivate() } if geoIPMatcher == nil { diff --git a/go.mod b/go.mod index d3206598..bb6115ba 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/mroth/weightedrand/v2 v2.0.1 github.com/openacid/low v0.1.21 github.com/oschwald/geoip2-golang v1.9.0 + github.com/oschwald/maxminddb-golang v1.11.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.2.8-0.20230703002104-c68251b6d059 github.com/sagernet/sing-mux v0.1.1-0.20230703132253-2cedde0fbc90 @@ -80,7 +81,6 @@ require ( github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect - github.com/oschwald/maxminddb-golang v1.11.0 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect diff --git a/rules/common/geoip.go b/rules/common/geoip.go index 0c134c63..07b342ac 100644 --- a/rules/common/geoip.go +++ b/rules/common/geoip.go @@ -40,8 +40,8 @@ func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) { resolver.IsFakeBroadcastIP(ip), g.adapter } if !C.GeodataMode { - record, _ := mmdb.Instance().Country(ip.AsSlice()) - return strings.EqualFold(record.Country.IsoCode, g.country), g.adapter + code := mmdb.Instance().LookupCode(ip.AsSlice()) + return strings.EqualFold(code, g.country), g.adapter } return g.geoIPMatcher.Match(ip.AsSlice()), g.adapter } From cfc30753af61e0da6190f9a6dd7031d02936d977 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 15 Jul 2023 16:52:44 +0800 Subject: [PATCH 57/79] chore: Update go1.21rc3 --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1957e9bf..b66257c0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,7 +128,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.21.0-rc.2" + go-version: "1.21.0-rc.3" check-latest: true - name: Test From f73f32e41cba9969a1fc6fd7642897ce9fa64e59 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 16 Jul 2023 10:14:29 +0800 Subject: [PATCH 58/79] fix: parse nested `sub-rules` failed --- config/config.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/config.go b/config/config.go index ae2ebbde..c7ae0fe1 100644 --- a/config/config.go +++ b/config/config.go @@ -712,6 +712,9 @@ func parseRuleProviders(cfg *RawConfig) (ruleProviders map[string]providerTypes. func parseSubRules(cfg *RawConfig, proxies map[string]C.Proxy) (subRules map[string][]C.Rule, err error) { subRules = map[string][]C.Rule{} + for name := range cfg.SubRules { + subRules[name] = make([]C.Rule, 0) + } for name, rawRules := range cfg.SubRules { if len(name) == 0 { return nil, fmt.Errorf("sub-rule name is empty") From 9cbca162a0bf6946434fdef08670523394301902 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 16 Jul 2023 10:29:43 +0800 Subject: [PATCH 59/79] feat: tuic outbound allow set an empty `ALPN` array --- adapter/outbound/tuic.go | 2 +- common/structure/structure.go | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 86b34dc8..c10a853a 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -162,7 +162,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) } - if len(option.ALPN) > 0 { + if option.ALPN != nil { // structure's Decode will ensure value not nil when input has value even it was set an empty array tlsConfig.NextProtos = option.ALPN } else { tlsConfig.NextProtos = []string{"h3"} diff --git a/common/structure/structure.go b/common/structure/structure.go index 78f344a4..85254e24 100644 --- a/common/structure/structure.go +++ b/common/structure/structure.go @@ -282,6 +282,9 @@ func (d *Decoder) decodeSlice(name string, data any, val reflect.Value) error { } valSlice := val + // make a new slice with cap(val)==cap(dataVal) + // the caller can determine whether the original configuration contains this item by judging whether the value is nil. + valSlice = reflect.MakeSlice(valType, 0, dataVal.Len()) for i := 0; i < dataVal.Len(); i++ { currentData := dataVal.Index(i).Interface() for valSlice.Len() <= i { From 9b50f56e7c2ed5a201a9f33b559b61f4f48f46ff Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 16 Jul 2023 10:35:10 +0800 Subject: [PATCH 60/79] fix: tunnel's handleUDPToLocal panic --- tunnel/connection.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tunnel/connection.go b/tunnel/connection.go index 38dbfa65..2e76b86b 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -41,7 +41,13 @@ func handleUDPToLocal(writeBack C.WriteBack, pc N.EnhancePacketConn, key string, } fromUDPAddr, isUDPAddr := from.(*net.UDPAddr) - if isUDPAddr { + if !isUDPAddr { + fromUDPAddr = net.UDPAddrFromAddrPort(oAddrPort) // oAddrPort was Unmapped + log.Warnln("server return a [%T](%s) which isn't a *net.UDPAddr, force replace to (%s), this may be caused by a wrongly implemented server", from, from, oAddrPort) + } else if fromUDPAddr == nil { + fromUDPAddr = net.UDPAddrFromAddrPort(oAddrPort) // oAddrPort was Unmapped + log.Warnln("server return a nil *net.UDPAddr, force replace to (%s), this may be caused by a wrongly implemented server", oAddrPort) + } else { _fromUDPAddr := *fromUDPAddr fromUDPAddr = &_fromUDPAddr // make a copy if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok { @@ -54,9 +60,6 @@ func handleUDPToLocal(writeBack C.WriteBack, pc N.EnhancePacketConn, key string, fromUDPAddr.Zone = "" // only ipv6 can have the zone } } - } else { - fromUDPAddr = net.UDPAddrFromAddrPort(oAddrPort) // oAddrPort was Unmapped - log.Warnln("server return a [%T](%s) which isn't a *net.UDPAddr, force replace to (%s), this may be caused by a wrongly implemented server", from, from, oAddrPort) } _, err = writeBack.WriteBack(data, fromUDPAddr) From 014537e1eab6fe97793c153a11a7869baf5afeb3 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 16 Jul 2023 11:10:07 +0800 Subject: [PATCH 61/79] fix: discard http unsuccessful status --- component/resource/vehicle.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/component/resource/vehicle.go b/component/resource/vehicle.go index 927a9604..1ae1b662 100644 --- a/component/resource/vehicle.go +++ b/component/resource/vehicle.go @@ -2,12 +2,14 @@ package resource import ( "context" - clashHttp "github.com/Dreamacro/clash/component/http" - types "github.com/Dreamacro/clash/constant/provider" + "errors" "io" "net/http" "os" "time" + + clashHttp "github.com/Dreamacro/clash/component/http" + types "github.com/Dreamacro/clash/constant/provider" ) type FileVehicle struct { @@ -54,8 +56,10 @@ func (h *HTTPVehicle) Read() ([]byte, error) { if err != nil { return nil, err } - defer resp.Body.Close() + if resp.StatusCode < 200 && resp.StatusCode > 299 { + return nil, errors.New(resp.Status) + } buf, err := io.ReadAll(resp.Body) if err != nil { return nil, err From a181e358658fa57619e9c00f81c083776fc0a3f3 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 16 Jul 2023 11:11:16 +0800 Subject: [PATCH 62/79] chore: structure support decode pointer --- common/structure/structure.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/common/structure/structure.go b/common/structure/structure.go index 85254e24..fde22309 100644 --- a/common/structure/structure.go +++ b/common/structure/structure.go @@ -96,6 +96,11 @@ func (d *Decoder) decode(name string, data any, val reflect.Value) error { return d.decodeFloat(name, data, val) } switch kind { + case reflect.Pointer: + if val.IsNil() { + val.Set(reflect.New(val.Type().Elem())) + } + return d.decode(name, data, val.Elem()) case reflect.String: return d.decodeString(name, data, val) case reflect.Bool: From cbb8ef5dfed19b550b47699fd54eccfb026f3d4e Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 16 Jul 2023 11:43:18 +0800 Subject: [PATCH 63/79] fix: discard http unsuccessful status --- component/resource/vehicle.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/component/resource/vehicle.go b/component/resource/vehicle.go index 1ae1b662..2f4bfbc8 100644 --- a/component/resource/vehicle.go +++ b/component/resource/vehicle.go @@ -57,7 +57,7 @@ func (h *HTTPVehicle) Read() ([]byte, error) { return nil, err } defer resp.Body.Close() - if resp.StatusCode < 200 && resp.StatusCode > 299 { + if resp.StatusCode < 200 || resp.StatusCode > 299 { return nil, errors.New(resp.Status) } buf, err := io.ReadAll(resp.Body) From a82745f544f38b624dd19135fec8f69d52219c23 Mon Sep 17 00:00:00 2001 From: Hellojack <106379370+H1JK@users.noreply.github.com> Date: Sun, 16 Jul 2023 23:26:07 +0800 Subject: [PATCH 64/79] chore: Remove legacy XTLS support (#645) * chore: Remove legacy XTLS support * chore: Rename function --- adapter/outbound/trojan.go | 28 -------- adapter/outbound/util.go | 13 +--- adapter/outbound/vless.go | 38 +++------- component/tls/config.go | 26 ------- go.mod | 1 - go.sum | 2 - transport/trojan/trojan.go | 141 ++++++++++--------------------------- transport/vless/conn.go | 21 ------ transport/vless/vless.go | 12 ++-- transport/vless/xtls.go | 37 ---------- 10 files changed, 55 insertions(+), 264 deletions(-) delete mode 100644 transport/vless/xtls.go diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 81fb1ceb..3af71b7d 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -14,7 +14,6 @@ import ( C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/gun" "github.com/Dreamacro/clash/transport/trojan" - "github.com/Dreamacro/clash/transport/vless" ) type Trojan struct { @@ -45,8 +44,6 @@ type TrojanOption struct { RealityOpts RealityOptions `proxy:"reality-opts,omitempty"` GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` WSOpts WSOptions `proxy:"ws-opts,omitempty"` - Flow string `proxy:"flow,omitempty"` - FlowShow bool `proxy:"flow-show,omitempty"` ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } @@ -95,11 +92,6 @@ func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C. return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } - c, err = t.instance.PresetXTLSConn(c) - if err != nil { - return nil, err - } - if metadata.NetWork == C.UDP { err = t.instance.WriteHeader(c, trojan.CommandUDP, serializesSocksAddr(metadata)) return c, err @@ -117,12 +109,6 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ... return nil, err } - c, err = t.instance.PresetXTLSConn(c) - if err != nil { - c.Close() - return nil, err - } - if err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)); err != nil { c.Close() return nil, err @@ -237,24 +223,10 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { ALPN: option.ALPN, ServerName: option.Server, SkipCertVerify: option.SkipCertVerify, - FlowShow: option.FlowShow, Fingerprint: option.Fingerprint, ClientFingerprint: option.ClientFingerprint, } - switch option.Network { - case "", "tcp": - if len(option.Flow) >= 16 { - option.Flow = option.Flow[:16] - switch option.Flow { - case vless.XRO, vless.XRD, vless.XRS: - tOption.Flow = option.Flow - default: - return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow) - } - } - } - if option.SNI != "" { tOption.ServerName = option.SNI } diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index 68d6b355..0504d005 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "crypto/tls" - xtls "github.com/xtls/go" "net" "net/netip" "strconv" @@ -17,9 +16,8 @@ import ( ) var ( - globalClientSessionCache tls.ClientSessionCache - globalClientXSessionCache xtls.ClientSessionCache - once sync.Once + globalClientSessionCache tls.ClientSessionCache + once sync.Once ) func tcpKeepAlive(c net.Conn) { @@ -36,13 +34,6 @@ func getClientSessionCache() tls.ClientSessionCache { return globalClientSessionCache } -func getClientXSessionCache() xtls.ClientSessionCache { - once.Do(func() { - globalClientXSessionCache = xtls.NewLRUClientSessionCache(128) - }) - return globalClientXSessionCache -} - func serializesSocksAddr(metadata *C.Metadata) []byte { var buf [][]byte addrType := metadata.AddrType() diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 803e0f57..6423eb29 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -56,7 +56,6 @@ type VlessOption struct { Port int `proxy:"port"` UUID string `proxy:"uuid"` Flow string `proxy:"flow,omitempty"` - FlowShow bool `proxy:"flow-show,omitempty"` TLS bool `proxy:"tls,omitempty"` UDP bool `proxy:"udp,omitempty"` PacketAddr bool `proxy:"packet-addr,omitempty"` @@ -133,7 +132,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M c, err = vmess.StreamWebsocketConn(ctx, c, wsOpts) case "http": // readability first, so just copy default TLS logic - c, err = v.streamTLSOrXTLSConn(ctx, c, false) + c, err = v.streamTLSConn(ctx, c, false) if err != nil { return nil, err } @@ -148,7 +147,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M c = vmess.StreamHTTPConn(c, httpOpts) case "h2": - c, err = v.streamTLSOrXTLSConn(ctx, c, true) + c, err = v.streamTLSConn(ctx, c, true) if err != nil { return nil, err } @@ -163,8 +162,8 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig) default: // default tcp network - // handle TLS And XTLS - c, err = v.streamTLSOrXTLSConn(ctx, c, false) + // handle TLS + c, err = v.streamTLSConn(ctx, c, false) } if err != nil { @@ -202,23 +201,10 @@ func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err return } -func (v *Vless) streamTLSOrXTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) { - host, _, _ := net.SplitHostPort(v.addr) +func (v *Vless) streamTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) { + if v.option.TLS { + host, _, _ := net.SplitHostPort(v.addr) - if v.isLegacyXTLSEnabled() && !isH2 { - xtlsOpts := vless.XTLSConfig{ - Host: host, - SkipCertVerify: v.option.SkipCertVerify, - Fingerprint: v.option.Fingerprint, - } - - if v.option.ServerName != "" { - xtlsOpts.Host = v.option.ServerName - } - - return vless.StreamXTLSConn(ctx, conn, &xtlsOpts) - - } else if v.option.TLS { tlsOpts := vmess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, @@ -241,10 +227,6 @@ func (v *Vless) streamTLSOrXTLSConn(ctx context.Context, conn net.Conn, isH2 boo return conn, nil } -func (v *Vless) isLegacyXTLSEnabled() bool { - return v.client.Addons != nil && v.client.Addons.Flow != vless.XRV -} - // DialContext implements C.ProxyAdapter func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { // gun transport @@ -526,11 +508,11 @@ func NewVless(option VlessOption) (*Vless, error) { switch option.Flow { case vless.XRV: log.Warnln("To use %s, ensure your server is upgrade to Xray-core v1.8.0+", vless.XRV) - fallthrough - case vless.XRO, vless.XRD, vless.XRS: addons = &vless.Addons{ Flow: option.Flow, } + case vless.XRO, vless.XRD, vless.XRS: + log.Fatalln("Legacy XTLS protocol %s is deprecated and no longer supported", option.Flow) default: return nil, fmt.Errorf("unsupported xtls flow type: %s", option.Flow) } @@ -549,7 +531,7 @@ func NewVless(option VlessOption) (*Vless, error) { option.PacketAddr = false } - client, err := vless.NewClient(option.UUID, addons, option.FlowShow) + client, err := vless.NewClient(option.UUID, addons) if err != nil { return nil, err } diff --git a/component/tls/config.go b/component/tls/config.go index 2896a1be..d7382f7c 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -10,8 +10,6 @@ import ( "fmt" "strings" "sync" - - xtls "github.com/xtls/go" ) var trustCerts []*x509.Certificate @@ -122,27 +120,3 @@ func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config { tlsConfig.RootCAs = certPool return tlsConfig } - -// GetSpecifiedFingerprintXTLSConfig specified fingerprint -func GetSpecifiedFingerprintXTLSConfig(tlsConfig *xtls.Config, fingerprint string) (*xtls.Config, error) { - if fingerprintBytes, err := convertFingerprint(fingerprint); err != nil { - return nil, err - } else { - tlsConfig = GetGlobalXTLSConfig(tlsConfig) - tlsConfig.VerifyPeerCertificate = verifyFingerprint(fingerprintBytes) - tlsConfig.InsecureSkipVerify = true - return tlsConfig, nil - } -} - -func GetGlobalXTLSConfig(tlsConfig *xtls.Config) *xtls.Config { - certPool := getCertPool() - if tlsConfig == nil { - return &xtls.Config{ - RootCAs: certPool, - } - } - - tlsConfig.RootCAs = certPool - return tlsConfig -} diff --git a/go.mod b/go.mod index bb6115ba..06e522c0 100644 --- a/go.mod +++ b/go.mod @@ -42,7 +42,6 @@ require ( github.com/shirou/gopsutil/v3 v3.23.6 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 - github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.2 diff --git a/go.sum b/go.sum index 77508629..4f5a5aab 100644 --- a/go.sum +++ b/go.sum @@ -194,8 +194,6 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM= -github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index abe21f34..710905ad 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -7,7 +7,6 @@ import ( "encoding/binary" "encoding/hex" "errors" - "fmt" "io" "net" "net/http" @@ -18,10 +17,7 @@ import ( tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/vless" "github.com/Dreamacro/clash/transport/vmess" - - xtls "github.com/xtls/go" ) const ( @@ -42,7 +38,7 @@ const ( CommandTCP byte = 1 CommandUDP byte = 3 - // for XTLS + // deprecated XTLS commands, as souvenirs commandXRD byte = 0xf0 // XTLS direct mode commandXRO byte = 0xf1 // XTLS origin mode ) @@ -53,8 +49,6 @@ type Option struct { ServerName string SkipCertVerify bool Fingerprint string - Flow string - FlowShow bool ClientFingerprint string Reality *tlsC.RealityConfig } @@ -76,78 +70,50 @@ func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error if len(t.option.ALPN) != 0 { alpn = t.option.ALPN } - switch t.option.Flow { - case vless.XRO, vless.XRD, vless.XRS: - xtlsConfig := &xtls.Config{ - NextProtos: alpn, - MinVersion: xtls.VersionTLS12, - InsecureSkipVerify: t.option.SkipCertVerify, - ServerName: t.option.ServerName, - } + tlsConfig := &tls.Config{ + NextProtos: alpn, + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: t.option.SkipCertVerify, + ServerName: t.option.ServerName, + } - if len(t.option.Fingerprint) == 0 { - xtlsConfig = tlsC.GetGlobalXTLSConfig(xtlsConfig) - } else { - var err error - if xtlsConfig, err = tlsC.GetSpecifiedFingerprintXTLSConfig(xtlsConfig, t.option.Fingerprint); err != nil { - return nil, err - } - } - - xtlsConn := xtls.Client(conn, xtlsConfig) - - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - if err := xtlsConn.HandshakeContext(ctx); err != nil { + if len(t.option.Fingerprint) == 0 { + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) + } else { + var err error + if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint); err != nil { return nil, err } - return xtlsConn, nil - default: - tlsConfig := &tls.Config{ - NextProtos: alpn, - MinVersion: tls.VersionTLS12, - InsecureSkipVerify: t.option.SkipCertVerify, - ServerName: t.option.ServerName, - } + } - if len(t.option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - var err error - if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint); err != nil { - return nil, err - } - } - - if len(t.option.ClientFingerprint) != 0 { - if t.option.Reality == nil { - utlsConn, valid := vmess.GetUTLSConn(conn, t.option.ClientFingerprint, tlsConfig) - if valid { - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - - err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx) - return utlsConn, err - } - } else { + if len(t.option.ClientFingerprint) != 0 { + if t.option.Reality == nil { + utlsConn, valid := vmess.GetUTLSConn(conn, t.option.ClientFingerprint, tlsConfig) + if valid { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) defer cancel() - return tlsC.GetRealityConn(ctx, conn, t.option.ClientFingerprint, tlsConfig, t.option.Reality) + + err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx) + return utlsConn, err } + } else { + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) + defer cancel() + return tlsC.GetRealityConn(ctx, conn, t.option.ClientFingerprint, tlsConfig, t.option.Reality) } - if t.option.Reality != nil { - return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint") - } - - tlsConn := tls.Client(conn, tlsConfig) - - // fix tls handshake not timeout - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - - err := tlsConn.HandshakeContext(ctx) - return tlsConn, err } + if t.option.Reality != nil { + return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint") + } + + tlsConn := tls.Client(conn, tlsConfig) + + // fix tls handshake not timeout + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) + defer cancel() + + err := tlsConn.HandshakeContext(ctx) + return tlsConn, err } func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) { @@ -174,37 +140,7 @@ func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptio }) } -func (t *Trojan) PresetXTLSConn(conn net.Conn) (net.Conn, error) { - switch t.option.Flow { - case vless.XRO, vless.XRD, vless.XRS: - if xtlsConn, ok := conn.(*xtls.Conn); ok { - xtlsConn.RPRX = true - xtlsConn.SHOW = t.option.FlowShow - xtlsConn.MARK = "XTLS" - if t.option.Flow == vless.XRS { - t.option.Flow = vless.XRD - } - - if t.option.Flow == vless.XRD { - xtlsConn.DirectMode = true - } - } else { - return conn, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", t.option.Flow) - } - } - - return conn, nil -} - func (t *Trojan) WriteHeader(w io.Writer, command Command, socks5Addr []byte) error { - if command == CommandTCP { - if t.option.Flow == vless.XRD { - command = commandXRD - } else if t.option.Flow == vless.XRO { - command = commandXRO - } - } - buf := pool.GetBuffer() defer pool.PutBuffer(buf) @@ -398,8 +334,7 @@ func (pc *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, er func hexSha224(data []byte) []byte { buf := make([]byte, 56) - hash := sha256.New224() - hash.Write(data) - hex.Encode(buf, hash.Sum(nil)) + hash := sha256.Sum224(data) + hex.Encode(buf, hash[:]) return buf } diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 3a2a6755..33ecd97a 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -3,7 +3,6 @@ package vless import ( "encoding/binary" "errors" - "fmt" "io" "net" "sync" @@ -13,7 +12,6 @@ import ( "github.com/Dreamacro/clash/transport/vless/vision" "github.com/gofrs/uuid/v5" - xtls "github.com/xtls/go" "google.golang.org/protobuf/proto" ) @@ -201,25 +199,6 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { if client.Addons != nil { switch client.Addons.Flow { - case XRO, XRD, XRS: - 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 - } - 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 { diff --git a/transport/vless/vless.go b/transport/vless/vless.go index c2066afe..6c01b839 100644 --- a/transport/vless/vless.go +++ b/transport/vless/vless.go @@ -42,9 +42,8 @@ type DstAddr struct { // Client is vless connection generator type Client struct { - uuid *uuid.UUID - Addons *Addons - XTLSShow bool + uuid *uuid.UUID + Addons *Addons } // StreamConn return a Conn with net.Conn and DstAddr @@ -53,15 +52,14 @@ func (c *Client) StreamConn(conn net.Conn, dst *DstAddr) (net.Conn, error) { } // NewClient return Client instance -func NewClient(uuidStr string, addons *Addons, xtlsShow bool) (*Client, error) { +func NewClient(uuidStr string, addons *Addons) (*Client, error) { uid, err := utils.UUIDMap(uuidStr) if err != nil { return nil, err } return &Client{ - uuid: &uid, - Addons: addons, - XTLSShow: xtlsShow, + uuid: &uid, + Addons: addons, }, nil } diff --git a/transport/vless/xtls.go b/transport/vless/xtls.go deleted file mode 100644 index 071e6e8f..00000000 --- a/transport/vless/xtls.go +++ /dev/null @@ -1,37 +0,0 @@ -package vless - -import ( - "context" - "net" - - tlsC "github.com/Dreamacro/clash/component/tls" - xtls "github.com/xtls/go" -) - -type XTLSConfig struct { - Host string - SkipCertVerify bool - Fingerprint string - NextProtos []string -} - -func StreamXTLSConn(ctx context.Context, conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { - xtlsConfig := &xtls.Config{ - ServerName: cfg.Host, - InsecureSkipVerify: cfg.SkipCertVerify, - NextProtos: cfg.NextProtos, - } - if len(cfg.Fingerprint) == 0 { - xtlsConfig = tlsC.GetGlobalXTLSConfig(xtlsConfig) - } else { - var err error - if xtlsConfig, err = tlsC.GetSpecifiedFingerprintXTLSConfig(xtlsConfig, cfg.Fingerprint); err != nil { - return nil, err - } - } - - xtlsConn := xtls.Client(conn, xtlsConfig) - - err := xtlsConn.HandshakeContext(ctx) - return xtlsConn, err -} From b0e76ec791a86c23cf142408ef88b866aebb649f Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 17 Jul 2023 10:33:20 +0800 Subject: [PATCH 65/79] feat: Add Meta-geoip V0 database support --- component/mmdb/mmdb.go | 21 +++++++++++++++------ component/mmdb/reader.go | 26 +++++++++++++++++++++++--- constant/path.go | 3 ++- dns/filters.go | 9 +++++++-- rules/common/geoip.go | 9 +++++++-- 5 files changed, 54 insertions(+), 14 deletions(-) diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go index 16d4d2df..5db8bee9 100644 --- a/component/mmdb/mmdb.go +++ b/component/mmdb/mmdb.go @@ -20,6 +20,7 @@ type databaseType = uint8 const ( typeMaxmind databaseType = iota typeSing + typeMetaV0 ) var ( @@ -34,9 +35,12 @@ func LoadFromBytes(buffer []byte) { log.Fatalln("Can't load mmdb: %s", err.Error()) } reader = Reader{Reader: mmdb} - if mmdb.Metadata.DatabaseType == "sing-geoip" { + switch mmdb.Metadata.DatabaseType { + case "sing-geoip": reader.databaseType = typeSing - } else { + case "Meta-geoip0": + reader.databaseType = typeMetaV0 + default: reader.databaseType = typeMaxmind } }) @@ -52,14 +56,19 @@ func Verify() bool { func Instance() Reader { once.Do(func() { - mmdb, err := maxminddb.Open(C.Path.MMDB()) + mmdbPath := C.Path.MMDB() + log.Debugln("Load MMDB file: %s", mmdbPath) + mmdb, err := maxminddb.Open(mmdbPath) if err != nil { - log.Fatalln("Can't load mmdb: %s", err.Error()) + log.Fatalln("Can't load MMDB: %s", err.Error()) } reader = Reader{Reader: mmdb} - if mmdb.Metadata.DatabaseType == "sing-geoip" { + switch mmdb.Metadata.DatabaseType { + case "sing-geoip": reader.databaseType = typeSing - } else { + case "Meta-geoip0": + reader.databaseType = typeMetaV0 + default: reader.databaseType = typeMaxmind } }) diff --git a/component/mmdb/reader.go b/component/mmdb/reader.go index 35040344..4db53d4f 100644 --- a/component/mmdb/reader.go +++ b/component/mmdb/reader.go @@ -5,6 +5,7 @@ import ( "net" "github.com/oschwald/maxminddb-golang" + "github.com/sagernet/sing/common" ) type geoip2Country struct { @@ -18,17 +19,36 @@ type Reader struct { databaseType } -func (r Reader) LookupCode(ipAddress net.IP) string { +func (r Reader) LookupCode(ipAddress net.IP) []string { switch r.databaseType { case typeMaxmind: var country geoip2Country _ = r.Lookup(ipAddress, &country) - return country.Country.IsoCode + if country.Country.IsoCode == "" { + return []string{} + } + return []string{country.Country.IsoCode} case typeSing: var code string _ = r.Lookup(ipAddress, &code) - return code + if code == "" { + return []string{} + } + return []string{code} + + case typeMetaV0: + var record any + _ = r.Lookup(ipAddress, &record) + switch record := record.(type) { + case string: + return []string{record} + case []any: // lookup returned type of slice is []any + return common.Map(record, func(it any) string { + return it.(string) + }) + } + return []string{} default: panic(fmt.Sprint("unknown geoip database type:", r.databaseType)) diff --git a/constant/path.go b/constant/path.go index 09f1d89b..e23ae886 100644 --- a/constant/path.go +++ b/constant/path.go @@ -92,7 +92,8 @@ func (p *path) MMDB() string { continue } else { if strings.EqualFold(fi.Name(), "Country.mmdb") || - strings.EqualFold(fi.Name(), "geoip.db") { + strings.EqualFold(fi.Name(), "geoip.db") || + strings.EqualFold(fi.Name(), "geoip.metadb") { GeoipName = fi.Name() return P.Join(p.homeDir, fi.Name()) } diff --git a/dns/filters.go b/dns/filters.go index 811fc976..47e7adcd 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -24,8 +24,13 @@ var geoIPMatcher *router.GeoIPMatcher func (gf *geoipFilter) Match(ip netip.Addr) bool { if !C.GeodataMode { - code := mmdb.Instance().LookupCode(ip.AsSlice()) - return !strings.EqualFold(code, gf.code) && !ip.IsPrivate() + codes := mmdb.Instance().LookupCode(ip.AsSlice()) + for _, code := range codes { + if !strings.EqualFold(code, gf.code) && !ip.IsPrivate() { + return true + } + } + return false } if geoIPMatcher == nil { diff --git a/rules/common/geoip.go b/rules/common/geoip.go index 07b342ac..2f96c2ef 100644 --- a/rules/common/geoip.go +++ b/rules/common/geoip.go @@ -40,8 +40,13 @@ func (g *GEOIP) Match(metadata *C.Metadata) (bool, string) { resolver.IsFakeBroadcastIP(ip), g.adapter } if !C.GeodataMode { - code := mmdb.Instance().LookupCode(ip.AsSlice()) - return strings.EqualFold(code, g.country), g.adapter + codes := mmdb.Instance().LookupCode(ip.AsSlice()) + for _, code := range codes { + if strings.EqualFold(code, g.country) { + return true, g.adapter + } + } + return false, g.adapter } return g.geoIPMatcher.Match(ip.AsSlice()), g.adapter } From 76328271776388ba2c1e34f6b8bc67e074e39aa3 Mon Sep 17 00:00:00 2001 From: H1JK Date: Thu, 20 Jul 2023 23:24:48 +0800 Subject: [PATCH 66/79] chore: Use Meta-geoip for default --- Dockerfile | 6 +++--- config/config.go | 2 +- constant/path.go | 2 +- docs/config.yaml | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index f5dcc307..6c5a91f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,9 +4,9 @@ RUN echo "I'm building for $TARGETPLATFORM" RUN apk add --no-cache gzip && \ mkdir /clash-config && \ - wget -O /clash-config/Country.mmdb https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb && \ - wget -O /clash-config/geosite.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat && \ - wget -O /clash-config/geoip.dat https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat + wget -O /clash-config/geoip.metadb https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb && \ + wget -O /clash-config/geosite.dat https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat && \ + wget -O /clash-config/geoip.dat https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat COPY docker/file-name.sh /clash/file-name.sh WORKDIR /clash diff --git a/config/config.go b/config/config.go index c7ae0fe1..ba61070c 100644 --- a/config/config.go +++ b/config/config.go @@ -419,7 +419,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { StoreSelected: true, }, GeoXUrl: RawGeoXUrl{ - Mmdb: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/country.mmdb", + Mmdb: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb", GeoIp: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat", GeoSite: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat", }, diff --git a/constant/path.go b/constant/path.go index e23ae886..d7477e0e 100644 --- a/constant/path.go +++ b/constant/path.go @@ -99,7 +99,7 @@ func (p *path) MMDB() string { } } } - return P.Join(p.homeDir, "Country.mmdb") + return P.Join(p.homeDir, "geoip.metadb") } func (p *path) OldCache() string { diff --git a/docs/config.yaml b/docs/config.yaml index 0cec9a04..6ae3910e 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -19,9 +19,9 @@ mode: rule #自定义 geodata url geox-url: - geoip: "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geoip.dat" - geosite: "https://cdn.jsdelivr.net/gh/Loyalsoldier/v2ray-rules-dat@release/geosite.dat" - mmdb: "https://cdn.jsdelivr.net/gh/Loyalsoldier/geoip@release/Country.mmdb" + geoip: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat" + geosite: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat" + mmdb: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb" log-level: debug # 日志等级 silent/error/warning/info/debug From e2216b7824e292684155ebcb222e6e4369588374 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 1 Aug 2023 09:55:55 +0800 Subject: [PATCH 67/79] chore: update quic-go to 0.37.1 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 06e522c0..c895f311 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d + github.com/metacubex/quic-go v0.37.2-0.20230801015013-c321217d291b github.com/metacubex/sing-shadowsocks v0.2.3-0.20230714014829-3669e0591014 github.com/metacubex/sing-shadowsocks2 v0.1.1-0.20230714014119-27b8d12c6d0b github.com/metacubex/sing-tun v0.1.9-0.20230714030349-b6aed664150f diff --git a/go.sum b/go.sum index 4f5a5aab..a4fcc724 100644 --- a/go.sum +++ b/go.sum @@ -94,8 +94,8 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d h1:LCMD4JnahhgImBdfsGe0PAQiYNx2UlqvrGpYbZ0CVHs= -github.com/metacubex/quic-go v0.36.2-0.20230702012232-c341ad4d2d5d/go.mod h1:runF6UZHW4A/P/VU+PtfQKKD85YgaZgrgbvCTs5Nwbk= +github.com/metacubex/quic-go v0.37.2-0.20230801015013-c321217d291b h1:oVYQtX4v8yT5CYI8oc8G6ZTnh5lzwvMOkwyGwcuIoGc= +github.com/metacubex/quic-go v0.37.2-0.20230801015013-c321217d291b/go.mod h1:runF6UZHW4A/P/VU+PtfQKKD85YgaZgrgbvCTs5Nwbk= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7 h1:XY3Y6nPL45XuN/k3rDXJ1TJknLo8rTo1SVuDOmOEf4E= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/metacubex/sing-shadowsocks v0.2.3-0.20230714014829-3669e0591014 h1:KRMv2Q0Fa69chRsNr0RVTqh99POzYQi/OJ9p6FRcXfQ= From f125e1ce9ec8b67010dcfb2af055303e78ce8d23 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 1 Aug 2023 13:54:22 +0800 Subject: [PATCH 68/79] chore: Update dependencies --- constant/tun.go | 4 + go.mod | 30 ++- go.sum | 57 ++--- transport/hysteria/acl/engine.go | 100 -------- transport/hysteria/acl/engine_test.go | 154 ------------ transport/hysteria/acl/entry.go | 331 -------------------------- transport/hysteria/acl/entry_test.go | 75 ------ 7 files changed, 44 insertions(+), 707 deletions(-) delete mode 100644 transport/hysteria/acl/engine.go delete mode 100644 transport/hysteria/acl/engine_test.go delete mode 100644 transport/hysteria/acl/entry.go delete mode 100644 transport/hysteria/acl/entry_test.go diff --git a/constant/tun.go b/constant/tun.go index 38f51155..5e2841bc 100644 --- a/constant/tun.go +++ b/constant/tun.go @@ -10,12 +10,14 @@ var StackTypeMapping = map[string]TUNStack{ strings.ToLower(TunGvisor.String()): TunGvisor, strings.ToLower(TunSystem.String()): TunSystem, strings.ToLower(TunLWIP.String()): TunLWIP, + strings.ToLower(TunMixed.String()): TunMixed, } const ( TunGvisor TUNStack = iota TunSystem TunLWIP + TunMixed ) type TUNStack int @@ -64,6 +66,8 @@ func (e TUNStack) String() string { return "System" case TunLWIP: return "LWIP" + case TunMixed: + return "Mixed" default: return "unknown" } diff --git a/go.mod b/go.mod index c895f311..a2bbff7c 100644 --- a/go.mod +++ b/go.mod @@ -8,45 +8,43 @@ require ( github.com/cilium/ebpf v0.11.0 github.com/coreos/go-iptables v0.6.0 github.com/dlclark/regexp2 v1.10.0 - github.com/go-chi/chi/v5 v5.0.8 + github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 - github.com/go-chi/render v1.0.2 + github.com/go-chi/render v1.0.3 github.com/gofrs/uuid/v5 v5.0.0 github.com/gorilla/websocket v1.5.0 - github.com/hashicorp/golang-lru v0.5.4 - github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df + github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c github.com/jpillora/backoff v1.0.0 github.com/klauspost/cpuid/v2 v2.2.5 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.37.2-0.20230801015013-c321217d291b - github.com/metacubex/sing-shadowsocks v0.2.3-0.20230714014829-3669e0591014 - github.com/metacubex/sing-shadowsocks2 v0.1.1-0.20230714014119-27b8d12c6d0b - github.com/metacubex/sing-tun v0.1.9-0.20230714030349-b6aed664150f - github.com/metacubex/sing-vmess v0.1.5-0.20230713151521-79843393b710 + github.com/metacubex/sing-shadowsocks v0.2.4 + github.com/metacubex/sing-shadowsocks2 v0.1.3 + github.com/metacubex/sing-tun v0.1.11 + github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8 github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 github.com/miekg/dns v1.1.55 github.com/mroth/weightedrand/v2 v2.0.1 github.com/openacid/low v0.1.21 - github.com/oschwald/geoip2-golang v1.9.0 - github.com/oschwald/maxminddb-golang v1.11.0 + github.com/oschwald/maxminddb-golang v1.12.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.8-0.20230703002104-c68251b6d059 - github.com/sagernet/sing-mux v0.1.1-0.20230703132253-2cedde0fbc90 - github.com/sagernet/sing-shadowtls v0.1.3-0.20230703132509-93bbad3057e4 + github.com/sagernet/sing v0.2.9 + github.com/sagernet/sing-mux v0.1.2 + github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 github.com/samber/lo v1.38.1 - github.com/shirou/gopsutil/v3 v3.23.6 + github.com/shirou/gopsutil/v3 v3.23.7 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.4 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 - go.uber.org/automaxprocs v1.5.2 + go.uber.org/automaxprocs v1.5.3 golang.org/x/crypto v0.11.0 - golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb + golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 golang.org/x/net v0.12.0 golang.org/x/sync v0.3.0 golang.org/x/sys v0.10.0 diff --git a/go.sum b/go.sum index a4fcc724..0e1a19aa 100644 --- a/go.sum +++ b/go.sum @@ -35,12 +35,12 @@ github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtB github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= -github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= -github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= +github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= +github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4= github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58= -github.com/go-chi/render v1.0.2 h1:4ER/udB0+fMWB2Jlf15RV3F4A2FDuYi/9f+lFttR/Lg= -github.com/go-chi/render v1.0.2/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= +github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4= +github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0= github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= @@ -64,13 +64,11 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc= -github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df h1:pF1MMIzEJzJ/MyI4bXYXVYyN8CJgoQ2PPKT2z3O/Cl4= -github.com/insomniacslk/dhcp v0.0.0-20230612134759-b20c9ba983df/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= +github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs= +github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -98,14 +96,14 @@ github.com/metacubex/quic-go v0.37.2-0.20230801015013-c321217d291b h1:oVYQtX4v8y github.com/metacubex/quic-go v0.37.2-0.20230801015013-c321217d291b/go.mod h1:runF6UZHW4A/P/VU+PtfQKKD85YgaZgrgbvCTs5Nwbk= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7 h1:XY3Y6nPL45XuN/k3rDXJ1TJknLo8rTo1SVuDOmOEf4E= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/metacubex/sing-shadowsocks v0.2.3-0.20230714014829-3669e0591014 h1:KRMv2Q0Fa69chRsNr0RVTqh99POzYQi/OJ9p6FRcXfQ= -github.com/metacubex/sing-shadowsocks v0.2.3-0.20230714014829-3669e0591014/go.mod h1:UeQCECVevysZhVYeSs1w8dN2MLJrt9RVAC4qhdLorm0= -github.com/metacubex/sing-shadowsocks2 v0.1.1-0.20230714014119-27b8d12c6d0b h1:cTDNDaqSoSOfhepLfc05Tl6gMMnLDxUApc/RcCzfHwE= -github.com/metacubex/sing-shadowsocks2 v0.1.1-0.20230714014119-27b8d12c6d0b/go.mod h1:YC5UDPqtDifY0jed5iYYcp3RsSDtzv5fJ9wQYtRrCaU= -github.com/metacubex/sing-tun v0.1.9-0.20230714030349-b6aed664150f h1:IA7kBQN/ShhszhCMBDke1Y0fWnxnRBdHJR+gOTeOjZM= -github.com/metacubex/sing-tun v0.1.9-0.20230714030349-b6aed664150f/go.mod h1:yhMxm3aiwfc8HRv429QqO+8gWXMeCDQw/bh5CGKbCYM= -github.com/metacubex/sing-vmess v0.1.5-0.20230713151521-79843393b710 h1:8zXxMXgG5HaLG43RT1j1fsmDZTwhElaFk+Dj7wmdb9k= -github.com/metacubex/sing-vmess v0.1.5-0.20230713151521-79843393b710/go.mod h1:i20X8MiR+bordyMPhp16Swl7Rycr9qf+gkYQiUTMzsY= +github.com/metacubex/sing-shadowsocks v0.2.4 h1:Gc99Z17JVif1PKKq1pjqhSmc2kvHUgk+AqxOstCzhQ0= +github.com/metacubex/sing-shadowsocks v0.2.4/go.mod h1:w9qoEZSh9aKeXSLXHe0DGbG2UE9/2VlLGwukzQZ7byI= +github.com/metacubex/sing-shadowsocks2 v0.1.3 h1:nZvH+4jQXZ92NeNdR9fXaUGTPNJPt6u0nkcuh/NEt5Y= +github.com/metacubex/sing-shadowsocks2 v0.1.3/go.mod h1:5Mt93RlmRlIcDmvtapkhQJ8YTRGLFhHciLYopJjs7j8= +github.com/metacubex/sing-tun v0.1.11 h1:B8meDewklvKkeUfjqR2ViuYLam0/m4IgkTi3qcJIOuc= +github.com/metacubex/sing-tun v0.1.11/go.mod h1:vbki176Y5sxXC1DWXucrPh3q5j8cKai1D87y8m8rjQc= +github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8 h1:AqqZCr9gOeKdO6oIzFh4b2puOUFcw8MdpmGHWRehyX8= +github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8/go.mod h1:tyJg7b4s8NrSztl/Y1ajA7X0sJLlIsEJWkgRVocjmgY= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= @@ -122,10 +120,8 @@ github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= github.com/openacid/must v0.1.3/go.mod h1:luPiXCuJlEo3UUFQngVQokV0MPGryeYvtCbQPs3U1+I= github.com/openacid/testkeys v0.1.6/go.mod h1:MfA7cACzBpbiwekivj8StqX0WIRmqlMsci1c37CA3Do= -github.com/oschwald/geoip2-golang v1.9.0 h1:uvD3O6fXAXs+usU+UGExshpdP13GAqp4GBrzN7IgKZc= -github.com/oschwald/geoip2-golang v1.9.0/go.mod h1:BHK6TvDyATVQhKNbQBdrj9eAvuwOMi2zSFXizL3K81Y= -github.com/oschwald/maxminddb-golang v1.11.0 h1:aSXMqYR/EPNjGE8epgqwDay+P30hCBZIveY0WZbAWh0= -github.com/oschwald/maxminddb-golang v1.11.0/go.mod h1:YmVI+H0zh3ySFR3w+oz8PCfglAFj3PuCmui13+P9zDg= +github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= +github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= @@ -143,10 +139,10 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= 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-mux v0.1.1-0.20230703132253-2cedde0fbc90 h1:aEe2HrRc9OTS7IZ8RHyh224OhltnwRQs4/y89UsHPo8= -github.com/sagernet/sing-mux v0.1.1-0.20230703132253-2cedde0fbc90/go.mod h1:sm126rB5EUi9HLf4jCSHTqo+XRPbh4BoEVeLbr2WRbE= -github.com/sagernet/sing-shadowtls v0.1.3-0.20230703132509-93bbad3057e4 h1:ZjLyCkEENqXzGp4PRZbQGk5wPzEq0Rg+/2jK82lmy3Q= -github.com/sagernet/sing-shadowtls v0.1.3-0.20230703132509-93bbad3057e4/go.mod h1:8ZSSHJSNOG7cUCUYJemZNH873EsKdFqABykTypoS/2M= +github.com/sagernet/sing-mux v0.1.2 h1:av2/m6e+Gh+ECTuJZqYCjJz55BNkot0VyRMkREqyF/g= +github.com/sagernet/sing-mux v0.1.2/go.mod h1:r2V8AlOzXaRCHXK7fILCUGzuI2iILweTaG8C5xlpHxo= +github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= +github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= @@ -159,8 +155,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/shirou/gopsutil/v3 v3.23.6 h1:5y46WPI9QBKBbK7EEccUPNXpJpNrvPuTD0O2zHEHT08= -github.com/shirou/gopsutil/v3 v3.23.6/go.mod h1:j7QX50DrXYggrpN30W0Mo+I4/8U2UUIQrnrhqUeWrAU= +github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= +github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -203,14 +199,14 @@ gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec h1:FpfFs4EhNehiV gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec/go.mod h1:BZ1RAoRPbCxum9Grlv5aeksu2H8BiKehBYooU2LFiOQ= go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ= go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= -go.uber.org/automaxprocs v1.5.2 h1:2LxUOGiR3O6tw8ui5sZa2LAaHnsviZdVOUZw4fvbnME= -go.uber.org/automaxprocs v1.5.2/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= +go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= 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.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb h1:xIApU0ow1zwMa2uL1VDNeQlNVFTWMQxZUZCMDy0Q4Us= -golang.org/x/exp v0.0.0-20230711153332-06a737ee72cb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 h1:/yRP+0AN7mf5DkD3BAI6TOFnd51gEoDEb8o35jIFtgw= +golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -242,7 +238,6 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/transport/hysteria/acl/engine.go b/transport/hysteria/acl/engine.go deleted file mode 100644 index adff5690..00000000 --- a/transport/hysteria/acl/engine.go +++ /dev/null @@ -1,100 +0,0 @@ -package acl - -import ( - "github.com/Dreamacro/clash/transport/hysteria/utils" - lru "github.com/hashicorp/golang-lru" - "github.com/oschwald/geoip2-golang" - "net" -) - -const entryCacheSize = 1024 - -type Engine struct { - DefaultAction Action - Entries []Entry - Cache *lru.ARCCache - ResolveIPAddr func(string) (*net.IPAddr, error) - GeoIPReader *geoip2.Reader -} - -type cacheKey struct { - Host string - Port uint16 - IsUDP bool -} - -type cacheValue struct { - Action Action - Arg string -} - -// action, arg, isDomain, resolvedIP, error -func (e *Engine) ResolveAndMatch(host string, port uint16, isUDP bool) (Action, string, bool, *net.IPAddr, error) { - ip, zone := utils.ParseIPZone(host) - if ip == nil { - // Domain - ipAddr, err := e.ResolveIPAddr(host) - if v, ok := e.Cache.Get(cacheKey{host, port, isUDP}); ok { - // Cache hit - ce := v.(cacheValue) - return ce.Action, ce.Arg, true, ipAddr, err - } - for _, entry := range e.Entries { - mReq := MatchRequest{ - Domain: host, - Port: port, - DB: e.GeoIPReader, - } - if ipAddr != nil { - mReq.IP = ipAddr.IP - } - if isUDP { - mReq.Protocol = ProtocolUDP - } else { - mReq.Protocol = ProtocolTCP - } - if entry.Match(mReq) { - e.Cache.Add(cacheKey{host, port, isUDP}, - cacheValue{entry.Action, entry.ActionArg}) - return entry.Action, entry.ActionArg, true, ipAddr, err - } - } - e.Cache.Add(cacheKey{host, port, isUDP}, cacheValue{e.DefaultAction, ""}) - return e.DefaultAction, "", true, ipAddr, err - } else { - // IP - if v, ok := e.Cache.Get(cacheKey{ip.String(), port, isUDP}); ok { - // Cache hit - ce := v.(cacheValue) - return ce.Action, ce.Arg, false, &net.IPAddr{ - IP: ip, - Zone: zone, - }, nil - } - for _, entry := range e.Entries { - mReq := MatchRequest{ - IP: ip, - Port: port, - DB: e.GeoIPReader, - } - if isUDP { - mReq.Protocol = ProtocolUDP - } else { - mReq.Protocol = ProtocolTCP - } - if entry.Match(mReq) { - e.Cache.Add(cacheKey{ip.String(), port, isUDP}, - cacheValue{entry.Action, entry.ActionArg}) - return entry.Action, entry.ActionArg, false, &net.IPAddr{ - IP: ip, - Zone: zone, - }, nil - } - } - e.Cache.Add(cacheKey{ip.String(), port, isUDP}, cacheValue{e.DefaultAction, ""}) - return e.DefaultAction, "", false, &net.IPAddr{ - IP: ip, - Zone: zone, - }, nil - } -} diff --git a/transport/hysteria/acl/engine_test.go b/transport/hysteria/acl/engine_test.go deleted file mode 100644 index 4c30884d..00000000 --- a/transport/hysteria/acl/engine_test.go +++ /dev/null @@ -1,154 +0,0 @@ -package acl - -import ( - "errors" - lru "github.com/hashicorp/golang-lru" - "net" - "strings" - "testing" -) - -func TestEngine_ResolveAndMatch(t *testing.T) { - cache, _ := lru.NewARC(16) - e := &Engine{ - DefaultAction: ActionDirect, - Entries: []Entry{ - { - Action: ActionProxy, - ActionArg: "", - Matcher: &domainMatcher{ - matcherBase: matcherBase{ - Protocol: ProtocolTCP, - Port: 443, - }, - Domain: "google.com", - Suffix: false, - }, - }, - { - Action: ActionHijack, - ActionArg: "good.org", - Matcher: &domainMatcher{ - matcherBase: matcherBase{}, - Domain: "evil.corp", - Suffix: true, - }, - }, - { - Action: ActionProxy, - ActionArg: "", - Matcher: &netMatcher{ - matcherBase: matcherBase{}, - Net: &net.IPNet{ - IP: net.ParseIP("10.0.0.0"), - Mask: net.CIDRMask(8, 32), - }, - }, - }, - { - Action: ActionBlock, - ActionArg: "", - Matcher: &allMatcher{}, - }, - }, - Cache: cache, - ResolveIPAddr: func(s string) (*net.IPAddr, error) { - if strings.Contains(s, "evil.corp") { - return nil, errors.New("resolve error") - } - return net.ResolveIPAddr("ip", s) - }, - } - tests := []struct { - name string - host string - port uint16 - isUDP bool - wantAction Action - wantArg string - wantErr bool - }{ - { - name: "domain proxy", - host: "google.com", - port: 443, - isUDP: false, - wantAction: ActionProxy, - wantArg: "", - }, - { - name: "domain block", - host: "google.com", - port: 80, - isUDP: false, - wantAction: ActionBlock, - wantArg: "", - }, - { - name: "domain suffix 1", - host: "evil.corp", - port: 8899, - isUDP: true, - wantAction: ActionHijack, - wantArg: "good.org", - wantErr: true, - }, - { - name: "domain suffix 2", - host: "notevil.corp", - port: 22, - isUDP: false, - wantAction: ActionBlock, - wantArg: "", - wantErr: true, - }, - { - name: "domain suffix 3", - host: "im.real.evil.corp", - port: 443, - isUDP: true, - wantAction: ActionHijack, - wantArg: "good.org", - wantErr: true, - }, - { - name: "ip match", - host: "10.2.3.4", - port: 80, - isUDP: false, - wantAction: ActionProxy, - wantArg: "", - }, - { - name: "ip mismatch", - host: "100.5.6.0", - port: 1234, - isUDP: false, - wantAction: ActionBlock, - wantArg: "", - }, - { - name: "domain proxy cache", - host: "google.com", - port: 443, - isUDP: false, - wantAction: ActionProxy, - wantArg: "", - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - gotAction, gotArg, _, _, err := e.ResolveAndMatch(tt.host, tt.port, tt.isUDP) - if (err != nil) != tt.wantErr { - t.Errorf("ResolveAndMatch() error = %v, wantErr %v", err, tt.wantErr) - return - } - if gotAction != tt.wantAction { - t.Errorf("ResolveAndMatch() gotAction = %v, wantAction %v", gotAction, tt.wantAction) - } - if gotArg != tt.wantArg { - t.Errorf("ResolveAndMatch() gotArg = %v, wantAction %v", gotArg, tt.wantArg) - } - }) - } -} diff --git a/transport/hysteria/acl/entry.go b/transport/hysteria/acl/entry.go deleted file mode 100644 index bc345aa1..00000000 --- a/transport/hysteria/acl/entry.go +++ /dev/null @@ -1,331 +0,0 @@ -package acl - -import ( - "errors" - "fmt" - "github.com/oschwald/geoip2-golang" - "net" - "strconv" - "strings" -) - -type Action byte -type Protocol byte - -const ( - ActionDirect = Action(iota) - ActionProxy - ActionBlock - ActionHijack -) - -const ( - ProtocolAll = Protocol(iota) - ProtocolTCP - ProtocolUDP -) - -var protocolPortAliases = map[string]string{ - "echo": "*/7", - "ftp-data": "*/20", - "ftp": "*/21", - "ssh": "*/22", - "telnet": "*/23", - "domain": "*/53", - "dns": "*/53", - "http": "*/80", - "sftp": "*/115", - "ntp": "*/123", - "https": "*/443", - "quic": "udp/443", - "socks": "*/1080", -} - -type Entry struct { - Action Action - ActionArg string - Matcher Matcher -} - -type MatchRequest struct { - IP net.IP - Domain string - - Protocol Protocol - Port uint16 - - DB *geoip2.Reader -} - -type Matcher interface { - Match(MatchRequest) bool -} - -type matcherBase struct { - Protocol Protocol - Port uint16 // 0 for all ports -} - -func (m *matcherBase) MatchProtocolPort(p Protocol, port uint16) bool { - return (m.Protocol == ProtocolAll || m.Protocol == p) && (m.Port == 0 || m.Port == port) -} - -func parseProtocolPort(s string) (Protocol, uint16, error) { - if protocolPortAliases[s] != "" { - s = protocolPortAliases[s] - } - if len(s) == 0 || s == "*" { - return ProtocolAll, 0, nil - } - parts := strings.Split(s, "/") - if len(parts) != 2 { - return ProtocolAll, 0, errors.New("invalid protocol/port syntax") - } - protocol := ProtocolAll - switch parts[0] { - case "tcp": - protocol = ProtocolTCP - case "udp": - protocol = ProtocolUDP - case "*": - protocol = ProtocolAll - default: - return ProtocolAll, 0, errors.New("invalid protocol") - } - if parts[1] == "*" { - return protocol, 0, nil - } - port, err := strconv.ParseUint(parts[1], 10, 16) - if err != nil { - return ProtocolAll, 0, errors.New("invalid port") - } - return protocol, uint16(port), nil -} - -type netMatcher struct { - matcherBase - Net *net.IPNet -} - -func (m *netMatcher) Match(r MatchRequest) bool { - if r.IP == nil { - return false - } - return m.Net.Contains(r.IP) && m.MatchProtocolPort(r.Protocol, r.Port) -} - -type domainMatcher struct { - matcherBase - Domain string - Suffix bool -} - -func (m *domainMatcher) Match(r MatchRequest) bool { - if len(r.Domain) == 0 { - return false - } - domain := strings.ToLower(r.Domain) - return (m.Domain == domain || (m.Suffix && strings.HasSuffix(domain, "."+m.Domain))) && - m.MatchProtocolPort(r.Protocol, r.Port) -} - -type countryMatcher struct { - matcherBase - Country string // ISO 3166-1 alpha-2 country code, upper case -} - -func (m *countryMatcher) Match(r MatchRequest) bool { - if r.IP == nil || r.DB == nil { - return false - } - c, err := r.DB.Country(r.IP) - if err != nil { - return false - } - return c.Country.IsoCode == m.Country && m.MatchProtocolPort(r.Protocol, r.Port) -} - -type allMatcher struct { - matcherBase -} - -func (m *allMatcher) Match(r MatchRequest) bool { - return m.MatchProtocolPort(r.Protocol, r.Port) -} - -func (e Entry) Match(r MatchRequest) bool { - return e.Matcher.Match(r) -} - -func ParseEntry(s string) (Entry, error) { - fields := strings.Fields(s) - if len(fields) < 2 { - return Entry{}, fmt.Errorf("expected at least 2 fields, got %d", len(fields)) - } - e := Entry{} - action := fields[0] - conds := fields[1:] - switch strings.ToLower(action) { - case "direct": - e.Action = ActionDirect - case "proxy": - e.Action = ActionProxy - case "block": - e.Action = ActionBlock - case "hijack": - if len(conds) < 2 { - return Entry{}, fmt.Errorf("hijack requires at least 3 fields, got %d", len(fields)) - } - e.Action = ActionHijack - e.ActionArg = conds[len(conds)-1] - conds = conds[:len(conds)-1] - default: - return Entry{}, fmt.Errorf("invalid action %s", fields[0]) - } - m, err := condsToMatcher(conds) - if err != nil { - return Entry{}, err - } - e.Matcher = m - return e, nil -} - -func condsToMatcher(conds []string) (Matcher, error) { - if len(conds) < 1 { - return nil, errors.New("no condition specified") - } - typ, args := conds[0], conds[1:] - switch strings.ToLower(typ) { - case "domain": - // domain - if len(args) == 0 || len(args) > 2 { - return nil, fmt.Errorf("invalid number of arguments for domain: %d, expected 1 or 2", len(args)) - } - mb := matcherBase{} - if len(args) == 2 { - protocol, port, err := parseProtocolPort(args[1]) - if err != nil { - return nil, err - } - mb.Protocol = protocol - mb.Port = port - } - return &domainMatcher{ - matcherBase: mb, - Domain: args[0], - Suffix: false, - }, nil - case "domain-suffix": - // domain-suffix - if len(args) == 0 || len(args) > 2 { - return nil, fmt.Errorf("invalid number of arguments for domain-suffix: %d, expected 1 or 2", len(args)) - } - mb := matcherBase{} - if len(args) == 2 { - protocol, port, err := parseProtocolPort(args[1]) - if err != nil { - return nil, err - } - mb.Protocol = protocol - mb.Port = port - } - return &domainMatcher{ - matcherBase: mb, - Domain: args[0], - Suffix: true, - }, nil - case "cidr": - // cidr - if len(args) == 0 || len(args) > 2 { - return nil, fmt.Errorf("invalid number of arguments for cidr: %d, expected 1 or 2", len(args)) - } - mb := matcherBase{} - if len(args) == 2 { - protocol, port, err := parseProtocolPort(args[1]) - if err != nil { - return nil, err - } - mb.Protocol = protocol - mb.Port = port - } - _, ipNet, err := net.ParseCIDR(args[0]) - if err != nil { - return nil, err - } - return &netMatcher{ - matcherBase: mb, - Net: ipNet, - }, nil - case "ip": - // ip - if len(args) == 0 || len(args) > 2 { - return nil, fmt.Errorf("invalid number of arguments for ip: %d, expected 1 or 2", len(args)) - } - mb := matcherBase{} - if len(args) == 2 { - protocol, port, err := parseProtocolPort(args[1]) - if err != nil { - return nil, err - } - mb.Protocol = protocol - mb.Port = port - } - ip := net.ParseIP(args[0]) - if ip == nil { - return nil, fmt.Errorf("invalid ip: %s", args[0]) - } - var ipNet *net.IPNet - if ip.To4() != nil { - ipNet = &net.IPNet{ - IP: ip, - Mask: net.CIDRMask(32, 32), - } - } else { - ipNet = &net.IPNet{ - IP: ip, - Mask: net.CIDRMask(128, 128), - } - } - return &netMatcher{ - matcherBase: mb, - Net: ipNet, - }, nil - case "country": - // country - if len(args) == 0 || len(args) > 2 { - return nil, fmt.Errorf("invalid number of arguments for country: %d, expected 1 or 2", len(args)) - } - mb := matcherBase{} - if len(args) == 2 { - protocol, port, err := parseProtocolPort(args[1]) - if err != nil { - return nil, err - } - mb.Protocol = protocol - mb.Port = port - } - return &countryMatcher{ - matcherBase: mb, - Country: strings.ToUpper(args[0]), - }, nil - case "all": - // all - if len(args) > 1 { - return nil, fmt.Errorf("invalid number of arguments for all: %d, expected 0 or 1", len(args)) - } - mb := matcherBase{} - if len(args) == 1 { - protocol, port, err := parseProtocolPort(args[0]) - if err != nil { - return nil, err - } - mb.Protocol = protocol - mb.Port = port - } - return &allMatcher{ - matcherBase: mb, - }, nil - default: - return nil, fmt.Errorf("invalid condition type: %s", typ) - } -} diff --git a/transport/hysteria/acl/entry_test.go b/transport/hysteria/acl/entry_test.go deleted file mode 100644 index 37b88071..00000000 --- a/transport/hysteria/acl/entry_test.go +++ /dev/null @@ -1,75 +0,0 @@ -package acl - -import ( - "net" - "reflect" - "testing" -) - -func TestParseEntry(t *testing.T) { - _, ok3net, _ := net.ParseCIDR("8.8.8.0/24") - - type args struct { - s string - } - tests := []struct { - name string - args args - want Entry - wantErr bool - }{ - {name: "empty", args: args{""}, want: Entry{}, wantErr: true}, - {name: "ok 1", args: args{"direct domain-suffix google.com"}, - want: Entry{ActionDirect, "", &domainMatcher{ - matcherBase: matcherBase{}, - Domain: "google.com", - Suffix: true, - }}, - wantErr: false}, - {name: "ok 2", args: args{"proxy domain shithole"}, - want: Entry{ActionProxy, "", &domainMatcher{ - matcherBase: matcherBase{}, - Domain: "shithole", - Suffix: false, - }}, - wantErr: false}, - {name: "ok 3", args: args{"block cidr 8.8.8.0/24 */53"}, - want: Entry{ActionBlock, "", &netMatcher{ - matcherBase: matcherBase{ProtocolAll, 53}, - Net: ok3net, - }}, - wantErr: false}, - {name: "ok 4", args: args{"hijack all udp/* udpblackhole.net"}, - want: Entry{ActionHijack, "udpblackhole.net", &allMatcher{ - matcherBase: matcherBase{ProtocolUDP, 0}, - }}, - wantErr: false}, - {name: "err 1", args: args{"what the heck"}, - want: Entry{}, - wantErr: true}, - {name: "err 2", args: args{"proxy sucks ass"}, - want: Entry{}, - wantErr: true}, - {name: "err 3", args: args{"block ip 999.999.999.999"}, - want: Entry{}, - wantErr: true}, - {name: "err 4", args: args{"hijack domain google.com"}, - want: Entry{}, - wantErr: true}, - {name: "err 5", args: args{"hijack domain google.com bing.com 123"}, - want: Entry{}, - wantErr: true}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - got, err := ParseEntry(tt.args.s) - if (err != nil) != tt.wantErr { - t.Errorf("ParseEntry() error = %v, wantErr %v", err, tt.wantErr) - return - } - if !reflect.DeepEqual(got, tt.want) { - t.Errorf("ParseEntry() got = %v, wantAction %v", got, tt.want) - } - }) - } -} From b0fed73236f74bbaf031437aedead5dde824f18b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?YuSaki=E4=B8=B6Kanade?= <53483352+Nep-Timeline@users.noreply.github.com> Date: Tue, 1 Aug 2023 17:30:57 +0800 Subject: [PATCH 69/79] Fix: mapping dns should not stale (#675) * Fix: mapping dns should not stale * Update enhancer.go --- dns/enhancer.go | 2 +- dns/middleware.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/dns/enhancer.go b/dns/enhancer.go index 76d4460e..ab144fd3 100644 --- a/dns/enhancer.go +++ b/dns/enhancer.go @@ -109,7 +109,7 @@ func NewEnhancer(cfg Config) *ResolverEnhancer { if cfg.EnhancedMode != C.DNSNormal { fakePool = cfg.Pool - mapping = cache.New(cache.WithSize[netip.Addr, string](4096), cache.WithStale[netip.Addr, string](true)) + mapping = cache.New(cache.WithSize[netip.Addr, string](4096)) } return &ResolverEnhancer{ diff --git a/dns/middleware.go b/dns/middleware.go index f2dd9c96..695432da 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -129,6 +129,10 @@ func withMapping(mapping *cache.LruCache[netip.Addr, string]) middleware { continue } + if ttl < 1 { + ttl = 1 + } + mapping.SetWithExpire(ip, host, time.Now().Add(time.Second*time.Duration(ttl))) } From 191243a1d2a8252c76092e65864e338f5e93db62 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 3 Aug 2023 23:07:30 +0800 Subject: [PATCH 70/79] chore: better tuicV5 deFragger --- common/cache/lrucache.go | 42 +++++++++++++++--- transport/tuic/v4/server.go | 8 ++-- transport/tuic/v5/frag.go | 85 +++++++++++++++++++++++++------------ transport/tuic/v5/packet.go | 14 +++--- transport/tuic/v5/server.go | 6 +-- 5 files changed, 105 insertions(+), 50 deletions(-) diff --git a/common/cache/lrucache.go b/common/cache/lrucache.go index 73600e71..1373b0be 100644 --- a/common/cache/lrucache.go +++ b/common/cache/lrucache.go @@ -82,6 +82,9 @@ func New[K comparable, V any](options ...Option[K, V]) *LruCache[K, V] { // Get returns the any representation of a cached response and a bool // set to true if the key was found. func (c *LruCache[K, V]) Get(key K) (V, bool) { + c.mu.Lock() + defer c.mu.Unlock() + el := c.get(key) if el == nil { return getZero[V](), false @@ -91,11 +94,29 @@ func (c *LruCache[K, V]) Get(key K) (V, bool) { return value, true } +func (c *LruCache[K, V]) GetOrStore(key K, constructor func() V) (V, bool) { + c.mu.Lock() + defer c.mu.Unlock() + + el := c.get(key) + if el == nil { + value := constructor() + c.set(key, value) + return value, false + } + value := el.value + + return value, true +} + // GetWithExpire returns the any representation of a cached response, // a time.Time Give expected expires, // and a bool set to true if the key was found. // This method will NOT check the maxAge of element and will NOT update the expires. func (c *LruCache[K, V]) GetWithExpire(key K) (V, time.Time, bool) { + c.mu.Lock() + defer c.mu.Unlock() + el := c.get(key) if el == nil { return getZero[V](), time.Time{}, false @@ -115,11 +136,18 @@ func (c *LruCache[K, V]) Exist(key K) bool { // Set stores the any representation of a response for a given key. func (c *LruCache[K, V]) Set(key K, value V) { + c.mu.Lock() + defer c.mu.Unlock() + + c.set(key, value) +} + +func (c *LruCache[K, V]) set(key K, value V) { expires := int64(0) if c.maxAge > 0 { expires = time.Now().Unix() + c.maxAge } - c.SetWithExpire(key, value, time.Unix(expires, 0)) + c.setWithExpire(key, value, time.Unix(expires, 0)) } // SetWithExpire stores the any representation of a response for a given key and given expires. @@ -128,6 +156,10 @@ func (c *LruCache[K, V]) SetWithExpire(key K, value V, expires time.Time) { c.mu.Lock() defer c.mu.Unlock() + c.setWithExpire(key, value, expires) +} + +func (c *LruCache[K, V]) setWithExpire(key K, value V, expires time.Time) { if le, ok := c.cache[key]; ok { c.lru.MoveToBack(le) e := le.Value @@ -165,9 +197,6 @@ func (c *LruCache[K, V]) CloneTo(n *LruCache[K, V]) { } func (c *LruCache[K, V]) get(key K) *entry[K, V] { - c.mu.Lock() - defer c.mu.Unlock() - le, ok := c.cache[key] if !ok { return nil @@ -191,12 +220,11 @@ func (c *LruCache[K, V]) get(key K) *entry[K, V] { // Delete removes the value associated with a key. func (c *LruCache[K, V]) Delete(key K) { c.mu.Lock() + defer c.mu.Unlock() if le, ok := c.cache[key]; ok { c.deleteElement(le) } - - c.mu.Unlock() } func (c *LruCache[K, V]) maybeDeleteOldest() { @@ -219,10 +247,10 @@ func (c *LruCache[K, V]) deleteElement(le *list.Element[*entry[K, V]]) { func (c *LruCache[K, V]) Clear() error { c.mu.Lock() + defer c.mu.Unlock() c.cache = make(map[K]*list.Element[*entry[K, V]]) - c.mu.Unlock() return nil } diff --git a/transport/tuic/v4/server.go b/transport/tuic/v4/server.go index 9513ccfd..b0012d96 100644 --- a/transport/tuic/v4/server.go +++ b/transport/tuic/v4/server.go @@ -66,10 +66,10 @@ func (s *serverHandler) HandleMessage(message []byte) (err error) { if err != nil { return } - return s.parsePacket(packet, common.NATIVE) + return s.parsePacket(&packet, common.NATIVE) } -func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayMode) (err error) { +func (s *serverHandler) parsePacket(packet *Packet, udpRelayMode common.UdpRelayMode) (err error) { <-s.authCh if !s.authOk.Load() { return @@ -97,7 +97,7 @@ func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayM return s.HandleUdpFn(packet.ADDR.SocksAddr(), &serverUDPPacket{ pc: pc, - packet: &packet, + packet: packet, rAddr: N.NewCustomAddr("tuic", fmt.Sprintf("tuic-%s-%d", s.uuid, assocId), s.quicConn.RemoteAddr()), // for tunnel's handleUDPConn }) } @@ -166,7 +166,7 @@ func (s *serverHandler) HandleUniStream(reader *bufio.Reader) (err error) { if err != nil { return } - return s.parsePacket(packet, common.QUIC) + return s.parsePacket(&packet, common.QUIC) case DissociateType: var disassociate Dissociate disassociate, err = ReadDissociateWithHead(commandHead, reader) diff --git a/transport/tuic/v5/frag.go b/transport/tuic/v5/frag.go index 30b7b3f5..ae9dbf10 100644 --- a/transport/tuic/v5/frag.go +++ b/transport/tuic/v5/frag.go @@ -2,6 +2,9 @@ package v5 import ( "bytes" + "sync" + + "github.com/Dreamacro/clash/common/cache" "github.com/metacubex/quic-go" ) @@ -39,42 +42,68 @@ func fragWriteNative(quicConn quic.Connection, packet Packet, buf *bytes.Buffer, } type deFragger struct { - pkgID uint16 - frags []*Packet - count uint8 + lru *cache.LruCache[uint16, *packetBag] + once sync.Once } -func (d *deFragger) Feed(m Packet) *Packet { +type packetBag struct { + frags []*Packet + count uint8 + mutex sync.Mutex +} + +func newPacketBag() *packetBag { + return new(packetBag) +} + +func (d *deFragger) init() { + if d.lru == nil { + d.lru = cache.New( + cache.WithAge[uint16, *packetBag](10), + cache.WithUpdateAgeOnGet[uint16, *packetBag](), + ) + } +} + +func (d *deFragger) Feed(m *Packet) *Packet { if m.FRAG_TOTAL <= 1 { - return &m + return m } if m.FRAG_ID >= m.FRAG_TOTAL { // wtf is this? return nil } - if d.count == 0 || m.PKT_ID != d.pkgID { + d.once.Do(d.init) // lazy init + bag, _ := d.lru.GetOrStore(m.PKT_ID, newPacketBag) + bag.mutex.Lock() + defer bag.mutex.Unlock() + if int(m.FRAG_TOTAL) != len(bag.frags) { // new message, clear previous state - d.pkgID = m.PKT_ID - d.frags = make([]*Packet, m.FRAG_TOTAL) - d.count = 1 - d.frags[m.FRAG_ID] = &m - } else if d.frags[m.FRAG_ID] == nil { - d.frags[m.FRAG_ID] = &m - d.count++ - if int(d.count) == len(d.frags) { - // all fragments received, assemble - var data []byte - for _, frag := range d.frags { - data = append(data, frag.DATA...) - } - p := d.frags[0] // recover from first fragment - p.SIZE = uint16(len(data)) - p.DATA = data - p.FRAG_ID = 0 - p.FRAG_TOTAL = 1 - d.count = 0 - return p - } + bag.frags = make([]*Packet, m.FRAG_TOTAL) + bag.count = 1 + bag.frags[m.FRAG_ID] = m + return nil } - return nil + if bag.frags[m.FRAG_ID] != nil { + return nil + } + bag.frags[m.FRAG_ID] = m + bag.count++ + if int(bag.count) != len(bag.frags) { + return nil + } + + // all fragments received, assemble + var data []byte + for _, frag := range bag.frags { + data = append(data, frag.DATA...) + } + p := *bag.frags[0] // recover from first fragment + p.SIZE = uint16(len(data)) + p.DATA = data + p.FRAG_ID = 0 + p.FRAG_TOTAL = 1 + bag.frags = nil + d.lru.Delete(m.PKT_ID) + return &p } diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go index 4a11d671..cd3ed12b 100644 --- a/transport/tuic/v5/packet.go +++ b/transport/tuic/v5/packet.go @@ -103,7 +103,7 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err if err != nil { return } - if packetPtr := q.deFragger.Feed(packet); packetPtr != nil { + if packetPtr := q.deFragger.Feed(&packet); packetPtr != nil { n = copy(p, packet.DATA) addr = packetPtr.ADDR.UDPAddr() return @@ -123,7 +123,7 @@ func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net if err != nil { return } - if packetPtr := q.deFragger.Feed(packet); packetPtr != nil { + if packetPtr := q.deFragger.Feed(&packet); packetPtr != nil { data = packetPtr.DATA addr = packetPtr.ADDR.UDPAddr() return @@ -178,16 +178,14 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro default: // native if len(p) > q.maxUdpRelayPacketSize { err = fragWriteNative(q.quicConn, packet, buf, q.maxUdpRelayPacketSize) + } else { + err = packet.WriteTo(buf) if err != nil { return } + data := buf.Bytes() + err = q.quicConn.SendMessage(data) } - err = packet.WriteTo(buf) - if err != nil { - return - } - data := buf.Bytes() - err = q.quicConn.SendMessage(data) var tooLarge quic.ErrMessageTooLarge if errors.As(err, &tooLarge) { diff --git a/transport/tuic/v5/server.go b/transport/tuic/v5/server.go index 96b3d24f..30259583 100644 --- a/transport/tuic/v5/server.go +++ b/transport/tuic/v5/server.go @@ -73,7 +73,7 @@ func (s *serverHandler) HandleMessage(message []byte) (err error) { if err != nil { return } - return s.parsePacket(packet, common.NATIVE) + return s.parsePacket(&packet, common.NATIVE) case HeartbeatType: var heartbeat Heartbeat heartbeat, err = ReadHeartbeatWithHead(commandHead, reader) @@ -85,7 +85,7 @@ func (s *serverHandler) HandleMessage(message []byte) (err error) { return } -func (s *serverHandler) parsePacket(packet Packet, udpRelayMode common.UdpRelayMode) (err error) { +func (s *serverHandler) parsePacket(packet *Packet, udpRelayMode common.UdpRelayMode) (err error) { <-s.authCh if !s.authOk.Load() { return @@ -179,7 +179,7 @@ func (s *serverHandler) HandleUniStream(reader *bufio.Reader) (err error) { if err != nil { return } - return s.parsePacket(packet, common.QUIC) + return s.parsePacket(&packet, common.QUIC) case DissociateType: var disassociate Dissociate disassociate, err = ReadDissociateWithHead(commandHead, reader) From 68f312288d82edc89f9e9eef29fe0990781058a8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 5 Aug 2023 12:53:49 +0800 Subject: [PATCH 71/79] chore: update quic-go to 0.37.2 and go1.21rc4 --- .github/workflows/build.yml | 2 +- go.mod | 4 ++-- go.sum | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b66257c0..806bf9ee 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,7 +128,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.21.0-rc.3" + go-version: "1.21.0-rc.4" check-latest: true - name: Test diff --git a/go.mod b/go.mod index a2bbff7c..b769b893 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.37.2-0.20230801015013-c321217d291b + github.com/metacubex/quic-go v0.37.3-0.20230805044943-1fefbff06fed github.com/metacubex/sing-shadowsocks v0.2.4 github.com/metacubex/sing-shadowsocks2 v0.1.3 github.com/metacubex/sing-tun v0.1.11 @@ -82,7 +82,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.0 // indirect + github.com/quic-go/qtls-go1-20 v0.3.1 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect diff --git a/go.sum b/go.sum index 0e1a19aa..d5215bc8 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,8 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.37.2-0.20230801015013-c321217d291b h1:oVYQtX4v8yT5CYI8oc8G6ZTnh5lzwvMOkwyGwcuIoGc= -github.com/metacubex/quic-go v0.37.2-0.20230801015013-c321217d291b/go.mod h1:runF6UZHW4A/P/VU+PtfQKKD85YgaZgrgbvCTs5Nwbk= +github.com/metacubex/quic-go v0.37.3-0.20230805044943-1fefbff06fed h1:gfosK9auM2PsR+4gnXfJ+As/dcfS6j0brv0zGBuontc= +github.com/metacubex/quic-go v0.37.3-0.20230805044943-1fefbff06fed/go.mod h1:HhHoyskMk4kzfLPKcm7EF7pGXF89KRVwjbGrEaN6lIU= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7 h1:XY3Y6nPL45XuN/k3rDXJ1TJknLo8rTo1SVuDOmOEf4E= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/metacubex/sing-shadowsocks v0.2.4 h1:Gc99Z17JVif1PKKq1pjqhSmc2kvHUgk+AqxOstCzhQ0= @@ -132,8 +132,8 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:Om github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-20 v0.3.0 h1:NrCXmDl8BddZwO67vlvEpBTwT89bJfKYygxv4HQvuDk= -github.com/quic-go/qtls-go1-20 v0.3.0/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg= +github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= From 09ec7c8a62a10070d6675991b000e1165df1c93f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 6 Aug 2023 09:45:51 +0800 Subject: [PATCH 72/79] chore: update quic-go to 0.37.3 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b769b893..2afa7013 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.37.3-0.20230805044943-1fefbff06fed + github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12 github.com/metacubex/sing-shadowsocks v0.2.4 github.com/metacubex/sing-shadowsocks2 v0.1.3 github.com/metacubex/sing-tun v0.1.11 diff --git a/go.sum b/go.sum index d5215bc8..9e5e7ed3 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,8 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.37.3-0.20230805044943-1fefbff06fed h1:gfosK9auM2PsR+4gnXfJ+As/dcfS6j0brv0zGBuontc= -github.com/metacubex/quic-go v0.37.3-0.20230805044943-1fefbff06fed/go.mod h1:HhHoyskMk4kzfLPKcm7EF7pGXF89KRVwjbGrEaN6lIU= +github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12 h1:18tcXxLgwjUjs38QM1E1a+AAh4j+Mo/mKcJTmqHrN9c= +github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12/go.mod h1:HhHoyskMk4kzfLPKcm7EF7pGXF89KRVwjbGrEaN6lIU= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7 h1:XY3Y6nPL45XuN/k3rDXJ1TJknLo8rTo1SVuDOmOEf4E= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/metacubex/sing-shadowsocks v0.2.4 h1:Gc99Z17JVif1PKKq1pjqhSmc2kvHUgk+AqxOstCzhQ0= From cca701c641edb5af9808322bead485fa1dc1bf0a Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 6 Aug 2023 18:38:50 +0800 Subject: [PATCH 73/79] chore: Update dependencies --- go.mod | 14 ++--- go.sum | 27 +++++----- test/go.mod | 69 ++++++++++++------------ test/go.sum | 148 +++++++++++++++++++++++++--------------------------- 4 files changed, 125 insertions(+), 133 deletions(-) diff --git a/go.mod b/go.mod index 2afa7013..95676975 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/3andne/restls-client-go v0.1.4 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da github.com/cilium/ebpf v0.11.0 - github.com/coreos/go-iptables v0.6.0 + github.com/coreos/go-iptables v0.7.0 github.com/dlclark/regexp2 v1.10.0 github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 @@ -26,7 +26,7 @@ require ( github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8 github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 github.com/miekg/dns v1.1.55 - github.com/mroth/weightedrand/v2 v2.0.1 + github.com/mroth/weightedrand/v2 v2.0.2 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 @@ -43,11 +43,11 @@ require ( github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.3 - golang.org/x/crypto v0.11.0 - golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 - golang.org/x/net v0.12.0 + golang.org/x/crypto v0.12.0 + golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b + golang.org/x/net v0.14.0 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.10.0 + golang.org/x/sys v0.11.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 @@ -97,7 +97,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect golang.org/x/mod v0.11.0 // indirect - golang.org/x/text v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.9.1 // indirect ) diff --git a/go.sum b/go.sum index 9e5e7ed3..344e8991 100644 --- a/go.sum +++ b/go.sum @@ -16,8 +16,8 @@ github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5P github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= -github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= -github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= +github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= 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= @@ -108,8 +108,8 @@ github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxf github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= -github.com/mroth/weightedrand/v2 v2.0.1 h1:zrEVDIaau/E4QLOKu02kpg8T8myweFlMGikIgbIdrRA= -github.com/mroth/weightedrand/v2 v2.0.1/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= +github.com/mroth/weightedrand/v2 v2.0.2 h1:A8wJRUBcfguGl6oOQHI8fy5P4ViGRT9hdQdlG/7RiXo= +github.com/mroth/weightedrand/v2 v2.0.2/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= @@ -203,10 +203,10 @@ go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= 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.11.0 h1:6Ewdq3tDic1mg5xRO4milcWCfMVQhI4NkqWWvqejpuA= -golang.org/x/crypto v0.11.0/go.mod h1:xgJhtzW8F9jGdVFWZESrid1U1bjeNy4zgy5cRr/CIio= -golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691 h1:/yRP+0AN7mf5DkD3BAI6TOFnd51gEoDEb8o35jIFtgw= -golang.org/x/exp v0.0.0-20230728194245-b0cb94b80691/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI= +golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -215,8 +215,8 @@ golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= -golang.org/x/net v0.12.0/go.mod h1:zEVYFnQC7m/vmpQFELhcD1EWkZlX69l4oqgmer6hfKA= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= 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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= @@ -238,13 +238,14 @@ golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0 h1:SqMFp9UcQJZa+pmYuAKjd9xq1f0j5rLcDIk0mj4qAsA= golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.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= -golang.org/x/text v0.11.0 h1:LAntKIrcmeSKERyiOh0XMV39LXS8IE9UL2yP7+f5ij4= -golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= 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 957c444b..80f958a5 100644 --- a/test/go.mod +++ b/test/go.mod @@ -6,9 +6,9 @@ require ( github.com/Dreamacro/clash v0.0.0 github.com/docker/docker v20.10.21+incompatible github.com/docker/go-connections v0.4.0 - github.com/miekg/dns v1.1.54 - github.com/stretchr/testify v1.8.3 - golang.org/x/net v0.10.0 + github.com/miekg/dns v1.1.55 + github.com/stretchr/testify v1.8.4 + golang.org/x/net v0.14.0 ) replace github.com/Dreamacro/clash => ../ @@ -20,8 +20,8 @@ require ( github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/andybalholm/brotli v1.0.5 // indirect - github.com/cilium/ebpf v0.10.0 // indirect - github.com/coreos/go-iptables v0.6.0 // indirect + github.com/cilium/ebpf v0.11.0 // indirect + github.com/coreos/go-iptables v0.7.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/dlclark/regexp2 v1.10.0 // indirect github.com/docker/distribution v2.8.2+incompatible // indirect @@ -32,16 +32,16 @@ require ( github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-ole/go-ole v1.2.6 // indirect - github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gofrs/uuid/v5 v5.0.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/mock v1.6.0 // indirect - github.com/google/btree v1.0.1 // indirect + github.com/google/btree v1.1.2 // indirect github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/hashicorp/yamux v0.1.1 // indirect - github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb // indirect + github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c // indirect github.com/josharian/native v1.1.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.15.15 // indirect @@ -51,65 +51,62 @@ require ( github.com/mdlayher/netlink v1.7.2 // indirect github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect - github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c // indirect - github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb // indirect - github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c // indirect - github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca // indirect - github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e // indirect - github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a // indirect + github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 // indirect + github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12 // indirect + github.com/metacubex/sing-shadowsocks v0.2.4 // indirect + github.com/metacubex/sing-shadowsocks2 v0.1.3 // indirect + github.com/metacubex/sing-tun v0.1.11 // indirect + github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8 // indirect + github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect - github.com/mroth/weightedrand/v2 v2.0.1 // indirect + github.com/mroth/weightedrand/v2 v2.0.2 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect - github.com/onsi/ginkgo/v2 v2.2.0 // indirect + github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/openacid/low v0.1.21 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect - github.com/oschwald/geoip2-golang v1.8.0 // indirect - github.com/oschwald/maxminddb-golang v1.10.0 // indirect + github.com/oschwald/maxminddb-golang v1.12.0 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-19 v0.3.2 // indirect - github.com/quic-go/qtls-go1-20 v0.2.2 // indirect + github.com/quic-go/qtls-go1-20 v0.3.1 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 // indirect - github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c // indirect - github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 // indirect - github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3 // indirect - github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 // indirect + github.com/sagernet/sing v0.2.9 // indirect + github.com/sagernet/sing-mux v0.1.2 // indirect + github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 // indirect github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 // indirect github.com/samber/lo v1.38.1 // indirect github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 // indirect - github.com/shirou/gopsutil/v3 v3.23.5 // indirect + github.com/shirou/gopsutil/v3 v3.23.7 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e // indirect - github.com/sirupsen/logrus v1.9.2 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/tklauser/go-sysconf v0.3.11 // indirect github.com/tklauser/numcpus v0.6.0 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 // indirect github.com/yusufpapurcu/wmi v1.2.3 // indirect github.com/zhangyunhao116/fastrand v0.3.0 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.etcd.io/bbolt v1.3.7 // indirect - golang.org/x/crypto v0.9.0 // indirect - golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect - golang.org/x/mod v0.8.0 // indirect - golang.org/x/sync v0.2.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect - golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect - golang.org/x/tools v0.6.0 // indirect - google.golang.org/protobuf v1.30.0 // indirect + golang.org/x/crypto v0.12.0 // indirect + golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b // indirect + golang.org/x/mod v0.11.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/sys v0.11.0 // indirect + golang.org/x/text v0.12.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.9.1 // indirect + google.golang.org/protobuf v1.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect lukechampine.com/blake3 v1.2.1 // indirect ) diff --git a/test/go.sum b/test/go.sum index dc47342f..fbf635c6 100644 --- a/test/go.sum +++ b/test/go.sum @@ -15,10 +15,10 @@ github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnweb github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/cilium/ebpf v0.10.0 h1:nk5HPMeoBXtOzbkZBWym+ZWq1GIiHUsBFXxwewXAHLQ= -github.com/cilium/ebpf v0.10.0/go.mod h1:DPiVdY/kT534dgc9ERmvP8mWA+9gvwgKfRvk4nNWnoE= -github.com/coreos/go-iptables v0.6.0 h1:is9qnZMPYjLd8LYqmm/qlE+wwEgJIkTYdhV3rfZo4jk= -github.com/coreos/go-iptables v0.6.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= +github.com/cilium/ebpf v0.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= +github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= +github.com/coreos/go-iptables v0.7.0 h1:XWM3V+MPRr5/q51NuWSgU0fqMad64Zyxs8ZUoMsamr8= +github.com/coreos/go-iptables v0.7.0/go.mod h1:Qe8Bv2Xik5FyTXwgIbLAnv2sWSBmvWdFETJConOQ//Q= 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= @@ -41,13 +41,14 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBE github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4RfsapbGx2j/vU5xC/5/9qB3kn9Awp1YDiEnN43QrJ4= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 h1:fuGucgPk5dN6wzfnxl3D0D3rVLw4v2SbBT9jb4VnxzA= github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010/go.mod h1:JtBcj7sBuTTRupn7c2bFspMDIObMJsVK8TeUvpShPok= -github.com/frankban/quicktest v1.14.4 h1:g2rn0vABPOOXmZUj+vbmUp0lPoXEMuhTpIluN0XL9UY= +github.com/frankban/quicktest v1.14.5 h1:dfYrrRyLtiqT9GyKXgdh+k4inNeTvmGbuSgZ3lx3GhA= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= +github.com/go-logr/logr v1.2.4 h1:g01GSCwiDw2xSZfjJ2/T9M+S6pFdcNtFYsp+Y43HYDQ= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= -github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= +github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/gofrs/uuid/v5 v5.0.0 h1:p544++a97kEL+svbcFbCQVM9KFu0Yo25UoISXGNNH9M= github.com/gofrs/uuid/v5 v5.0.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -56,9 +57,9 @@ github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= -github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4= -github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= +github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= +github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= @@ -71,8 +72,8 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad github.com/hashicorp/yamux v0.1.1 h1:yrQxtgseBDrq9Y652vSRDvsKCJKOUD+GzTS4Y0Y8pvE= github.com/hashicorp/yamux v0.1.1/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb h1:6fDKEAXwe3rsfS4khW3EZ8kEqmSiV9szhMPcDrD+Y7Q= -github.com/insomniacslk/dhcp v0.0.0-20230516061539-49801966e6cb/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= +github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs= +github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= github.com/josharian/native v1.0.1-0.20221213033349-c1e37c09b531/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA= github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= @@ -96,31 +97,33 @@ github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvOzK9ubNCCkQ+ldc4YSH/rILn53l/xGBFHHI= github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= -github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+3aI8tqfeyc6YgbfarYKywTnnvXwEM= -github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= -github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb h1:92YTNmYXCSycERjKn/zPbeK5DiW3dd80j3+oVTEWTE8= -github.com/metacubex/quic-go v0.35.2-0.20230603072621-ea2663348ebb/go.mod h1:6pg8+Tje9KOltnj1whuvB2i5KFUMPp1TAF3oPhc5axM= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c h1:LpVNvlW/xE+mR8z76xJeYZlYznZXEmU4TeWeuygYdJg= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca h1:10qc50Q1hHrfGO4NjEJpIAgHX63Y256tHE0dFCTN8J4= -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-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= -github.com/miekg/dns v1.1.54/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= +github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= +github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12 h1:18tcXxLgwjUjs38QM1E1a+AAh4j+Mo/mKcJTmqHrN9c= +github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12/go.mod h1:HhHoyskMk4kzfLPKcm7EF7pGXF89KRVwjbGrEaN6lIU= +github.com/metacubex/sing-shadowsocks v0.2.4 h1:Gc99Z17JVif1PKKq1pjqhSmc2kvHUgk+AqxOstCzhQ0= +github.com/metacubex/sing-shadowsocks v0.2.4/go.mod h1:w9qoEZSh9aKeXSLXHe0DGbG2UE9/2VlLGwukzQZ7byI= +github.com/metacubex/sing-shadowsocks2 v0.1.3 h1:nZvH+4jQXZ92NeNdR9fXaUGTPNJPt6u0nkcuh/NEt5Y= +github.com/metacubex/sing-shadowsocks2 v0.1.3/go.mod h1:5Mt93RlmRlIcDmvtapkhQJ8YTRGLFhHciLYopJjs7j8= +github.com/metacubex/sing-tun v0.1.11 h1:B8meDewklvKkeUfjqR2ViuYLam0/m4IgkTi3qcJIOuc= +github.com/metacubex/sing-tun v0.1.11/go.mod h1:vbki176Y5sxXC1DWXucrPh3q5j8cKai1D87y8m8rjQc= +github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8 h1:AqqZCr9gOeKdO6oIzFh4b2puOUFcw8MdpmGHWRehyX8= +github.com/metacubex/sing-vmess v0.1.8-0.20230801054944-603005461ff8/go.mod h1:tyJg7b4s8NrSztl/Y1ajA7X0sJLlIsEJWkgRVocjmgY= +github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= +github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28/go.mod h1:KrDPq/dE793jGIJw9kcIvjA/proAfU0IeU7WlMXW7rs= +github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= +github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= -github.com/mroth/weightedrand/v2 v2.0.1 h1:zrEVDIaau/E4QLOKu02kpg8T8myweFlMGikIgbIdrRA= -github.com/mroth/weightedrand/v2 v2.0.1/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= +github.com/mroth/weightedrand/v2 v2.0.2 h1:A8wJRUBcfguGl6oOQHI8fy5P4ViGRT9hdQdlG/7RiXo= +github.com/mroth/weightedrand/v2 v2.0.2/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7/go.mod h1:UqoUn6cHESlliMhOnKLWr+CBH+e3bazUPvFj1XZwAjs= -github.com/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= -github.com/onsi/ginkgo/v2 v2.2.0/go.mod h1:MEH45j8TBi6u9BMogfbp0stKC5cdGjumZj5Y7AG4VIk= -github.com/onsi/gomega v1.20.1 h1:PA/3qinGoukvymdIDV8pii6tiZgC8kbmJO6Z5+b002Q= +github.com/onsi/ginkgo/v2 v2.9.5 h1:+6Hr4uxzP4XIUyAkg61dWBw8lb/gc4/X5luuxN/EC+Q= +github.com/onsi/ginkgo/v2 v2.9.5/go.mod h1:tvAoo1QUJwNEU2ITftXTpR7R1RbCzoZUOs3RonqW57k= +github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE= github.com/openacid/errors v0.8.1/go.mod h1:GUQEJJOJE3W9skHm8E8Y4phdl2LLEN8iD7c5gcGgdx0= github.com/openacid/low v0.1.21 h1:Tr2GNu4N/+rGRYdOsEHOE89cxUIaDViZbVmKz29uKGo= github.com/openacid/low v0.1.21/go.mod h1:q+MsKI6Pz2xsCkzV4BLj7NR5M4EX0sGz5AqotpZDVh0= @@ -130,10 +133,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -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= -github.com/oschwald/maxminddb-golang v1.10.0/go.mod h1:Y2ELenReaLAZ0b400URyGwvYxHV1dLIxBuyOsyYjHK0= +github.com/oschwald/maxminddb-golang v1.12.0 h1:9FnTOD0YOhP7DGxGsq4glzpGy5+w7pq50AS6wALUMYs= +github.com/oschwald/maxminddb-golang v1.12.0/go.mod h1:q0Nob5lTCqyQ8WT6FYgS1L7PXKVVbgiymefNwIjPzgY= github.com/pierrec/lz4/v4 v4.1.14 h1:+fL8AQEZtz/ijeNnpduH0bROTu0O3NZAlPjQxGn8LwE= github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -144,10 +145,8 @@ github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= -github.com/quic-go/qtls-go1-19 v0.3.2 h1:tFxjCFcTQzK+oMxG6Zcvp4Dq8dx4yD3dDiIiyc86Z5U= -github.com/quic-go/qtls-go1-19 v0.3.2/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.2.2 h1:WLOPx6OY/hxtTxKV1Zrq20FtXtDEkeY00CGQm8GEa3E= -github.com/quic-go/qtls-go1-20 v0.2.2/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +github.com/quic-go/qtls-go1-20 v0.3.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg= +github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 h1:5+m7c6AkmAylhauulqN/c5dnh8/KssrE9c93TQrXldA= github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h1:QUQ4RRHD6hGGHdFMEtR8T2P6GS6R3D/CXKdaYHKKXms= @@ -155,14 +154,12 @@ github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6E 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/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c h1:OAwuwvyjPPsCCdSxqZA7T+ABNezeNbF68sRbcMkKT7M= -github.com/sagernet/sing v0.2.5-0.20230530114415-221f066dba7c/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646 h1:X3ADfMqeGns1Q1FlXc9kaL9FwW1UM6D6tEQo8jFstpc= -github.com/sagernet/sing-mux v0.0.0-20230517134606-1ebe6bb26646/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= -github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3 h1:PNwJs1F+3e/iZguYQR7YzxsH8Sm0Eu7vVuHawD89r34= -github.com/sagernet/sing-shadowtls v0.1.2-0.20230531025805-ebadc7615da3/go.mod h1:oG8bPerYI6cZ74KquY3DvA7ynECyrILPBnce6wtBqeI= -github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= -github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3/go.mod h1:yKrAr+dqZd64DxBXCHWrYicp+n4qbqO73mtwv3dck8U= +github.com/sagernet/sing v0.2.9 h1:3wsTz+JG5Wzy65eZnh6AuCrD2QqcRF6Iq6f7ttmJsAo= +github.com/sagernet/sing v0.2.9/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing-mux v0.1.2 h1:av2/m6e+Gh+ECTuJZqYCjJz55BNkot0VyRMkREqyF/g= +github.com/sagernet/sing-mux v0.1.2/go.mod h1:r2V8AlOzXaRCHXK7fILCUGzuI2iILweTaG8C5xlpHxo= +github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= +github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 h1:HuE6xSwco/Xed8ajZ+coeYLmioq0Qp1/Z2zczFaV8as= github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37/go.mod h1:3skNSftZDJWTGVtVaM2jfbce8qHnmH/AGDRe62iNOg0= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= @@ -175,8 +172,8 @@ github.com/samber/lo v1.38.1 h1:j2XEAqXKb09Am4ebOg31SpvzUTTs6EN3VfgeLUhPdXM= github.com/samber/lo v1.38.1/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh8n+csdOuDfP+NuykE0U6AeYSJJHKDgSg= github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= -github.com/shirou/gopsutil/v3 v3.23.5 h1:5SgDCeQ0KW0S4N0znjeM/eFHXXOKyv2dVNgRq/c9P6Y= -github.com/shirou/gopsutil/v3 v3.23.5/go.mod h1:Ng3Maa27Q2KARVJ0SPZF5NdrQSC3XHKP8IIWrHgMeLY= +github.com/shirou/gopsutil/v3 v3.23.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= +github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -187,19 +184,18 @@ github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c h1:DjKMC30y6y github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c/go.mod h1:NV/a66PhhWYVmUMaotlXJ8fIEFB98u+c8l/CQIEFLrU= github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e h1:ur8uMsPIFG3i4Gi093BQITvwH9znsz2VUZmnmwHvpIo= github.com/sina-ghaderi/rabbitio v0.0.0-20220730151941-9ce26f4f872e/go.mod h1:+e5fBW3bpPyo+3uLo513gIUblc03egGjMM0+5GKbzK8= -github.com/sirupsen/logrus v1.9.2 h1:oxx1eChJGI6Uks2ZC4W1zpLlVgqB8ner4EuQwV4Ik1Y= -github.com/sirupsen/logrus v1.9.2/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= -github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM= github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI= github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms= @@ -211,8 +207,6 @@ github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17 github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= -github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 h1:a3Y4WVjCxwoyO4E2xdNvq577tW8lkSBgyrA8E9+2NtM= -github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3/go.mod h1:YJTRELIWrGxR1s8xcEBgxcxBfwQfMGjdvNLTjN9XFgY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= @@ -227,30 +221,30 @@ go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw= 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.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc= -golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= +golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk= +golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw= +golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b h1:r+vk0EmXNmekl0S0BascoeeoHk/L7wmaW2QF90K+kYI= +golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= 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= -golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8= -golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= +golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= +golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= 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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= -golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -269,33 +263,33 @@ golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM= +golang.org/x/sys v0.11.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= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= -golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= +golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= -golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.9.1 h1:8WMNJAz3zrtPmnYC7ISf5dEn3MT0gY7jBJfw27yrrLo= +golang.org/x/tools v0.9.1/go.mod h1:owI94Op576fPu3cIGQeHs3joujW/2Oc6MtlxbF5dfNc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= -google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= +google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= 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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 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= From 68bf6f16ac7d6acb98975b939f13cf33f32d960a Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 6 Aug 2023 23:34:10 +0800 Subject: [PATCH 74/79] refactor: Geodata initialization --- config/config.go | 13 +++++++++---- config/initial.go | 18 ------------------ 2 files changed, 9 insertions(+), 22 deletions(-) diff --git a/config/config.go b/config/config.go index ba61070c..401786c8 100644 --- a/config/config.go +++ b/config/config.go @@ -51,6 +51,7 @@ type General struct { IPv6 bool `json:"ipv6"` Interface string `json:"interface-name"` RoutingMark int `json:"-"` + GeoXUrl GeoXUrl `json:"geox-url"` GeodataMode bool `json:"geodata-mode"` GeodataLoader string `json:"geodata-loader"` TCPConcurrent bool `json:"tcp-concurrent"` @@ -273,7 +274,7 @@ type RawConfig struct { IPTables IPTables `yaml:"iptables"` Experimental Experimental `yaml:"experimental"` Profile Profile `yaml:"profile"` - GeoXUrl RawGeoXUrl `yaml:"geox-url"` + GeoXUrl GeoXUrl `yaml:"geox-url"` Proxy []map[string]any `yaml:"proxies"` ProxyGroup []map[string]any `yaml:"proxy-groups"` Rule []string `yaml:"rules"` @@ -282,7 +283,7 @@ type RawConfig struct { Listeners []map[string]any `yaml:"listeners"` } -type RawGeoXUrl struct { +type GeoXUrl struct { GeoIp string `yaml:"geoip" json:"geoip"` Mmdb string `yaml:"mmdb" json:"mmdb"` GeoSite string `yaml:"geosite" json:"geosite"` @@ -418,7 +419,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { Profile: Profile{ StoreSelected: true, }, - GeoXUrl: RawGeoXUrl{ + GeoXUrl: GeoXUrl{ Mmdb: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb", GeoIp: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.dat", GeoSite: "https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat", @@ -448,7 +449,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { config.General = general if len(config.General.GlobalClientFingerprint) != 0 { - log.Debugln("GlobalClientFingerprint:%s", config.General.GlobalClientFingerprint) + log.Debugln("GlobalClientFingerprint: %s", config.General.GlobalClientFingerprint) tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint) } @@ -532,6 +533,9 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { func parseGeneral(cfg *RawConfig) (*General, error) { externalUI := cfg.ExternalUI geodata.SetLoader(cfg.GeodataLoader) + C.GeoIpUrl = cfg.GeoXUrl.GeoIp + C.GeoSiteUrl = cfg.GeoXUrl.GeoSite + C.MmdbUrl = cfg.GeoXUrl.Mmdb // checkout externalUI exist if externalUI != "" { externalUI = C.Path.Resolve(externalUI) @@ -565,6 +569,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { IPv6: cfg.IPv6, Interface: cfg.Interface, RoutingMark: cfg.RoutingMark, + GeoXUrl: cfg.GeoXUrl, GeodataMode: cfg.GeodataMode, GeodataLoader: cfg.GeodataLoader, TCPConcurrent: cfg.TCPConcurrent, diff --git a/config/initial.go b/config/initial.go index 0921040d..6d6429ab 100644 --- a/config/initial.go +++ b/config/initial.go @@ -2,7 +2,6 @@ package config import ( "fmt" - "github.com/Dreamacro/clash/component/geodata" "os" C "github.com/Dreamacro/clash/constant" @@ -28,23 +27,6 @@ func Init(dir string) error { f.Write([]byte(`mixed-port: 7890`)) f.Close() } - buf, _ := os.ReadFile(C.Path.Config()) - rawCfg, err := UnmarshalRawConfig(buf) - if err != nil { - log.Errorln(err.Error()) - fmt.Printf("configuration file %s test failed\n", C.Path.Config()) - os.Exit(1) - } - if !C.GeodataMode { - C.GeodataMode = rawCfg.GeodataMode - } - C.GeoIpUrl = rawCfg.GeoXUrl.GeoIp - C.GeoSiteUrl = rawCfg.GeoXUrl.GeoSite - C.MmdbUrl = rawCfg.GeoXUrl.Mmdb - // initial GeoIP - if err := geodata.InitGeoIP(); err != nil { - return fmt.Errorf("can't initial GeoIP: %w", err) - } return nil } From bad9f2e6dcc93fa7f6466f9697331edb15f97508 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Mon, 7 Aug 2023 01:43:23 +0800 Subject: [PATCH 75/79] fix geodata-mode --- config/config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config/config.go b/config/config.go index 401786c8..ba6271ed 100644 --- a/config/config.go +++ b/config/config.go @@ -536,6 +536,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { C.GeoIpUrl = cfg.GeoXUrl.GeoIp C.GeoSiteUrl = cfg.GeoXUrl.GeoSite C.MmdbUrl = cfg.GeoXUrl.Mmdb + C.GeodataMode = cfg.GeodataMode // checkout externalUI exist if externalUI != "" { externalUI = C.Path.Resolve(externalUI) From e2e0fd4ebaafc168e5e1708b042b624d8acba1f1 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 9 Aug 2023 13:51:02 +0800 Subject: [PATCH 76/79] chore: using uint16 for ports in Metadata --- adapter/adapter.go | 7 ++++++- adapter/inbound/socket.go | 5 ++++- adapter/inbound/util.go | 26 ++++++++++++++++++-------- adapter/outbound/snell.go | 6 ++---- adapter/outbound/util.go | 3 +-- adapter/outbound/vless.go | 5 ++--- adapter/outbound/wireguard.go | 6 ++---- component/sniffer/dispatcher.go | 31 ++++++++++++------------------- constant/metadata.go | 22 +++++++++++++--------- dns/util.go | 15 ++++++++++++--- rules/common/port.go | 9 +-------- rules/logic_test/logic_test.go | 4 ++-- test/clash_test.go | 12 ++++++------ transport/tuic/v4/protocol.go | 4 +--- transport/tuic/v5/protocol.go | 4 +--- tunnel/tunnel.go | 4 +--- 16 files changed, 84 insertions(+), 79 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 20de5f29..6cc79c3a 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -9,6 +9,7 @@ import ( "net/http" "net/netip" "net/url" + "strconv" "time" "github.com/Dreamacro/clash/common/atomic" @@ -327,11 +328,15 @@ func urlToMetadata(rawURL string) (addr C.Metadata, err error) { return } } + uintPort, err := strconv.ParseUint(port, 10, 16) + if err != nil { + return + } addr = C.Metadata{ Host: u.Hostname(), DstIP: netip.Addr{}, - DstPort: port, + DstPort: uint16(uintPort), } return } diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index e41ee925..d75901f1 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -3,6 +3,7 @@ package inbound import ( "net" "net/netip" + "strconv" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/context" @@ -37,7 +38,9 @@ func NewInner(conn net.Conn, address string) *context.ConnContext { metadata.DNSMode = C.DNSNormal metadata.Process = C.ClashName if h, port, err := net.SplitHostPort(address); err == nil { - metadata.DstPort = port + if port, err := strconv.ParseUint(port, 10, 16); err == nil { + metadata.DstPort = uint16(port) + } if ip, err := netip.ParseAddr(h); err == nil { metadata.DstIP = ip } else { diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index 88e989f9..626687c0 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -20,14 +20,14 @@ func parseSocksAddr(target socks5.Addr) *C.Metadata { case socks5.AtypDomainName: // trim for FQDN metadata.Host = strings.TrimRight(string(target[2:2+target[1]]), ".") - metadata.DstPort = strconv.Itoa((int(target[2+target[1]]) << 8) | int(target[2+target[1]+1])) + metadata.DstPort = uint16((int(target[2+target[1]]) << 8) | int(target[2+target[1]+1])) case socks5.AtypIPv4: metadata.DstIP = nnip.IpToAddr(net.IP(target[1 : 1+net.IPv4len])) - metadata.DstPort = strconv.Itoa((int(target[1+net.IPv4len]) << 8) | int(target[1+net.IPv4len+1])) + metadata.DstPort = uint16((int(target[1+net.IPv4len]) << 8) | int(target[1+net.IPv4len+1])) case socks5.AtypIPv6: ip6, _ := netip.AddrFromSlice(target[1 : 1+net.IPv6len]) metadata.DstIP = ip6.Unmap() - metadata.DstPort = strconv.Itoa((int(target[1+net.IPv6len]) << 8) | int(target[1+net.IPv6len+1])) + metadata.DstPort = uint16((int(target[1+net.IPv6len]) << 8) | int(target[1+net.IPv6len+1])) } return metadata @@ -43,11 +43,16 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { // trim FQDN (#737) host = strings.TrimRight(host, ".") + var uint16Port uint16 + if port, err := strconv.ParseUint(port, 10, 16); err == nil { + uint16Port = uint16(port) + } + metadata := &C.Metadata{ NetWork: C.TCP, Host: host, DstIP: netip.Addr{}, - DstPort: port, + DstPort: uint16Port, } ip, err := netip.ParseAddr(host) @@ -58,10 +63,10 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } -func parseAddr(addr net.Addr) (netip.Addr, string, error) { +func parseAddr(addr net.Addr) (netip.Addr, uint16, error) { // Filter when net.Addr interface is nil if addr == nil { - return netip.Addr{}, "", errors.New("nil addr") + return netip.Addr{}, 0, errors.New("nil addr") } if rawAddr, ok := addr.(interface{ RawAddr() net.Addr }); ok { ip, port, err := parseAddr(rawAddr.RawAddr()) @@ -72,9 +77,14 @@ func parseAddr(addr net.Addr) (netip.Addr, string, error) { addrStr := addr.String() host, port, err := net.SplitHostPort(addrStr) if err != nil { - return netip.Addr{}, "", err + return netip.Addr{}, 0, err + } + + var uint16Port uint16 + if port, err := strconv.ParseUint(port, 10, 16); err == nil { + uint16Port = uint16(port) } ip, err := netip.ParseAddr(host) - return ip, port, err + return ip, uint16Port, err } diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index fc1f4eb3..e542d84d 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -59,8 +59,7 @@ func (s *Snell) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M err := snell.WriteUDPHeader(c, s.version) return c, err } - port, _ := strconv.ParseUint(metadata.DstPort, 10, 16) - err := snell.WriteHeader(c, metadata.String(), uint(port), s.version) + err := snell.WriteHeader(c, metadata.String(), uint(metadata.DstPort), s.version) return c, err } @@ -72,8 +71,7 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d return nil, err } - port, _ := strconv.ParseUint(metadata.DstPort, 10, 16) - if err = snell.WriteHeader(c, metadata.String(), uint(port), s.version); err != nil { + if err = snell.WriteHeader(c, metadata.String(), uint(metadata.DstPort), s.version); err != nil { c.Close() return nil, err } diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index 0504d005..7f3ec4c3 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -6,7 +6,6 @@ import ( "crypto/tls" "net" "net/netip" - "strconv" "sync" "time" @@ -38,7 +37,7 @@ func serializesSocksAddr(metadata *C.Metadata) []byte { var buf [][]byte addrType := metadata.AddrType() aType := uint8(addrType) - p, _ := strconv.ParseUint(metadata.DstPort, 10, 16) + p := uint(metadata.DstPort) port := []byte{uint8(p >> 8), uint8(p & 0xff)} switch addrType { case socks5.AtypDomainName: diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 6423eb29..44d05ba6 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -179,7 +179,7 @@ func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err metadata = &C.Metadata{ NetWork: C.UDP, Host: packetaddr.SeqPacketMagicAddress, - DstPort: "443", + DstPort: 443, } } else { metadata = &C.Metadata{ // a clear metadata only contains ip @@ -399,12 +399,11 @@ func parseVlessAddr(metadata *C.Metadata, xudp bool) *vless.DstAddr { copy(addr[1:], metadata.Host) } - port, _ := strconv.ParseUint(metadata.DstPort, 10, 16) return &vless.DstAddr{ UDP: metadata.NetWork == C.UDP, AddrType: addrType, Addr: addr, - Port: uint16(port), + Port: metadata.DstPort, Mux: metadata.NetWork == C.UDP && xudp, } } diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index c12321f3..e6738596 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -374,8 +374,7 @@ func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts options = append(options, dialer.WithNetDialer(wgNetDialer{tunDevice: w.tunDevice})) conn, err = dialer.NewDialer(options...).DialContext(ctx, "tcp", metadata.RemoteAddress()) } else { - port, _ := strconv.Atoi(metadata.DstPort) - conn, err = w.tunDevice.DialContext(ctx, "tcp", M.SocksaddrFrom(metadata.DstIP, uint16(port)).Unwrap()) + conn, err = w.tunDevice.DialContext(ctx, "tcp", M.SocksaddrFrom(metadata.DstIP, metadata.DstPort).Unwrap()) } if err != nil { return nil, err @@ -412,8 +411,7 @@ func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadat } metadata.DstIP = ip } - port, _ := strconv.Atoi(metadata.DstPort) - pc, err = w.tunDevice.ListenPacket(ctx, M.SocksaddrFrom(metadata.DstIP, uint16(port)).Unwrap()) + pc, err = w.tunDevice.ListenPacket(ctx, M.SocksaddrFrom(metadata.DstIP, metadata.DstPort).Unwrap()) if err != nil { return nil, err } diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index fa1c6827..f813eec2 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -5,7 +5,6 @@ import ( "fmt" "net" "net/netip" - "strconv" "sync" "time" @@ -26,29 +25,23 @@ var ( var Dispatcher *SnifferDispatcher type SnifferDispatcher struct { - enable bool - sniffers map[sniffer.Sniffer]SnifferConfig - forceDomain *trie.DomainSet - skipSNI *trie.DomainSet - skipList *cache.LruCache[string, uint8] - rwMux sync.RWMutex - forceDnsMapping bool - parsePureIp bool + enable bool + sniffers map[sniffer.Sniffer]SnifferConfig + forceDomain *trie.DomainSet + skipSNI *trie.DomainSet + skipList *cache.LruCache[string, uint8] + rwMux sync.RWMutex + forceDnsMapping bool + parsePureIp bool } func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) { if (metadata.Host == "" && sd.parsePureIp) || sd.forceDomain.Has(metadata.Host) || (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) { - port, err := strconv.ParseUint(metadata.DstPort, 10, 16) - if err != nil { - log.Debugln("[Sniffer] Dst port is error") - return - } - inWhitelist := false overrideDest := false for sniffer, config := range sd.sniffers { if sniffer.SupportNetwork() == C.TCP || sniffer.SupportNetwork() == C.ALLNet { - inWhitelist = sniffer.SupportPort(uint16(port)) + inWhitelist = sniffer.SupportPort(metadata.DstPort) if inWhitelist { overrideDest = config.OverrideDest break @@ -61,7 +54,7 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata } sd.rwMux.RLock() - dst := fmt.Sprintf("%s:%s", metadata.DstIP, metadata.DstPort) + dst := fmt.Sprintf("%s:%d", metadata.DstIP, metadata.DstPort) if count, ok := sd.skipList.Get(dst); ok && count > 5 { log.Debugln("[Sniffer] Skip sniffing[%s] due to multiple failures", dst) defer sd.rwMux.RUnlock() @@ -71,7 +64,7 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata if host, err := sd.sniffDomain(conn, metadata); err != nil { sd.cacheSniffFailed(metadata) - log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%s] to [%s:%s]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort) + log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%d] to [%s:%d]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort) return } else { if sd.skipSNI.Has(host) { @@ -149,7 +142,7 @@ func (sd *SnifferDispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metad func (sd *SnifferDispatcher) cacheSniffFailed(metadata *C.Metadata) { sd.rwMux.Lock() - dst := fmt.Sprintf("%s:%s", metadata.DstIP, metadata.DstPort) + dst := fmt.Sprintf("%s:%d", metadata.DstIP, metadata.DstPort) count, _ := sd.skipList.Get(dst) if count <= 5 { count++ diff --git a/constant/metadata.go b/constant/metadata.go index de26a05f..dbd31fd8 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -128,10 +128,10 @@ type Metadata struct { Type Type `json:"type"` SrcIP netip.Addr `json:"sourceIP"` DstIP netip.Addr `json:"destinationIP"` - SrcPort string `json:"sourcePort"` - DstPort string `json:"destinationPort"` + SrcPort uint16 `json:"sourcePort,string"` // `,string` is used to compatible with old version json output + DstPort uint16 `json:"destinationPort,string"` // `,string` is used to compatible with old version json output InIP netip.Addr `json:"inboundIP"` - InPort string `json:"inboundPort"` + InPort uint16 `json:"inboundPort,string"` // `,string` is used to compatible with old version json output InName string `json:"inboundName"` InUser string `json:"inboundUser"` Host string `json:"host"` @@ -147,11 +147,11 @@ type Metadata struct { } func (m *Metadata) RemoteAddress() string { - return net.JoinHostPort(m.String(), m.DstPort) + return net.JoinHostPort(m.String(), strconv.FormatUint(uint64(m.DstPort), 10)) } func (m *Metadata) SourceAddress() string { - return net.JoinHostPort(m.SrcIP.String(), m.SrcPort) + return net.JoinHostPort(m.SrcIP.String(), strconv.FormatUint(uint64(m.SrcPort), 10)) } func (m *Metadata) SourceDetail() string { @@ -172,7 +172,7 @@ func (m *Metadata) SourceDetail() string { } func (m *Metadata) SourceValid() bool { - return m.SrcPort != "" && m.SrcIP.IsValid() + return m.SrcPort != 0 && m.SrcIP.IsValid() } func (m *Metadata) AddrType() int { @@ -211,8 +211,7 @@ func (m *Metadata) Pure() *Metadata { } func (m *Metadata) AddrPort() netip.AddrPort { - port, _ := strconv.ParseUint(m.DstPort, 10, 16) - return netip.AddrPortFrom(m.DstIP.Unmap(), uint16(port)) + return netip.AddrPortFrom(m.DstIP.Unmap(), m.DstPort) } func (m *Metadata) UDPAddr() *net.UDPAddr { @@ -242,6 +241,11 @@ func (m *Metadata) SetRemoteAddress(rawAddress string) error { return err } + var uint16Port uint16 + if port, err := strconv.ParseUint(port, 10, 16); err == nil { + uint16Port = uint16(port) + } + if ip, err := netip.ParseAddr(host); err != nil { m.Host = host m.DstIP = netip.Addr{} @@ -249,7 +253,7 @@ func (m *Metadata) SetRemoteAddress(rawAddress string) error { m.Host = "" m.DstIP = ip.Unmap() } - m.DstPort = port + m.DstPort = uint16Port return nil } diff --git a/dns/util.go b/dns/util.go index 739fd16b..77f677cb 100644 --- a/dns/util.go +++ b/dns/util.go @@ -7,6 +7,7 @@ import ( "fmt" "net" "net/netip" + "strconv" "strings" "time" @@ -193,6 +194,10 @@ func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, if err != nil { return nil, err } + uintPort, err := strconv.ParseUint(port, 10, 16) + if err != nil { + return nil, err + } if proxyAdapter == nil { var ok bool proxyAdapter, ok = tunnel.Proxies()[proxyName] @@ -206,7 +211,7 @@ func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, metadata := &C.Metadata{ NetWork: C.TCP, Host: host, - DstPort: port, + DstPort: uint16(uintPort), } if proxyAdapter != nil { if proxyAdapter.IsL3Protocol(metadata) { // L3 proxy should resolve domain before to avoid loopback @@ -231,7 +236,7 @@ func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, NetWork: C.UDP, Host: "", DstIP: dstIP, - DstPort: port, + DstPort: uint16(uintPort), } if proxyAdapter == nil { return dialer.DialContext(ctx, network, addr, opts...) @@ -257,6 +262,10 @@ func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName st if err != nil { return nil, err } + uintPort, err := strconv.ParseUint(port, 10, 16) + if err != nil { + return nil, err + } if proxyAdapter == nil { var ok bool proxyAdapter, ok = tunnel.Proxies()[proxyName] @@ -274,7 +283,7 @@ func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName st NetWork: C.UDP, Host: "", DstIP: dstIP, - DstPort: port, + DstPort: uint16(uintPort), } if proxyAdapter == nil { return dialer.ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", opts...) diff --git a/rules/common/port.go b/rules/common/port.go index aeacc4dc..334d083f 100644 --- a/rules/common/port.go +++ b/rules/common/port.go @@ -2,7 +2,6 @@ package common import ( "fmt" - "strconv" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" @@ -28,7 +27,7 @@ func (p *Port) Match(metadata *C.Metadata) (bool, string) { case C.SrcPort: targetPort = metadata.SrcPort } - return p.matchPortReal(targetPort), p.adapter + return p.portRanges.Check(targetPort), p.adapter } func (p *Port) Adapter() string { @@ -39,12 +38,6 @@ func (p *Port) Payload() string { return p.port } -func (p *Port) matchPortReal(portRef string) bool { - port, _ := strconv.Atoi(portRef) - - return p.portRanges.Check(uint16(port)) -} - func NewPort(port string, adapter string, ruleType C.RuleType) (*Port, error) { portRanges, err := utils.NewIntRanges[uint16](port) if err != nil { diff --git a/rules/logic_test/logic_test.go b/rules/logic_test/logic_test.go index de5ae569..52318b3f 100644 --- a/rules/logic_test/logic_test.go +++ b/rules/logic_test/logic_test.go @@ -20,7 +20,7 @@ func TestAND(t *testing.T) { m, _ := and.Match(&C.Metadata{ Host: "baidu.com", NetWork: C.TCP, - DstPort: "20000", + DstPort: 20000, }) assert.Equal(t, true, m) @@ -35,7 +35,7 @@ func TestNOT(t *testing.T) { not, err := NewNOT("((DST-PORT,6000-6500))", "REJECT", ParseRule) assert.Equal(t, nil, err) m, _ := not.Match(&C.Metadata{ - DstPort: "6100", + DstPort: 6100, }) assert.Equal(t, false, m) diff --git a/test/clash_test.go b/test/clash_test.go index 3fdca5d0..60b99791 100644 --- a/test/clash_test.go +++ b/test/clash_test.go @@ -556,7 +556,7 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) { assert.NoError(t, testPingPongWithConn(t, func() net.Conn { conn, err := proxy.DialContext(context.Background(), &C.Metadata{ Host: localIP.String(), - DstPort: "10001", + DstPort: 10001, }) require.NoError(t, err) return conn @@ -565,7 +565,7 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) { assert.NoError(t, testLargeDataWithConn(t, func() net.Conn { conn, err := proxy.DialContext(context.Background(), &C.Metadata{ Host: localIP.String(), - DstPort: "10001", + DstPort: 10001, }) require.NoError(t, err) return conn @@ -578,7 +578,7 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) { pc, err := proxy.ListenPacketContext(context.Background(), &C.Metadata{ NetWork: C.UDP, DstIP: localIP, - DstPort: "10001", + DstPort: 10001, }) require.NoError(t, err) defer pc.Close() @@ -588,7 +588,7 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) { pc, err = proxy.ListenPacketContext(context.Background(), &C.Metadata{ NetWork: C.UDP, DstIP: localIP, - DstPort: "10001", + DstPort: 10001, }) require.NoError(t, err) defer pc.Close() @@ -598,7 +598,7 @@ func testSuit(t *testing.T, proxy C.ProxyAdapter) { pc, err = proxy.ListenPacketContext(context.Background(), &C.Metadata{ NetWork: C.UDP, DstIP: localIP, - DstPort: "10001", + DstPort: 10001, }) require.NoError(t, err) defer pc.Close() @@ -635,7 +635,7 @@ func benchmarkProxy(b *testing.B, proxy C.ProxyAdapter) { conn, err := proxy.DialContext(context.Background(), &C.Metadata{ Host: localIP.String(), - DstPort: "10001", + DstPort: 10001, }) require.NoError(b, err) diff --git a/transport/tuic/v4/protocol.go b/transport/tuic/v4/protocol.go index 11ac3b4e..bbdca67c 100644 --- a/transport/tuic/v4/protocol.go +++ b/transport/tuic/v4/protocol.go @@ -457,12 +457,10 @@ func NewAddress(metadata *C.Metadata) Address { copy(addr[1:], metadata.Host) } - port, _ := strconv.ParseUint(metadata.DstPort, 10, 16) - return Address{ TYPE: addrType, ADDR: addr, - PORT: uint16(port), + PORT: metadata.DstPort, } } diff --git a/transport/tuic/v5/protocol.go b/transport/tuic/v5/protocol.go index 83b44146..964401e1 100644 --- a/transport/tuic/v5/protocol.go +++ b/transport/tuic/v5/protocol.go @@ -436,12 +436,10 @@ func NewAddress(metadata *C.Metadata) Address { copy(addr[1:], metadata.Host) } - port, _ := strconv.ParseUint(metadata.DstPort, 10, 16) - return Address{ TYPE: addrType, ADDR: addr, - PORT: uint16(port), + PORT: metadata.DstPort, } } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index e375f656..d4c15a87 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -7,7 +7,6 @@ import ( "net/netip" "path/filepath" "runtime" - "strconv" "sync" "time" @@ -566,8 +565,7 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { if attemptProcessLookup && !findProcessMode.Off() && (findProcessMode.Always() || rule.ShouldFindProcess()) { attemptProcessLookup = false - srcPort, _ := strconv.ParseUint(metadata.SrcPort, 10, 16) - uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(srcPort)) + uid, path, err := P.FindProcessName(metadata.NetWork.String(), metadata.SrcIP, int(metadata.SrcPort)) if err != nil { log.Debugln("[Process] find process %s: %v", metadata.String(), err) } else { From cc42d787d4cc2aca0076869eb941ce29ce5fd024 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 9 Aug 2023 16:57:39 +0800 Subject: [PATCH 77/79] feat: add `mptcp` for all proxy --- adapter/outbound/base.go | 8 ++++++++ adapter/outbound/http.go | 1 + adapter/outbound/shadowsocks.go | 1 + adapter/outbound/shadowsocksr.go | 1 + adapter/outbound/snell.go | 1 + adapter/outbound/socks5.go | 1 + adapter/outbound/trojan.go | 1 + adapter/outbound/vless.go | 1 + adapter/outbound/vmess.go | 1 + component/dialer/dialer.go | 3 +++ component/dialer/mptcp_go120.go | 12 ++++++++++++ component/dialer/mptcp_go121.go | 11 +++++++++++ component/dialer/options.go | 7 +++++++ 13 files changed, 49 insertions(+) create mode 100644 component/dialer/mptcp_go120.go create mode 100644 component/dialer/mptcp_go121.go diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index f2ce56c9..ba991bfc 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -21,6 +21,7 @@ type Base struct { udp bool xudp bool tfo bool + mpTcp bool rmark int id string prefer C.DNSPrefer @@ -143,11 +144,16 @@ func (b *Base) DialOptions(opts ...dialer.Option) []dialer.Option { opts = append(opts, dialer.WithTFO(true)) } + if b.mpTcp { + opts = append(opts, dialer.WithMPTCP(true)) + } + return opts } type BasicOption struct { TFO bool `proxy:"tfo,omitempty" group:"tfo,omitempty"` + MPTCP bool `proxy:"mptcp,omitempty" group:"mptcp,omitempty"` Interface string `proxy:"interface-name,omitempty" group:"interface-name,omitempty"` RoutingMark int `proxy:"routing-mark,omitempty" group:"routing-mark,omitempty"` IPVersion string `proxy:"ip-version,omitempty" group:"ip-version,omitempty"` @@ -161,6 +167,7 @@ type BaseOption struct { UDP bool XUDP bool TFO bool + MPTCP bool Interface string RoutingMark int Prefer C.DNSPrefer @@ -174,6 +181,7 @@ func NewBase(opt BaseOption) *Base { udp: opt.UDP, xudp: opt.XUDP, tfo: opt.TFO, + mpTcp: opt.MPTCP, iface: opt.Interface, rmark: opt.RoutingMark, prefer: opt.Prefer, diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 78735b2d..0b652ca9 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -177,6 +177,7 @@ func NewHttp(option HttpOption) (*Http, error) { addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.Http, tfo: option.TFO, + mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 32558eac..c1481622 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -315,6 +315,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { tp: C.Shadowsocks, udp: option.UDP, tfo: option.TFO, + mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 07778032..cd6854af 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -181,6 +181,7 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { tp: C.ShadowsocksR, udp: option.UDP, tfo: option.TFO, + mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index e542d84d..d0b9e748 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -181,6 +181,7 @@ func NewSnell(option SnellOption) (*Snell, error) { tp: C.Snell, udp: option.UDP, tfo: option.TFO, + mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 9af4d0fc..f451cd1a 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -196,6 +196,7 @@ func NewSocks5(option Socks5Option) (*Socks5, error) { tp: C.Socks5, udp: option.UDP, tfo: option.TFO, + mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 3af71b7d..ec420bf3 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -238,6 +238,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { tp: C.Trojan, udp: option.UDP, tfo: option.TFO, + mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 44d05ba6..83ce4e57 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -543,6 +543,7 @@ func NewVless(option VlessOption) (*Vless, error) { udp: option.UDP, xudp: option.XUDP, tfo: option.TFO, + mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index acf6de75..8a94c082 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -436,6 +436,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { udp: option.UDP, xudp: option.XUDP, tfo: option.TFO, + mpTcp: option.MPTCP, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 5e19046c..89c7564a 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -132,6 +132,9 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po if opt.routingMark != 0 { bindMarkToDialer(opt.routingMark, dialer, network, destination) } + if opt.mpTcp { + setMultiPathTCP(dialer) + } if opt.tfo { return dialTFO(ctx, *dialer, network, address) } diff --git a/component/dialer/mptcp_go120.go b/component/dialer/mptcp_go120.go new file mode 100644 index 00000000..6e564673 --- /dev/null +++ b/component/dialer/mptcp_go120.go @@ -0,0 +1,12 @@ +//go:build !go1.21 + +package dialer + +import ( + "net" +) + +const multipathTCPAvailable = false + +func setMultiPathTCP(dialer *net.Dialer) { +} diff --git a/component/dialer/mptcp_go121.go b/component/dialer/mptcp_go121.go new file mode 100644 index 00000000..360826c8 --- /dev/null +++ b/component/dialer/mptcp_go121.go @@ -0,0 +1,11 @@ +//go:build go1.21 + +package dialer + +import "net" + +const multipathTCPAvailable = true + +func setMultiPathTCP(dialer *net.Dialer) { + dialer.SetMultipathTCP(true) +} diff --git a/component/dialer/options.go b/component/dialer/options.go index 096c7a5c..30771e71 100644 --- a/component/dialer/options.go +++ b/component/dialer/options.go @@ -25,6 +25,7 @@ type option struct { network int prefer int tfo bool + mpTcp bool resolver resolver.Resolver netDialer NetDialer } @@ -83,6 +84,12 @@ func WithTFO(tfo bool) Option { } } +func WithMPTCP(mpTcp bool) Option { + return func(opt *option) { + opt.mpTcp = mpTcp + } +} + func WithNetDialer(netDialer NetDialer) Option { return func(opt *option) { opt.netDialer = netDialer From 984fca47264a7d2d4d18fba89b3cdcda91e515bb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 9 Aug 2023 17:09:03 +0800 Subject: [PATCH 78/79] feat: add `inbound-mptcp` for listeners --- adapter/inbound/listen.go | 4 ++++ adapter/inbound/mptcp_go120.go | 10 ++++++++++ adapter/inbound/mptcp_go121.go | 11 +++++++++++ config/config.go | 3 +++ hub/executor/executor.go | 1 + 5 files changed, 29 insertions(+) create mode 100644 adapter/inbound/mptcp_go120.go create mode 100644 adapter/inbound/mptcp_go121.go diff --git a/adapter/inbound/listen.go b/adapter/inbound/listen.go index fa82db92..8b7b5fb2 100644 --- a/adapter/inbound/listen.go +++ b/adapter/inbound/listen.go @@ -17,6 +17,10 @@ func SetTfo(open bool) { lc.DisableTFO = !open } +func SetMPTCP(open bool) { + setMultiPathTCP(&lc.ListenConfig, open) +} + func ListenContext(ctx context.Context, network, address string) (net.Listener, error) { return lc.Listen(ctx, network, address) } diff --git a/adapter/inbound/mptcp_go120.go b/adapter/inbound/mptcp_go120.go new file mode 100644 index 00000000..f9b22533 --- /dev/null +++ b/adapter/inbound/mptcp_go120.go @@ -0,0 +1,10 @@ +//go:build !go1.21 + +package inbound + +import "net" + +const multipathTCPAvailable = false + +func setMultiPathTCP(listenConfig *net.ListenConfig, open bool) { +} diff --git a/adapter/inbound/mptcp_go121.go b/adapter/inbound/mptcp_go121.go new file mode 100644 index 00000000..6b35d1a8 --- /dev/null +++ b/adapter/inbound/mptcp_go121.go @@ -0,0 +1,11 @@ +//go:build go1.21 + +package inbound + +import "net" + +const multipathTCPAvailable = true + +func setMultiPathTCP(listenConfig *net.ListenConfig, open bool) { + listenConfig.SetMultipathTCP(open) +} diff --git a/config/config.go b/config/config.go index ba6271ed..cb30999b 100644 --- a/config/config.go +++ b/config/config.go @@ -76,6 +76,7 @@ type Inbound struct { AllowLan bool `json:"allow-lan"` BindAddress string `json:"bind-address"` InboundTfo bool `json:"inbound-tfo"` + InboundMPTCP bool `json:"inbound-mptcp"` } // Controller config @@ -243,6 +244,7 @@ type RawConfig struct { ShadowSocksConfig string `yaml:"ss-config"` VmessConfig string `yaml:"vmess-config"` InboundTfo bool `yaml:"inbound-tfo"` + InboundMPTCP bool `yaml:"inbound-mptcp"` Authentication []string `yaml:"authentication"` AllowLan bool `yaml:"allow-lan"` BindAddress string `yaml:"bind-address"` @@ -557,6 +559,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { AllowLan: cfg.AllowLan, BindAddress: cfg.BindAddress, InboundTfo: cfg.InboundTfo, + InboundMPTCP: cfg.InboundMPTCP, }, Controller: Controller{ ExternalController: cfg.ExternalController, diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 724150e7..f4cda47a 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -360,6 +360,7 @@ func updateGeneral(general *config.General) { } inbound.SetTfo(general.InboundTfo) + inbound.SetMPTCP(general.InboundMPTCP) adapter.UnifiedDelay.Store(general.UnifiedDelay) From 3093fc4f33fc58251406b35c83d451be65dcb795 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 9 Aug 2023 17:26:24 +0800 Subject: [PATCH 79/79] chore: update go1.21.0 release --- .github/workflows/build.yml | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 806bf9ee..d7cdd6c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -128,7 +128,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.21.0-rc.4" + go-version: "1.21" check-latest: true - name: Test diff --git a/go.mod b/go.mod index 95676975..3167d9ea 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 - github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12 + github.com/metacubex/quic-go v0.37.4-0.20230809092428-5acf8eb2de86 github.com/metacubex/sing-shadowsocks v0.2.4 github.com/metacubex/sing-shadowsocks2 v0.1.3 github.com/metacubex/sing-tun v0.1.11 diff --git a/go.sum b/go.sum index 344e8991..a90f4dba 100644 --- a/go.sum +++ b/go.sum @@ -92,8 +92,8 @@ github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 h1:cjd4biTvO github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759/go.mod h1:UHOv2xu+RIgLwpXca7TLrXleEd4oR3sPatW6IF8wU88= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= -github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12 h1:18tcXxLgwjUjs38QM1E1a+AAh4j+Mo/mKcJTmqHrN9c= -github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12/go.mod h1:HhHoyskMk4kzfLPKcm7EF7pGXF89KRVwjbGrEaN6lIU= +github.com/metacubex/quic-go v0.37.4-0.20230809092428-5acf8eb2de86 h1:qGExcB3lYk51LPEJh5HTdQplbZmuTn+tkcuhuas1LC8= +github.com/metacubex/quic-go v0.37.4-0.20230809092428-5acf8eb2de86/go.mod h1:HhHoyskMk4kzfLPKcm7EF7pGXF89KRVwjbGrEaN6lIU= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7 h1:XY3Y6nPL45XuN/k3rDXJ1TJknLo8rTo1SVuDOmOEf4E= github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/metacubex/sing-shadowsocks v0.2.4 h1:Gc99Z17JVif1PKKq1pjqhSmc2kvHUgk+AqxOstCzhQ0=