From 1a1e3345f4d77f1d0006ace29553e3975074f3f1 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 19 Feb 2023 10:10:27 +0800 Subject: [PATCH 001/530] chore: reset tunName in macos when it isn't startWith "utun" --- listener/sing_tun/server.go | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 5c387a8d..8e0a6c34 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -67,6 +67,26 @@ func CalculateInterfaceName(name string) (tunName string) { return } +func checkTunName(tunName string) (ok bool) { + defer func() { + if !ok { + log.Warnln("[TUN] Unsupported tunName(%s) in %s, force regenerate by ourselves.", tunName, runtime.GOOS) + } + }() + if runtime.GOOS == "darwin" { + if len(tunName) <= 4 { + return false + } + if tunName[:4] == "utun" { + return false + } + if _, parseErr := strconv.ParseInt(tunName[4:], 10, 16); parseErr != nil { + return false + } + } + return true +} + func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (l *Listener, err error) { if len(additions) == 0 { additions = []inbound.Addition{ @@ -75,7 +95,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte } } tunName := options.Device - if tunName == "" { + if tunName == "" || !checkTunName(tunName) { tunName = CalculateInterfaceName(InterfaceName) options.Device = tunName } From db3e1b9ed56756225d65265b8f0a253a82fe0a2c Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 19 Feb 2023 16:20:30 +0800 Subject: [PATCH 002/530] feat: add sni field for tuic --- adapter/outbound/tuic.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 0ca13670..5b7bde6e 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -51,6 +51,7 @@ type TuicOption struct { ReceiveWindowConn int `proxy:"recv-window-conn,omitempty"` ReceiveWindow int `proxy:"recv-window,omitempty"` DisableMTUDiscovery bool `proxy:"disable-mtu-discovery,omitempty"` + SNI string `proxy:"sni,omitempty"` } // DialContext implements C.ProxyAdapter @@ -106,12 +107,14 @@ func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (pc net.Pack func NewTuic(option TuicOption) (*Tuic, error) { addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) serverName := option.Server - tlsConfig := &tls.Config{ ServerName: serverName, InsecureSkipVerify: option.SkipCertVerify, MinVersion: tls.VersionTLS13, } + if option.SNI != "" { + tlsConfig.ServerName = option.SNI + } var bs []byte var err error From baaf509637e7cef01eec8c56ad73dfb8852d1ba2 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 21 Feb 2023 21:58:37 +0800 Subject: [PATCH 003/530] chore: using sing-shadowtls to support shadowtls v1/2/3 --- adapter/outbound/shadowsocks.go | 70 +++++++++++++-------- adapter/outbound/wireguard.go | 8 +-- component/tls/utls.go | 2 +- go.mod | 17 ++--- go.sum | 34 +++++----- listener/sing/log.go | 41 ------------ listener/sing_tun/server.go | 2 +- log/sing.go | 68 ++++++++++++++++++++ transport/sing-shadowtls/shadowtls.go | 91 +++++++++++++++++++++++++++ 9 files changed, 236 insertions(+), 97 deletions(-) delete mode 100644 listener/sing/log.go create mode 100644 log/sing.go create mode 100644 transport/sing-shadowtls/shadowtls.go diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 54566666..f6701469 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -10,10 +10,9 @@ import ( "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/dialer" - tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/shadowtls" obfs "github.com/Dreamacro/clash/transport/simple-obfs" + shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls" "github.com/Dreamacro/clash/transport/socks5" v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" @@ -33,7 +32,7 @@ type ShadowSocks struct { obfsMode string obfsOption *simpleObfsOption v2rayOption *v2rayObfs.Option - shadowTLSOption *shadowTLSOption + shadowTLSOption *shadowtls.ShadowTLSOption tlsConfig *tls.Config } @@ -67,14 +66,31 @@ type v2rayObfsOption struct { } type shadowTLSOption struct { - Password string `obfs:"password"` - Host string `obfs:"host"` - Fingerprint string `obfs:"fingerprint,omitempty"` - SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` + Password string `obfs:"password"` + Host string `obfs:"host"` + Fingerprint string `obfs:"fingerprint,omitempty"` + ClientFingerprint string `obfs:"client-fingerprint,omitempty"` + SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` + Version int `obfs:"version,omitempty"` } // StreamConn implements C.ProxyAdapter func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { + switch ss.obfsMode { + case shadowtls.Mode: + // fix tls handshake not timeout + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) + defer cancel() + var err error + c, err = shadowtls.NewShadowTLS(ctx, c, ss.shadowTLSOption) + if err != nil { + return nil, err + } + } + return ss.streamConn(c, metadata) +} + +func (ss *ShadowSocks) streamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { switch ss.obfsMode { case "tls": c = obfs.NewTLSObfs(c, ss.obfsOption.Host) @@ -87,8 +103,6 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } - case shadowtls.Mode: - c = shadowtls.NewShadowTLS(c, ss.shadowTLSOption.Password, ss.tlsConfig) } if metadata.NetWork == C.UDP && ss.option.UDPOverTCP { return ss.method.DialConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")) @@ -113,7 +127,15 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale safeConnClose(c, err) }(c) - c, err = ss.StreamConn(c, metadata) + switch ss.obfsMode { + case shadowtls.Mode: + c, err = shadowtls.NewShadowTLS(ctx, c, ss.shadowTLSOption) + if err != nil { + return nil, err + } + } + + c, err = ss.streamConn(c, metadata) return NewConn(c, ss), err } @@ -171,7 +193,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { var v2rayOption *v2rayObfs.Option var obfsOption *simpleObfsOption - var shadowTLSOpt *shadowTLSOption + var shadowTLSOpt *shadowtls.ShadowTLSOption var tlsConfig *tls.Config obfsMode := "" @@ -210,24 +232,20 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } } else if option.Plugin == shadowtls.Mode { obfsMode = shadowtls.Mode - shadowTLSOpt = &shadowTLSOption{} - if err := decoder.Decode(option.PluginOpts, shadowTLSOpt); err != nil { + opt := &shadowTLSOption{ + Version: 2, + } + if err := decoder.Decode(option.PluginOpts, opt); err != nil { return nil, fmt.Errorf("ss %s initialize shadow-tls-plugin error: %w", addr, err) } - tlsConfig = &tls.Config{ - NextProtos: shadowtls.DefaultALPN, - MinVersion: tls.VersionTLS12, - InsecureSkipVerify: shadowTLSOpt.SkipCertVerify, - ServerName: shadowTLSOpt.Host, - } - - if len(shadowTLSOpt.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, shadowTLSOpt.Fingerprint); err != nil { - return nil, err - } + shadowTLSOpt = &shadowtls.ShadowTLSOption{ + Password: opt.Password, + Host: opt.Host, + Fingerprint: opt.Fingerprint, + ClientFingerprint: opt.ClientFingerprint, + SkipCertVerify: opt.SkipCertVerify, + Version: opt.Version, } } diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index d1a5ea6e..e3dafbbf 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -17,7 +17,7 @@ import ( "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/sing" + "github.com/Dreamacro/clash/log" wireguard "github.com/metacubex/sing-wireguard" @@ -174,14 +174,14 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { } outbound.device = device.NewDevice(outbound.tunDevice, outbound.bind, &device.Logger{ Verbosef: func(format string, args ...interface{}) { - sing.Logger.Debug(fmt.Sprintf(strings.ToLower(format), args...)) + log.SingLogger.Debug(fmt.Sprintf(strings.ToLower(format), args...)) }, Errorf: func(format string, args ...interface{}) { - sing.Logger.Error(fmt.Sprintf(strings.ToLower(format), args...)) + log.SingLogger.Error(fmt.Sprintf(strings.ToLower(format), args...)) }, }, option.Workers) if debug.Enabled { - sing.Logger.Trace("created wireguard ipc conf: \n", ipcConf) + log.SingLogger.Trace("created wireguard ipc conf: \n", ipcConf) } err = outbound.device.IpcSet(ipcConf) if err != nil { diff --git a/component/tls/utls.go b/component/tls/utls.go index f965fc64..4724c9a5 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -7,7 +7,7 @@ import ( "github.com/Dreamacro/clash/log" "github.com/mroth/weightedrand/v2" - utls "github.com/refraction-networking/utls" + utls "github.com/sagernet/utls" ) type UConn struct { diff --git a/go.mod b/go.mod index c2a979dc..b7d374ca 100644 --- a/go.mod +++ b/go.mod @@ -25,11 +25,12 @@ require ( github.com/miekg/dns v1.1.50 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 - github.com/refraction-networking/utls v1.2.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 + github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b + github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d + github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 github.com/sirupsen/logrus v1.9.0 @@ -38,11 +39,11 @@ require ( go.etcd.io/bbolt v1.3.6 go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 - golang.org/x/crypto v0.5.0 + golang.org/x/crypto v0.6.0 golang.org/x/exp v0.0.0-20221205204356-47842c84f3db - golang.org/x/net v0.5.0 + golang.org/x/net v0.6.0 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.4.0 + golang.org/x/sys v0.5.0 google.golang.org/protobuf v1.28.1 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.1.7 @@ -50,7 +51,7 @@ require ( require ( github.com/ajg/form v1.5.1 // indirect - github.com/andybalholm/brotli v1.0.4 // indirect + github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect @@ -59,7 +60,7 @@ require ( github.com/google/go-cmp v0.5.9 // indirect github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/josharian/native v1.1.0 // indirect - github.com/klauspost/compress v1.15.12 // indirect + github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/mdlayher/socket v0.4.0 // indirect github.com/metacubex/gvisor v0.0.0-20230213124051-7a16c835d80e // indirect @@ -75,7 +76,7 @@ require ( github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect golang.org/x/mod v0.6.0 // indirect - golang.org/x/text v0.6.0 // indirect + golang.org/x/text v0.7.0 // indirect golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect golang.org/x/tools v0.2.0 // indirect ) diff --git a/go.sum b/go.sum index 076442ab..cacccf97 100644 --- a/go.sum +++ b/go.sum @@ -2,8 +2,8 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= -github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= -github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= 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= @@ -67,8 +67,8 @@ github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGu github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/klauspost/compress v1.15.12 h1:YClS/PImqYbn+UILDnqxQCZ3RehC9N318SU3kElDUEM= -github.com/klauspost/compress v1.15.12/go.mod h1:QPwzmACJjUTFsnSHH934V6woptycfrDDJnH7hvFVbGM= +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= @@ -121,8 +121,6 @@ github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4 github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI= github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= -github.com/refraction-networking/utls v1.2.0 h1:U5f8wkij2NVinfLuJdFP3gCMwIHs+EzvhxmYdXgiapo= -github.com/refraction-networking/utls v1.2.0/go.mod h1:NPq+cVqzH7D1BeOkmOcb5O/8iVewAsiVt2x1/eO0hgQ= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34= github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g= @@ -131,12 +129,16 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9 h1:qnXh4RjHsNjdZXkfbqwVqAzYUfc160gfkS5gepmsA+A= -github.com/sagernet/sing v0.1.7-0.20230207063819-27d2950cdbe9/go.mod h1:JLSXsPTGRJFo/3X7EcAOCUgJH2/gAoxSJgBsnCZRp/w= +github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b h1:Ji2AfGlc4j9AitobOx4k3BCj7eS5nSxL1cgaL81zvlo= +github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e h1:S1fd0kB9aEU68dd269AQy783sUlFu/2fSh/4YYVJ/Oc= +github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb h1:oyd3w17fXNmWVYFUe17YVHJW5CLW9X2mxJFDP/IWrAM= github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb/go.mod h1:9KkmnQzTL4Gvv8U2TRAH2BOITCGsGPpHtUPP5sxn5sY= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= +github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 h1:gDXi/0uYe8dA48UyUI1LM2la5QYN0IvsDvR2H2+kFnA= +github.com/sagernet/utls v0.0.0-20230220130002-c08891932056/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= @@ -169,8 +171,8 @@ go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= -golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= +golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= +golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -190,8 +192,8 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw= -golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= +golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= @@ -220,14 +222,14 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18= -golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k= -golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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/log.go b/listener/sing/log.go deleted file mode 100644 index 4847e063..00000000 --- a/listener/sing/log.go +++ /dev/null @@ -1,41 +0,0 @@ -package sing - -import ( - "fmt" - - "github.com/Dreamacro/clash/log" - - L "github.com/sagernet/sing/common/logger" -) - -type logger struct{} - -func (l logger) Trace(args ...any) { - log.Debugln(fmt.Sprint(args...)) -} - -func (l logger) Debug(args ...any) { - log.Debugln(fmt.Sprint(args...)) -} - -func (l logger) Info(args ...any) { - log.Infoln(fmt.Sprint(args...)) -} - -func (l logger) Warn(args ...any) { - log.Warnln(fmt.Sprint(args...)) -} - -func (l logger) Error(args ...any) { - log.Errorln(fmt.Sprint(args...)) -} - -func (l logger) Fatal(args ...any) { - log.Fatalln(fmt.Sprint(args...)) -} - -func (l logger) Panic(args ...any) { - log.Fatalln(fmt.Sprint(args...)) -} - -var Logger L.Logger = logger{} diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 8e0a6c34..63d475cf 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -237,7 +237,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte EndpointIndependentNat: options.EndpointIndependentNat, UDPTimeout: udpTimeout, Handler: handler, - Logger: sing.Logger, + Logger: log.SingLogger, }) if err != nil { return diff --git a/log/sing.go b/log/sing.go new file mode 100644 index 00000000..818acc79 --- /dev/null +++ b/log/sing.go @@ -0,0 +1,68 @@ +package log + +import ( + "context" + "fmt" + + L "github.com/sagernet/sing/common/logger" +) + +type singLogger struct{} + +func (l singLogger) TraceContext(ctx context.Context, args ...any) { + Debugln(fmt.Sprint(args...)) +} + +func (l singLogger) DebugContext(ctx context.Context, args ...any) { + Debugln(fmt.Sprint(args...)) +} + +func (l singLogger) InfoContext(ctx context.Context, args ...any) { + Infoln(fmt.Sprint(args...)) +} + +func (l singLogger) WarnContext(ctx context.Context, args ...any) { + Warnln(fmt.Sprint(args...)) +} + +func (l singLogger) ErrorContext(ctx context.Context, args ...any) { + Errorln(fmt.Sprint(args...)) +} + +func (l singLogger) FatalContext(ctx context.Context, args ...any) { + Fatalln(fmt.Sprint(args...)) +} + +func (l singLogger) PanicContext(ctx context.Context, args ...any) { + Fatalln(fmt.Sprint(args...)) +} + +func (l singLogger) Trace(args ...any) { + Debugln(fmt.Sprint(args...)) +} + +func (l singLogger) Debug(args ...any) { + Debugln(fmt.Sprint(args...)) +} + +func (l singLogger) Info(args ...any) { + Infoln(fmt.Sprint(args...)) +} + +func (l singLogger) Warn(args ...any) { + Warnln(fmt.Sprint(args...)) +} + +func (l singLogger) Error(args ...any) { + Errorln(fmt.Sprint(args...)) +} + +func (l singLogger) Fatal(args ...any) { + Fatalln(fmt.Sprint(args...)) +} + +func (l singLogger) Panic(args ...any) { + Fatalln(fmt.Sprint(args...)) +} + +var SingLogger L.ContextLogger = singLogger{} diff --git a/transport/sing-shadowtls/shadowtls.go b/transport/sing-shadowtls/shadowtls.go new file mode 100644 index 00000000..0e1e95c0 --- /dev/null +++ b/transport/sing-shadowtls/shadowtls.go @@ -0,0 +1,91 @@ +package sing_shadowtls + +import ( + "context" + "crypto/tls" + "net" + + tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/log" + + "github.com/sagernet/sing-shadowtls" + sing_common "github.com/sagernet/sing/common" + utls "github.com/sagernet/utls" +) + +const ( + Mode string = "shadow-tls" +) + +var ( + DefaultALPN = []string{"h2", "http/1.1"} +) + +type ShadowTLSOption struct { + Password string + Host string + Fingerprint string + ClientFingerprint string + SkipCertVerify bool + Version int +} + +func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) (net.Conn, error) { + tlsConfig := &tls.Config{ + NextProtos: DefaultALPN, + MinVersion: tls.VersionTLS12, + InsecureSkipVerify: option.SkipCertVerify, + ServerName: option.Host, + } + + var err error + if len(option.Fingerprint) == 0 { + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) + } else { + if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { + return nil, err + } + } + + tlsHandshake := shadowtls.DefaultTLSHandshakeFunc(option.Password, tlsConfig) + if len(option.ClientFingerprint) != 0 { + if fingerprint, exists := tlsC.GetFingerprint(option.ClientFingerprint); exists { + tlsHandshake = uTLSHandshakeFunc(tlsConfig, *fingerprint.ClientHelloID) + } + } + client, err := shadowtls.NewClient(shadowtls.ClientConfig{ + Version: option.Version, + Password: option.Password, + TLSHandshake: tlsHandshake, + Logger: log.SingLogger, + }) + if err != nil { + return nil, err + } + return client.DialContextConn(ctx, conn) +} + +func uTLSHandshakeFunc(config *tls.Config, clientHelloID utls.ClientHelloID) shadowtls.TLSHandshakeFunc { + return func(ctx context.Context, conn net.Conn, sessionIDGenerator shadowtls.TLSSessionIDGeneratorFunc) error { + tlsConfig := &utls.Config{ + Rand: config.Rand, + Time: config.Time, + VerifyPeerCertificate: config.VerifyPeerCertificate, + RootCAs: config.RootCAs, + NextProtos: config.NextProtos, + ServerName: config.ServerName, + InsecureSkipVerify: config.InsecureSkipVerify, + CipherSuites: config.CipherSuites, + MinVersion: config.MinVersion, + MaxVersion: config.MaxVersion, + CurvePreferences: sing_common.Map(config.CurvePreferences, func(it tls.CurveID) utls.CurveID { + return utls.CurveID(it) + }), + SessionTicketsDisabled: config.SessionTicketsDisabled, + Renegotiation: utls.RenegotiationSupport(config.Renegotiation), + SessionIDGenerator: sessionIDGenerator, + } + tlsConn := utls.UClient(conn, tlsConfig, clientHelloID) + return tlsConn.HandshakeContext(ctx) + } +} From 5c8d955f61c51933909b9d722ede84958234bb65 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 22 Feb 2023 13:41:33 +0800 Subject: [PATCH 004/530] chore: better windows bind error handle --- component/dialer/bind_windows.go | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/component/dialer/bind_windows.go b/component/dialer/bind_windows.go index b680e90f..4a099169 100644 --- a/component/dialer/bind_windows.go +++ b/component/dialer/bind_windows.go @@ -37,14 +37,25 @@ func bindControl(ifaceIdx int) controlFn { var innerErr error err = c.Control(func(fd uintptr) { handle := syscall.Handle(fd) + bind6err := bind6(handle, ifaceIdx) + bind4err := bind4(handle, ifaceIdx) switch network { - case "tcp6", "udp6": - innerErr = bind6(handle, ifaceIdx) - _ = bind4(handle, ifaceIdx) - default: - innerErr = bind4(handle, ifaceIdx) - // try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6 - _ = bind6(handle, ifaceIdx) + case "ip6", "tcp6": + innerErr = bind6err + case "ip4", "tcp4", "udp4": + innerErr = bind4err + case "udp6": + // golang will set network to udp6 when listenUDP on wildcard ip (eg: ":0", "") + if (!addrPort.Addr().IsValid() || addrPort.Addr().IsUnspecified()) && bind6err != nil { + // try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6 + if bind4err != nil { + innerErr = bind6err + } else { + innerErr = bind4err + } + } else { + innerErr = bind6err + } } }) From 4a6ebff473c93e1c4c43c1f2e2411408ff5b57e6 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 22 Feb 2023 19:14:11 +0800 Subject: [PATCH 005/530] fix: add "dns resolve failed" error in dialer --- component/dialer/dialer.go | 127 +++++++++++++++---------------------- 1 file changed, 50 insertions(+), 77 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index e31936e9..39e47bde 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -65,18 +65,7 @@ func DialContext(ctx context.Context, network, address string, options ...Option } func ListenPacket(ctx context.Context, network, address string, options ...Option) (net.PacketConn, error) { - cfg := &option{ - interfaceName: DefaultInterface.Load(), - routingMark: int(DefaultRoutingMark.Load()), - } - - for _, o := range DefaultOptions { - o(cfg) - } - - for _, o := range options { - o(cfg) - } + cfg := applyOptions(options...) lc := &net.ListenConfig{} if cfg.interfaceName != "" { @@ -132,6 +121,35 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po return dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port)) } +func singleDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { + host, port, err := net.SplitHostPort(address) + if err != nil { + return nil, err + } + + var ip netip.Addr + switch network { + case "tcp4", "udp4": + if opt.resolver == nil { + ip, err = resolver.ResolveIPv4ProxyServerHost(ctx, host) + } else { + ip, err = resolver.ResolveIPv4WithResolver(ctx, host, opt.resolver) + } + default: + if opt.resolver == nil { + ip, err = resolver.ResolveIPv6ProxyServerHost(ctx, host) + } else { + ip, err = resolver.ResolveIPv6WithResolver(ctx, host, opt.resolver) + } + } + if err != nil { + err = fmt.Errorf("dns resolve failed:%w", err) + return nil, err + } + + return dialContext(ctx, network, ip, port, opt) +} + func dualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { host, port, err := net.SplitHostPort(address) if err != nil { @@ -178,6 +196,7 @@ func dualStackDialContext(ctx context.Context, network, address string, opt *opt } } if result.error != nil { + result.error = fmt.Errorf("dns resolve failed:%w", result.error) return } result.resolved = true @@ -225,26 +244,6 @@ func dualStackDialContext(ctx context.Context, network, address string, opt *opt return nil, err } -func concurrentDualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { - host, port, err := net.SplitHostPort(address) - if err != nil { - return nil, err - } - - var ips []netip.Addr - if opt.resolver != nil { - ips, err = resolver.LookupIPWithResolver(ctx, host, opt.resolver) - } else { - ips, err = resolver.LookupIPProxyServerHost(ctx, host) - } - - if err != nil { - return nil, err - } - - return concurrentDialContext(ctx, network, ips, port, opt) -} - func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { returned := make(chan struct{}) defer close(returned) @@ -356,77 +355,51 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr return nil, finalError } -func singleDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { - host, port, err := net.SplitHostPort(address) - if err != nil { - return nil, err - } - - var ip netip.Addr - switch network { - case "tcp4", "udp4": - if opt.resolver == nil { - ip, err = resolver.ResolveIPv4ProxyServerHost(ctx, host) - } else { - ip, err = resolver.ResolveIPv4WithResolver(ctx, host, opt.resolver) - } - default: - if opt.resolver == nil { - ip, err = resolver.ResolveIPv6ProxyServerHost(ctx, host) - } else { - ip, err = resolver.ResolveIPv6WithResolver(ctx, host, opt.resolver) - } - } - if err != nil { - return nil, err - } - - return dialContext(ctx, network, ip, port, opt) -} - func concurrentSingleDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { - switch network { - case "tcp4", "udp4": - return concurrentIPv4DialContext(ctx, network, address, opt) - default: - return concurrentIPv6DialContext(ctx, network, address, opt) - } -} - -func concurrentIPv4DialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { host, port, err := net.SplitHostPort(address) if err != nil { return nil, err } var ips []netip.Addr - if opt.resolver == nil { - ips, err = resolver.LookupIPv4ProxyServerHost(ctx, host) - } else { - ips, err = resolver.LookupIPv4WithResolver(ctx, host, opt.resolver) + switch network { + case "tcp4", "udp4": + if opt.resolver == nil { + ips, err = resolver.LookupIPv4ProxyServerHost(ctx, host) + } else { + ips, err = resolver.LookupIPv4WithResolver(ctx, host, opt.resolver) + } + default: + if opt.resolver == nil { + ips, err = resolver.LookupIPv6ProxyServerHost(ctx, host) + } else { + ips, err = resolver.LookupIPv6WithResolver(ctx, host, opt.resolver) + } } if err != nil { + err = fmt.Errorf("dns resolve failed:%w", err) return nil, err } return concurrentDialContext(ctx, network, ips, port, opt) } -func concurrentIPv6DialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { +func concurrentDualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { host, port, err := net.SplitHostPort(address) if err != nil { return nil, err } var ips []netip.Addr - if opt.resolver == nil { - ips, err = resolver.LookupIPv6ProxyServerHost(ctx, host) + if opt.resolver != nil { + ips, err = resolver.LookupIPWithResolver(ctx, host, opt.resolver) } else { - ips, err = resolver.LookupIPv6WithResolver(ctx, host, opt.resolver) + ips, err = resolver.LookupIPProxyServerHost(ctx, host) } if err != nil { + err = fmt.Errorf("dns resolve failed:%w", err) return nil, err } From 28c57c41444063c1496859fd860427c973dff859 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 22 Feb 2023 19:35:43 +0800 Subject: [PATCH 006/530] chore: Update dependencies --- go.mod | 17 ++++++++--------- go.sum | 34 ++++++++++++++++------------------ 2 files changed, 24 insertions(+), 27 deletions(-) diff --git a/go.mod b/go.mod index b7d374ca..9c3b78ac 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( 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 - github.com/gofrs/uuid v4.3.1+incompatible + github.com/gofrs/uuid v4.4.0+incompatible github.com/google/gopacket v1.1.19 github.com/gorilla/websocket v1.5.0 github.com/hashicorp/golang-lru v0.5.4 @@ -20,7 +20,7 @@ require ( github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.32.0 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7 - github.com/metacubex/sing-tun v0.1.1-0.20230213124625-28d27a0c236b + github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 github.com/miekg/dns v1.1.50 github.com/mroth/weightedrand/v2 v2.0.0 @@ -28,7 +28,7 @@ require ( github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e - github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb + github.com/sagernet/sing-vmess v0.1.2 github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c @@ -44,7 +44,7 @@ require ( golang.org/x/net v0.6.0 golang.org/x/sync v0.1.0 golang.org/x/sys v0.5.0 - google.golang.org/protobuf v1.28.1 + google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.1.7 ) @@ -63,7 +63,7 @@ require ( github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/mdlayher/socket v0.4.0 // indirect - github.com/metacubex/gvisor v0.0.0-20230213124051-7a16c835d80e // indirect + github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -71,14 +71,13 @@ require ( github.com/quic-go/qtls-go1-18 v0.2.0 // indirect github.com/quic-go/qtls-go1-19 v0.2.0 // indirect github.com/quic-go/qtls-go1-20 v0.1.0 // indirect - github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - golang.org/x/mod v0.6.0 // indirect + golang.org/x/mod v0.7.0 // indirect golang.org/x/text v0.7.0 // indirect - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect - golang.org/x/tools v0.2.0 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect + golang.org/x/tools v0.5.0 // indirect ) replace go.uber.org/atomic v1.10.0 => github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 diff --git a/go.sum b/go.sum index cacccf97..c06b8506 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ 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-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/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= +github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 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.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= @@ -87,14 +87,14 @@ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= -github.com/metacubex/gvisor v0.0.0-20230213124051-7a16c835d80e h1:j4j2dlV2d//FAsQlRUriH6nvv36AEAhECbNy7narf1M= -github.com/metacubex/gvisor v0.0.0-20230213124051-7a16c835d80e/go.mod h1:abc7OdNmWlhcNHz84ECEosd5ND5pnWQmD8W55p/4cuc= +github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65 h1:WUINdCB/UvSX9I+wN+y5xVEisPrXA73rxkoHK5DMyZs= +github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65/go.mod h1:e3lCxh3TozKMWAsYTC7nBVnepAxPL/sNyScUFvmEoec= github.com/metacubex/quic-go v0.32.0 h1:dSD8LB4MSeBuD4otd8y1DUZcRdDcEB0Ax5esPOqn2Hw= github.com/metacubex/quic-go v0.32.0/go.mod h1:yParIzDYUd/t/pzFlDtZKhnvSqbUu0bPChlKEGmJStA= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7 h1:MNCGIpXhxXn9ck5bxfm/cW9Nr2FGQ5cakcGK0yKZcak= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ= -github.com/metacubex/sing-tun v0.1.1-0.20230213124625-28d27a0c236b h1:ZF/oNrSCaxIFoZmFQCiUx67t9aENZjyuqw2n4zw3L2o= -github.com/metacubex/sing-tun v0.1.1-0.20230213124625-28d27a0c236b/go.mod h1:TjuaYuR/g1MaY3um89xTfRNt61FJ2IcI/m5zD8QBxw4= +github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d h1:oMzkrEoBdwn2/Vyu0n6/LAmvjxqsyFs+f2kqeg7kI8U= +github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d/go.mod h1:WmbtxVPpJulKoQGwfnBMk4KSWzZ68sE/myTrQeN/5GE= github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 h1:d96mCF/LYyC9kULd2xwcXfP0Jd8klrOngmRxuUIZg/8= github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4/go.mod h1:p2VpJuxRefgVMxc8cmatMGSFNvYbjMYMsXJOe7qFstw= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= @@ -122,8 +122,6 @@ github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05 github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI= github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34= -github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g= 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= @@ -133,8 +131,8 @@ github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b h1:Ji2AfGlc4j9Aito github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e h1:S1fd0kB9aEU68dd269AQy783sUlFu/2fSh/4YYVJ/Oc= github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= -github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb h1:oyd3w17fXNmWVYFUe17YVHJW5CLW9X2mxJFDP/IWrAM= -github.com/sagernet/sing-vmess v0.1.1-0.20230212211128-cb4e47dd0acb/go.mod h1:9KkmnQzTL4Gvv8U2TRAH2BOITCGsGPpHtUPP5sxn5sY= +github.com/sagernet/sing-vmess v0.1.2 h1:RbOZNAId2LrCai8epMoQXlf0XTrou0bfcw08hNBg6lM= +github.com/sagernet/sing-vmess v0.1.2/go.mod h1:9NSj8mZTx1JIY/HF9LaYRppUsVkysIN5tEFpNZujXxY= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 h1:gDXi/0uYe8dA48UyUI1LM2la5QYN0IvsDvR2H2+kFnA= @@ -178,8 +176,8 @@ golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZ 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.6.0 h1:b9gGHsz9/HhJ3HF5DHQytPpuwocVTChQJK3AvoLRD5I= -golang.org/x/mod v0.6.0/go.mod h1:4mET923SAdbXp2ki8ey+zGs1SLqsuM2Y0uvdZR/fUNI= +golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= +golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -230,23 +228,23 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/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-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 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.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.2.0 h1:G6AHpWxTMGY1KyEYoAQ5WTtIekUUvDNjan3ugu60JvE= -golang.org/x/tools v0.2.0/go.mod h1:y4OqIKeOV/fWJetJ8bXPU1sEVniLMIyDAZWeHdV+NTA= +golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= +golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= 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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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= 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= From 21848d6bf1fb2707f3d9115bab9537e52c21354f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 22 Feb 2023 19:43:32 +0800 Subject: [PATCH 007/530] chore: code cleanup --- adapter/outbound/shadowsocks.go | 4 ---- 1 file changed, 4 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index f6701469..ae404eec 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -2,7 +2,6 @@ package outbound import ( "context" - "crypto/tls" "errors" "fmt" "net" @@ -33,7 +32,6 @@ type ShadowSocks struct { obfsOption *simpleObfsOption v2rayOption *v2rayObfs.Option shadowTLSOption *shadowtls.ShadowTLSOption - tlsConfig *tls.Config } type ShadowSocksOption struct { @@ -194,7 +192,6 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { var v2rayOption *v2rayObfs.Option var obfsOption *simpleObfsOption var shadowTLSOpt *shadowtls.ShadowTLSOption - var tlsConfig *tls.Config obfsMode := "" decoder := structure.NewDecoder(structure.Option{TagName: "obfs", WeaklyTypedInput: true}) @@ -266,7 +263,6 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { v2rayOption: v2rayOption, obfsOption: obfsOption, shadowTLSOption: shadowTLSOpt, - tlsConfig: tlsConfig, }, nil } From f586f22ce35c4df2126bb27385116f001ad3c53e Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 22 Feb 2023 21:08:08 +0800 Subject: [PATCH 008/530] fix: incorrect time to set interface name --- config/config.go | 1 - 1 file changed, 1 deletion(-) diff --git a/config/config.go b/config/config.go index d71fc63f..24159d8e 100644 --- a/config/config.go +++ b/config/config.go @@ -447,7 +447,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } config.General = general - dialer.DefaultInterface.Store(config.General.Interface) proxies, providers, err := parseProxies(rawCfg) if err != nil { return nil, err From 7fecd20a1d2dc921261e08351d115d125ef0348f Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 22 Feb 2023 22:32:04 +0800 Subject: [PATCH 009/530] chore: adjust the configuration loading order --- hub/executor/executor.go | 60 +++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index b3e33f98..ec6ee8ff 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -81,13 +81,13 @@ func ApplyConfig(cfg *config.Config, force bool) { updateRules(cfg.Rules, cfg.SubRules, cfg.RuleProviders) updateSniffer(cfg.Sniffer) updateHosts(cfg.Hosts) + updateGeneral(cfg.General) initInnerTcp() updateDNS(cfg.DNS, cfg.General.IPv6) loadProxyProvider(cfg.Providers) updateProfile(cfg) loadRuleProvider(cfg.RuleProviders) - updateGeneral(cfg.General, force) - updateListeners(cfg.Listeners) + updateListeners(cfg.General, cfg.Listeners, force) updateIPTables(cfg) updateTun(cfg.General) updateExperimental(cfg) @@ -134,12 +134,31 @@ func GetGeneral() *config.General { return general } -func updateListeners(listeners map[string]C.InboundListener) { +func updateListeners(general *config.General, listeners map[string]C.InboundListener, force bool) { tcpIn := tunnel.TCPIn() udpIn := tunnel.UDPIn() natTable := tunnel.NatTable() listener.PatchInboundListeners(listeners, tcpIn, udpIn, natTable, true) + if !force { + return + } + + inbound.SetTfo(general.InboundTfo) + allowLan := general.AllowLan + listener.SetAllowLan(allowLan) + + bindAddress := general.BindAddress + listener.SetBindAddress(bindAddress) + listener.ReCreateHTTP(general.Port, tcpIn) + listener.ReCreateSocks(general.SocksPort, tcpIn, udpIn) + listener.ReCreateRedir(general.RedirPort, tcpIn, udpIn, natTable) + listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tcpIn, udpIn) + listener.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn, natTable) + listener.ReCreateMixed(general.MixedPort, tcpIn, udpIn) + listener.ReCreateShadowSocks(general.ShadowSocksConfig, tcpIn, udpIn) + listener.ReCreateVmess(general.VmessConfig, tcpIn, udpIn) + listener.ReCreateTuic(LC.TuicServer(general.TuicServer), tcpIn, udpIn) } func updateExperimental(c *config.Config) { @@ -304,7 +323,7 @@ func updateTunnels(tunnels []LC.Tunnel) { listener.PatchTunnel(tunnels, tunnel.TCPIn(), tunnel.UDPIn()) } -func updateGeneral(general *config.General, force bool) { +func updateGeneral(general *config.General) { tunnel.SetMode(general.Mode) tunnel.SetFindProcessMode(general.FindProcessMode) dialer.DisableIPv6 = !general.IPv6 @@ -319,9 +338,9 @@ func updateGeneral(general *config.General, force bool) { } adapter.UnifiedDelay.Store(general.UnifiedDelay) - dialer.DefaultInterface.Store(general.Interface) - - if dialer.DefaultInterface.Load() != "" { + // Avoid reload configuration clean the value, causing traffic loops + if general.Interface != "" && general.Tun.Enable && !general.Tun.AutoDetectInterface { + dialer.DefaultInterface.Store(general.Interface) log.Infoln("Use interface name: %s", general.Interface) } @@ -331,35 +350,8 @@ func updateGeneral(general *config.General, force bool) { } iface.FlushCache() - - if !force { - return - } - geodataLoader := general.GeodataLoader G.SetLoader(geodataLoader) - - allowLan := general.AllowLan - listener.SetAllowLan(allowLan) - - bindAddress := general.BindAddress - listener.SetBindAddress(bindAddress) - - inbound.SetTfo(general.InboundTfo) - - tcpIn := tunnel.TCPIn() - udpIn := tunnel.UDPIn() - natTable := tunnel.NatTable() - - listener.ReCreateHTTP(general.Port, tcpIn) - listener.ReCreateSocks(general.SocksPort, tcpIn, udpIn) - listener.ReCreateRedir(general.RedirPort, tcpIn, udpIn, natTable) - listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tcpIn, udpIn) - listener.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn, natTable) - listener.ReCreateMixed(general.MixedPort, tcpIn, udpIn) - listener.ReCreateShadowSocks(general.ShadowSocksConfig, tcpIn, udpIn) - listener.ReCreateVmess(general.VmessConfig, tcpIn, udpIn) - listener.ReCreateTuic(LC.TuicServer(general.TuicServer), tcpIn, udpIn) } func updateUsers(users []auth.AuthUser) { From b72bd5bb37977ef04886644afc62f742363252db Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 23 Feb 2023 14:13:27 +0800 Subject: [PATCH 010/530] chore: adjust the configuration loading order --- hub/executor/executor.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index ec6ee8ff..57a9ffe8 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -144,6 +144,10 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList return } + if general.Interface == "" && (!general.Tun.Enable || !general.Tun.AutoDetectInterface) { + dialer.DefaultInterface.Store(general.Interface) + } + inbound.SetTfo(general.InboundTfo) allowLan := general.AllowLan listener.SetAllowLan(allowLan) @@ -339,9 +343,14 @@ func updateGeneral(general *config.General) { adapter.UnifiedDelay.Store(general.UnifiedDelay) // Avoid reload configuration clean the value, causing traffic loops - if general.Interface != "" && general.Tun.Enable && !general.Tun.AutoDetectInterface { + if listener.GetTunConf().Enable && listener.GetTunConf().AutoDetectInterface { + // changed only when the name is specified + // if name is empty, setting delay until after tun loaded + if general.Interface != "" && (!general.Tun.Enable || !general.Tun.AutoDetectInterface) { + dialer.DefaultInterface.Store(general.Interface) + } + } else { dialer.DefaultInterface.Store(general.Interface) - log.Infoln("Use interface name: %s", general.Interface) } dialer.DefaultRoutingMark.Store(int32(general.RoutingMark)) From d5d62a4ffd20235b983842db639bd841fde8ded8 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 23 Feb 2023 20:26:25 +0800 Subject: [PATCH 011/530] chore: change internal tcp traffic type --- adapter/inbound/socket.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index 590f64d7..4024ee42 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -34,7 +34,7 @@ func NewInner(conn net.Conn, dst string, host string) *context.ConnContext { metadata := &C.Metadata{} metadata.NetWork = C.TCP metadata.Type = C.INNER - metadata.DNSMode = C.DNSMapping + metadata.DNSMode = C.DNSNormal metadata.Host = host metadata.Process = C.ClashName if h, port, err := net.SplitHostPort(dst); err == nil { From a1d008e6f0c62ba0c0272922316c9371d6a0c060 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 23 Feb 2023 23:30:53 +0800 Subject: [PATCH 012/530] chore: add pprof api, when log-level is debug --- hub/hub.go | 3 ++- hub/route/server.go | 16 ++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/hub/hub.go b/hub/hub.go index 1e925bfe..e4c414fa 100644 --- a/hub/hub.go +++ b/hub/hub.go @@ -4,6 +4,7 @@ import ( "github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/hub/executor" "github.com/Dreamacro/clash/hub/route" + "github.com/Dreamacro/clash/log" ) type Option func(*config.Config) @@ -43,7 +44,7 @@ func Parse(options ...Option) error { if cfg.General.ExternalController != "" { go route.Start(cfg.General.ExternalController, cfg.General.ExternalControllerTLS, - cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey) + cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey,cfg.General.LogLevel==log.DEBUG) } executor.ApplyConfig(cfg, true) diff --git a/hub/route/server.go b/hub/route/server.go index 0d6a47ac..2ce4ba8c 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "encoding/json" "net/http" + "runtime/debug" "strings" "time" @@ -13,8 +14,8 @@ import ( 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" "github.com/go-chi/render" "github.com/gorilla/websocket" @@ -43,7 +44,7 @@ func SetUIPath(path string) { } func Start(addr string, tlsAddr string, secret string, - certificat, privateKey string) { + certificat, privateKey string, isDebug bool) { if serverAddr != "" { return } @@ -59,6 +60,17 @@ func Start(addr string, tlsAddr string, secret string, MaxAge: 300, }) r.Use(corsM.Handler) + if isDebug { + r.Mount("/debug", func() http.Handler { + r := chi.NewRouter() + r.Put("/gc", func(w http.ResponseWriter, r *http.Request) { + debug.FreeOSMemory() + }) + handler := middleware.Profiler + r.Mount("/", handler()) + return r + }()) + } r.Group(func(r chi.Router) { r.Use(authentication) r.Get("/", hello) From 75680c5866ebc497016120cda9afc39c3e13a0aa Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 24 Feb 2023 09:54:54 +0800 Subject: [PATCH 013/530] chore: use early conn to support real ws 0-rtt --- adapter/outbound/reject.go | 3 +++ adapter/outbound/shadowsocks.go | 4 ++-- adapter/outbound/vmess.go | 10 ++++----- adapter/outboundgroup/fallback.go | 13 ++++++++++- adapter/outboundgroup/loadbalance.go | 28 +++++++++++++++--------- adapter/outboundgroup/urltest.go | 13 ++++++++++- common/callback/callback.go | 25 ++++++++++++++++++++++ common/net/bufconn.go | 12 ++++++++++- component/sniffer/dispatcher.go | 9 ++------ constant/context.go | 4 +++- context/conn.go | 4 ++-- transport/vless/conn.go | 15 ++++++------- tunnel/tunnel.go | 32 ++++++++++++++++++++++++++-- 13 files changed, 132 insertions(+), 40 deletions(-) create mode 100644 common/callback/callback.go diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index 43833238..d5a9c823 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -53,6 +53,9 @@ func (rw *nopConn) Read(b []byte) (int, error) { } func (rw *nopConn) Write(b []byte) (int, error) { + if len(b) == 0 { + return 0, nil + } return 0, io.EOF } diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index ae404eec..2ac1f234 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -103,9 +103,9 @@ func (ss *ShadowSocks) streamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e } } if metadata.NetWork == C.UDP && ss.option.UDPOverTCP { - return ss.method.DialConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")) + return ss.method.DialEarlyConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")), nil } - return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + return ss.method.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil } // DialContext implements C.ProxyAdapter diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 5da8c8b1..e8220767 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -213,12 +213,12 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { } if metadata.NetWork == C.UDP { if v.option.XUDP { - return v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + return v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil } else { - return v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + return v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil } } else { - return v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + return v.client.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil } } @@ -289,9 +289,9 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o }(c) if v.option.XUDP { - c, err = v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + c = v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) } else { - c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + c = v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) } if err != nil { diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 34365d0e..066e8a37 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -7,6 +7,7 @@ import ( "time" "github.com/Dreamacro/clash/adapter/outbound" + "github.com/Dreamacro/clash/common/callback" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" @@ -30,11 +31,21 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata, opts . c, err := proxy.DialContext(ctx, metadata, f.Base.DialOptions(opts...)...) if err == nil { c.AppendToChains(f) - f.onDialSuccess() } else { f.onDialFailed(proxy.Type(), err) } + c = &callback.FirstWriteCallBackConn{ + Conn: c, + Callback: func(err error) { + if err == nil { + f.onDialSuccess() + } else { + f.onDialFailed(proxy.Type(), err) + } + }, + } + return c, err } diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 48bd4994..9a010cf9 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -10,6 +10,7 @@ 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" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" @@ -83,17 +84,24 @@ func jumpHash(key uint64, buckets int32) int32 { // DialContext implements C.ProxyAdapter func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (c C.Conn, err error) { proxy := lb.Unwrap(metadata, true) - - defer func() { - if err == nil { - c.AppendToChains(lb) - lb.onDialSuccess() - } else { - lb.onDialFailed(proxy.Type(), err) - } - }() - c, err = proxy.DialContext(ctx, metadata, lb.Base.DialOptions(opts...)...) + + if err == nil { + c.AppendToChains(lb) + } else { + lb.onDialFailed(proxy.Type(), err) + } + + c = &callback.FirstWriteCallBackConn{ + Conn: c, + Callback: func(err error) { + if err == nil { + lb.onDialSuccess() + } else { + lb.onDialFailed(proxy.Type(), err) + } + }, + } return } diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 27cef9c6..31eaf4a4 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -6,6 +6,7 @@ import ( "time" "github.com/Dreamacro/clash/adapter/outbound" + "github.com/Dreamacro/clash/common/callback" "github.com/Dreamacro/clash/common/singledo" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" @@ -38,10 +39,20 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts .. c, err = proxy.DialContext(ctx, metadata, u.Base.DialOptions(opts...)...) if err == nil { c.AppendToChains(u) - u.onDialSuccess() } else { u.onDialFailed(proxy.Type(), err) } + + c = &callback.FirstWriteCallBackConn{ + Conn: c, + Callback: func(err error) { + if err == nil { + u.onDialSuccess() + } else { + u.onDialFailed(proxy.Type(), err) + } + }, + } return c, err } diff --git a/common/callback/callback.go b/common/callback/callback.go new file mode 100644 index 00000000..a0f1e717 --- /dev/null +++ b/common/callback/callback.go @@ -0,0 +1,25 @@ +package callback + +import ( + C "github.com/Dreamacro/clash/constant" +) + +type FirstWriteCallBackConn struct { + C.Conn + Callback func(error) + written bool +} + +func (c *FirstWriteCallBackConn) Write(b []byte) (n int, err error) { + defer func() { + if !c.written { + c.written = true + c.Callback(err) + } + }() + return c.Conn.Write(b) +} + +func (c *FirstWriteCallBackConn) Upstream() any { + return c.Conn +} diff --git a/common/net/bufconn.go b/common/net/bufconn.go index ba0ca026..54326cf9 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -12,13 +12,14 @@ var _ ExtendedConn = (*BufferedConn)(nil) type BufferedConn struct { r *bufio.Reader ExtendedConn + peeked bool } func NewBufferedConn(c net.Conn) *BufferedConn { if bc, ok := c.(*BufferedConn); ok { return bc } - return &BufferedConn{bufio.NewReader(c), NewExtendedConn(c)} + return &BufferedConn{bufio.NewReader(c), NewExtendedConn(c), false} } // Reader returns the internal bufio.Reader. @@ -26,11 +27,20 @@ func (c *BufferedConn) Reader() *bufio.Reader { return c.r } +func (c *BufferedConn) Peeked() bool { + return c.peeked +} + // Peek returns the next n bytes without advancing the reader. func (c *BufferedConn) Peek(n int) ([]byte, error) { + c.peeked = true return c.r.Peek(n) } +func (c *BufferedConn) Discard(n int) (discarded int, err error) { + return c.r.Discard(n) +} + func (c *BufferedConn) Read(p []byte) (int, error) { return c.r.Read(p) } diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index f4511b97..97d448ce 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -36,12 +36,7 @@ type SnifferDispatcher struct { parsePureIp bool } -func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) { - bufConn, ok := conn.(*N.BufferedConn) - if !ok { - return - } - +func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) { if (metadata.Host == "" && sd.parsePureIp) || sd.forceDomain.Search(metadata.Host) != nil || (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) { port, err := strconv.ParseUint(metadata.DstPort, 10, 16) if err != nil { @@ -74,7 +69,7 @@ func (sd *SnifferDispatcher) TCPSniff(conn net.Conn, metadata *C.Metadata) { } sd.rwMux.RUnlock() - if host, err := sd.sniffDomain(bufConn, metadata); err != nil { + 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) return diff --git a/constant/context.go b/constant/context.go index e641ed14..da1e4155 100644 --- a/constant/context.go +++ b/constant/context.go @@ -3,6 +3,8 @@ package constant import ( "net" + N "github.com/Dreamacro/clash/common/net" + "github.com/gofrs/uuid" ) @@ -13,7 +15,7 @@ type PlainContext interface { type ConnContext interface { PlainContext Metadata() *Metadata - Conn() net.Conn + Conn() *N.BufferedConn } type PacketConnContext interface { diff --git a/context/conn.go b/context/conn.go index 08bbe3c7..b695ac4d 100644 --- a/context/conn.go +++ b/context/conn.go @@ -12,7 +12,7 @@ import ( type ConnContext struct { id uuid.UUID metadata *C.Metadata - conn net.Conn + conn *N.BufferedConn } func NewConnContext(conn net.Conn, metadata *C.Metadata) *ConnContext { @@ -36,6 +36,6 @@ func (c *ConnContext) Metadata() *C.Metadata { } // Conn implement C.ConnContext Conn -func (c *ConnContext) Conn() net.Conn { +func (c *ConnContext) Conn() *N.BufferedConn { return c.conn } diff --git a/transport/vless/conn.go b/transport/vless/conn.go index aceda463..e063d465 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -7,7 +7,6 @@ import ( "io" "net" "sync" - "time" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" @@ -208,12 +207,12 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { } } - go func() { - select { - case <-c.handshake: - case <-time.After(200 * time.Millisecond): - c.sendRequest(nil) - } - }() + //go func() { + // select { + // case <-c.handshake: + // case <-time.After(200 * time.Millisecond): + // c.sendRequest(nil) + // } + //}() return c, nil } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 695f2945..b9d0e594 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -366,8 +366,20 @@ func handleTCPConn(connCtx C.ConnContext) { return } + conn := connCtx.Conn() if sniffer.Dispatcher.Enable() && sniffingEnable { - sniffer.Dispatcher.TCPSniff(connCtx.Conn(), metadata) + sniffer.Dispatcher.TCPSniff(conn, metadata) + } + + peekMutex := sync.Mutex{} + if !conn.Peeked() { + peekMutex.Lock() + go func() { + defer peekMutex.Unlock() + _ = conn.SetReadDeadline(time.Now().Add(200 * time.Millisecond)) + _, _ = conn.Peek(1) + _ = conn.SetReadDeadline(time.Time{}) + }() } proxy, rule, err := resolveMetadata(connCtx, metadata) @@ -387,10 +399,26 @@ func handleTCPConn(connCtx C.ConnContext) { } } + var peekBytes []byte + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout) defer cancel() remoteConn, err := retry(ctx, func(ctx context.Context) (C.Conn, error) { - return proxy.DialContext(ctx, dialMetadata) + remoteConn, err := proxy.DialContext(ctx, dialMetadata) + if err != nil { + return nil, err + } + peekMutex.Lock() + defer peekMutex.Unlock() + peekBytes, _ = conn.Peek(conn.Buffered()) + _, err = remoteConn.Write(peekBytes) + if err != nil { + return nil, err + } + if peekLen := len(peekBytes); peekLen > 0 { + _, _ = conn.Discard(peekLen) + } + return remoteConn, err }, func(err error) { if rule == nil { log.Warnln( From 7d524668e02d2ed8d9c4c876ce3b906b055c62e0 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 24 Feb 2023 13:53:44 +0800 Subject: [PATCH 014/530] chore: support TFO for outbounds --- adapter/outbound/base.go | 5 ++ 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 | 6 +- component/dialer/options.go | 7 ++ component/dialer/tfo.go | 119 +++++++++++++++++++++++++++++++ 12 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 component/dialer/tfo.go diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 24de7d94..d51655d8 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -140,10 +140,15 @@ func (b *Base) DialOptions(opts ...dialer.Option) []dialer.Option { default: } + if b.tfo { + opts = append(opts, dialer.WithTFO(true)) + } + return opts } type BasicOption struct { + TFO bool `proxy:"tfo,omitempty" group:"tfo,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"` diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 720dc3e1..6a668ebb 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -170,6 +170,7 @@ func NewHttp(option HttpOption) (*Http, error) { name: option.Name, addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.Http, + tfo: option.TFO, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 2ac1f234..6e6a8d0a 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -252,6 +252,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { addr: addr, tp: C.Shadowsocks, udp: option.UDP, + tfo: option.TFO, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index e84de879..135e7132 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -163,6 +163,7 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { addr: addr, tp: C.ShadowsocksR, udp: option.UDP, + tfo: option.TFO, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index 1331b526..d6f1efee 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -167,6 +167,7 @@ func NewSnell(option SnellOption) (*Snell, error) { addr: addr, tp: C.Snell, udp: option.UDP, + tfo: option.TFO, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index d40a6bff..cdb89cc2 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -182,6 +182,7 @@ func NewSocks5(option Socks5Option) (*Socks5, error) { addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), tp: C.Socks5, udp: option.UDP, + tfo: option.TFO, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 2a8cfe47..beedd614 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -250,6 +250,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { addr: addr, tp: C.Trojan, udp: option.UDP, + tfo: option.TFO, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index e46e245d..eef05687 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -510,6 +510,7 @@ func NewVless(option VlessOption) (*Vless, error) { tp: C.Vless, udp: option.UDP, xudp: option.XUDP, + tfo: option.TFO, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index e8220767..2ae72069 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -387,6 +387,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { tp: C.Vmess, udp: option.UDP, xudp: option.XUDP, + tfo: option.TFO, iface: option.Interface, rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 39e47bde..9ac9d719 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -118,7 +118,11 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po return nil, ErrorDisableIPv6 } - return dialer.DialContext(ctx, network, net.JoinHostPort(destination.String(), port)) + address := net.JoinHostPort(destination.String(), port) + if opt.tfo { + return dialTFO(ctx, *dialer, network, address) + } + return dialer.DialContext(ctx, network, address) } func singleDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { diff --git a/component/dialer/options.go b/component/dialer/options.go index 27adc845..1c4e7bfc 100644 --- a/component/dialer/options.go +++ b/component/dialer/options.go @@ -18,6 +18,7 @@ type option struct { routingMark int network int prefer int + tfo bool resolver resolver.Resolver } @@ -69,6 +70,12 @@ func WithOnlySingleStack(isIPv4 bool) Option { } } +func WithTFO(tfo bool) Option { + return func(opt *option) { + opt.tfo = tfo + } +} + func WithOption(o option) Option { return func(opt *option) { *opt = o diff --git a/component/dialer/tfo.go b/component/dialer/tfo.go new file mode 100644 index 00000000..2db2e91e --- /dev/null +++ b/component/dialer/tfo.go @@ -0,0 +1,119 @@ +package dialer + +import ( + "context" + "github.com/sagernet/tfo-go" + "io" + "net" + "time" +) + +type tfoConn struct { + net.Conn + closed bool + dialed chan bool + cancel context.CancelFunc + ctx context.Context + dialFn func(ctx context.Context, earlyData []byte) (net.Conn, error) +} + +func (c *tfoConn) Dial(earlyData []byte) (err error) { + c.Conn, err = c.dialFn(c.ctx, earlyData) + if err != nil { + return + } + c.dialed <- true + return err +} + +func (c *tfoConn) Read(b []byte) (n int, err error) { + if c.closed { + return 0, io.ErrClosedPipe + } + if c.Conn == nil { + select { + case <-c.ctx.Done(): + return 0, io.ErrUnexpectedEOF + case <-c.dialed: + } + } + return c.Conn.Read(b) +} + +func (c *tfoConn) Write(b []byte) (n int, err error) { + if c.closed { + return 0, io.ErrClosedPipe + } + if c.Conn == nil { + if err := c.Dial(b); err != nil { + return 0, err + } + return len(b), nil + } + + return c.Conn.Write(b) +} + +func (c *tfoConn) Close() error { + c.closed = true + c.cancel() + if c.Conn == nil { + return nil + } + return c.Conn.Close() +} + +func (c *tfoConn) LocalAddr() net.Addr { + if c.Conn == nil { + return nil + } + return c.Conn.LocalAddr() +} + +func (c *tfoConn) RemoteAddr() net.Addr { + if c.Conn == nil { + return nil + } + return c.Conn.RemoteAddr() +} + +func (c *tfoConn) SetDeadline(t time.Time) error { + if err := c.SetReadDeadline(t); err != nil { + return err + } + return c.SetWriteDeadline(t) +} + +func (c *tfoConn) SetReadDeadline(t time.Time) error { + if c.Conn == nil { + return nil + } + return c.Conn.SetReadDeadline(t) +} + +func (c *tfoConn) SetWriteDeadline(t time.Time) error { + if c.Conn == nil { + return nil + } + return c.Conn.SetWriteDeadline(t) +} + +func (c *tfoConn) Upstream() any { + if c.Conn == nil { // ensure return a nil interface not an interface with nil value + return nil + } + return c.Conn +} + +func dialTFO(ctx context.Context, netDialer net.Dialer, network, address string) (net.Conn, error) { + ctx, cancel := context.WithCancel(ctx) + dialer := tfo.Dialer{Dialer: netDialer, DisableTFO: false} + return &tfoConn{ + dialed: make(chan bool, 1), + cancel: cancel, + ctx: ctx, + dialFn: func(ctx context.Context, earlyData []byte) (net.Conn, error) { + return dialer.DialContext(ctx, network, address, earlyData) + }, + }, nil +} From 8f0c61ed14b8019fe851edda3e76c63647249b66 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 24 Feb 2023 14:02:20 +0800 Subject: [PATCH 015/530] fix: tuic missing routing mark --- adapter/outbound/tuic.go | 1 + 1 file changed, 1 insertion(+) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 5b7bde6e..b6335fa8 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -216,6 +216,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { udp: true, tfo: option.FastOpen, iface: option.Interface, + rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, } From 880664c6ab9df410df0ceae85ea221484c175b8c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 24 Feb 2023 14:19:50 +0800 Subject: [PATCH 016/530] fix: tunnel's inboundTFO missing --- hub/executor/executor.go | 3 ++- listener/tunnel/tcp.go | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 57a9ffe8..916f17c7 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -148,7 +148,6 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList dialer.DefaultInterface.Store(general.Interface) } - inbound.SetTfo(general.InboundTfo) allowLan := general.AllowLan listener.SetAllowLan(allowLan) @@ -341,6 +340,8 @@ func updateGeneral(general *config.General) { log.Infoln("Use tcp concurrent") } + inbound.SetTfo(general.InboundTfo) + adapter.UnifiedDelay.Store(general.UnifiedDelay) // Avoid reload configuration clean the value, causing traffic loops if listener.GetTunConf().Enable && listener.GetTunConf().AutoDetectInterface { diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index bf278c1c..c1d896ad 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -41,7 +41,7 @@ func (l *Listener) handleTCP(conn net.Conn, in chan<- C.ConnContext, additions . } func New(addr, target, proxy string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { - l, err := net.Listen("tcp", addr) + l, err := inbound.Listen("tcp", addr) if err != nil { return nil, err } From 5bfad04b4121523d8d1ad1927591a10393f152f4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 24 Feb 2023 14:58:01 +0800 Subject: [PATCH 017/530] fix: checkTunName mistake --- listener/sing_tun/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 63d475cf..3abef12d 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -77,7 +77,7 @@ func checkTunName(tunName string) (ok bool) { if len(tunName) <= 4 { return false } - if tunName[:4] == "utun" { + if tunName[:4] != "utun" { return false } if _, parseErr := strconv.ParseInt(tunName[4:], 10, 16); parseErr != nil { From 81722610d50904a4aa88eaa8f3f12ee97bcbc5ac Mon Sep 17 00:00:00 2001 From: Hellojack <106379370+H1JK@users.noreply.github.com> Date: Sat, 25 Feb 2023 13:12:19 +0800 Subject: [PATCH 018/530] feat: Support VLESS XTLS Vision (#406) --- adapter/outbound/vless.go | 8 +- common/buf/sing.go | 6 + transport/vless/conn.go | 352 +++++++++++++++++++++++++++++++++----- transport/vless/filter.go | 79 +++++++++ transport/vless/vision.go | 69 ++++++++ transport/vless/vless.go | 1 + transport/vless/xtls.go | 5 + 7 files changed, 477 insertions(+), 43 deletions(-) create mode 100644 transport/vless/filter.go create mode 100644 transport/vless/vision.go diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index eef05687..010af23c 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -171,7 +171,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) { host, _, _ := net.SplitHostPort(v.addr) - if v.isXTLSEnabled() && !isH2 { + if v.isLegacyXTLSEnabled() && !isH2 { xtlsOpts := vless.XTLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, @@ -206,8 +206,8 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) return conn, nil } -func (v *Vless) isXTLSEnabled() bool { - return v.client.Addons != nil +func (v *Vless) isLegacyXTLSEnabled() bool { + return v.client.Addons != nil && v.client.Addons.Flow != vless.XRV } // DialContext implements C.ProxyAdapter @@ -479,7 +479,7 @@ func NewVless(option VlessOption) (*Vless, error) { if option.Network != "ws" && len(option.Flow) >= 16 { option.Flow = option.Flow[:16] switch option.Flow { - case vless.XRO, vless.XRD, vless.XRS: + case vless.XRO, vless.XRD, vless.XRS, vless.XRV: addons = &vless.Addons{ Flow: option.Flow, } diff --git a/common/buf/sing.go b/common/buf/sing.go index b5e015f5..f86b5755 100644 --- a/common/buf/sing.go +++ b/common/buf/sing.go @@ -5,9 +5,15 @@ import ( "github.com/sagernet/sing/common/buf" ) +const BufferSize = buf.BufferSize + type Buffer = buf.Buffer +var New = buf.New +var StackNew = buf.StackNew var StackNewSize = buf.StackNewSize +var With = buf.With + var KeepAlive = common.KeepAlive //go:norace diff --git a/transport/vless/conn.go b/transport/vless/conn.go index e063d465..eae8868e 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -1,23 +1,33 @@ package vless import ( + "bytes" + "crypto/subtle" + gotls "crypto/tls" "encoding/binary" "errors" "fmt" "io" "net" + "reflect" "sync" + "unsafe" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" + tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/log" "github.com/gofrs/uuid" + utls "github.com/sagernet/utls" xtls "github.com/xtls/go" "google.golang.org/protobuf/proto" ) type Conn struct { - N.ExtendedConn + N.ExtendedWriter + N.ExtendedReader + net.Conn dst *DstAddr id *uuid.UUID addons *Addons @@ -26,30 +36,143 @@ type Conn struct { handshake chan struct{} handshakeMutex sync.Mutex err error + + tlsConn net.Conn + input *bytes.Reader + rawInput *bytes.Buffer + + packetsToFilter int + isTLS bool + isTLS12orAbove bool + enableXTLS bool + cipher uint16 + remainingServerHello uint16 + readRemainingContent int + readRemainingPadding int + readProcess bool + readFilterUUID bool + readLastCommand byte + writeFilterApplicationData bool + writeDirect bool } func (vc *Conn) Read(b []byte) (int, error) { if vc.received { - return vc.ExtendedConn.Read(b) + if vc.readProcess { + buffer := buf.With(b) + err := vc.ReadBuffer(buffer) + return buffer.Len(), err + } + return vc.ExtendedReader.Read(b) } if err := vc.recvResponse(); err != nil { return 0, err } vc.received = true - return vc.ExtendedConn.Read(b) + return vc.Read(b) } func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { if vc.received { - return vc.ExtendedConn.ReadBuffer(buffer) + toRead := buffer.FreeBytes() + if vc.readRemainingContent > 0 { + if vc.readRemainingContent < buffer.FreeLen() { + toRead = toRead[:vc.readRemainingContent] + } + n, err := vc.ExtendedReader.Read(toRead) + buffer.Truncate(n) + vc.readRemainingContent -= n + vc.FilterTLS(toRead) + return err + } + if vc.readRemainingPadding > 0 { + _, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding)) + if err != nil { + return err + } + vc.readRemainingPadding = 0 + } + if vc.readProcess { + switch vc.readLastCommand { + case commandPaddingContinue: + //if vc.isTLS || vc.packetsToFilter > 0 { + headerUUIDLen := 0 + if vc.readFilterUUID { + headerUUIDLen = uuid.Size + } + var header []byte + if need := headerUUIDLen + paddingHeaderLen; buffer.FreeLen() < need { + header = make([]byte, need) + } else { + header = buffer.FreeBytes()[:need] + } + _, err := io.ReadFull(vc.ExtendedReader, header) + if err != nil { + return err + } + pos := 0 + if vc.readFilterUUID { + vc.readFilterUUID = false + pos = uuid.Size + if subtle.ConstantTimeCompare(vc.id.Bytes(), header[:uuid.Size]) != 1 { + err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", + uuid.FromBytesOrNil(header[:uuid.Size]).String()) + log.Errorln(err.Error()) + return err + } + } + vc.readLastCommand = header[pos] + vc.readRemainingContent = int(binary.BigEndian.Uint16(header[pos+1:])) + vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[pos+3:])) + log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d", + vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding) + return vc.ReadBuffer(buffer) + //} + case commandPaddingEnd: + vc.readProcess = false + return vc.ReadBuffer(buffer) + case commandPaddingDirect: + if vc.input != nil { + _, err := buffer.ReadFrom(vc.input) + if err != nil { + return err + } + if vc.input.Len() == 0 { + vc.input = nil + } + if buffer.IsFull() { + return nil + } + } + if vc.rawInput != nil { + _, err := buffer.ReadFrom(vc.rawInput) + if err != nil { + return err + } + if vc.rawInput.Len() == 0 { + vc.rawInput = nil + } + } + if vc.input == nil && vc.rawInput == nil { + vc.readProcess = false + vc.ExtendedReader = N.NewExtendedReader(vc.Conn) + log.Debugln("XTLS Vision direct read start") + } + default: + err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand) + log.Debugln(err.Error()) + return err + } + } + return vc.ExtendedReader.ReadBuffer(buffer) } if err := vc.recvResponse(); err != nil { return err } vc.received = true - return vc.ExtendedConn.ReadBuffer(buffer) + return vc.ReadBuffer(buffer) } func (vc *Conn) Write(p []byte) (int, error) { @@ -66,7 +189,19 @@ func (vc *Conn) Write(p []byte) (int, error) { return 0, vc.err } } - return vc.ExtendedConn.Write(p) + if vc.writeFilterApplicationData { + _buffer := buf.StackNew() + defer buf.KeepAlive(_buffer) + buffer := buf.Dup(_buffer) + defer buffer.Release() + buffer.Write(p) + err := vc.WriteBuffer(buffer) + if err != nil { + return 0, err + } + return len(p), nil + } + return vc.ExtendedWriter.Write(p) } func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { @@ -80,7 +215,57 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { return vc.err } } - return vc.ExtendedConn.WriteBuffer(buffer) + if vc.writeFilterApplicationData && vc.isTLS { + buffer2 := ReshapeBuffer(buffer) + defer buffer2.Release() + vc.FilterTLS(buffer.Bytes()) + command := commandPaddingContinue + if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { + command = commandPaddingEnd + if vc.enableXTLS { + command = commandPaddingDirect + vc.writeDirect = true + } + vc.writeFilterApplicationData = false + } + ApplyPadding(buffer, command, nil) + err := vc.ExtendedWriter.WriteBuffer(buffer) + if err != nil { + return err + } + if vc.writeDirect { + vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) + log.Debugln("XTLS Vision direct write start") + //time.Sleep(10 * time.Millisecond) + } + if buffer2 != nil { + if vc.writeDirect { + return vc.ExtendedWriter.WriteBuffer(buffer2) + } + vc.FilterTLS(buffer2.Bytes()) + command = commandPaddingContinue + if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { + command = commandPaddingEnd + if vc.enableXTLS { + command = commandPaddingDirect + vc.writeDirect = true + } + vc.writeFilterApplicationData = false + } + ApplyPadding(buffer2, command, nil) + err = vc.ExtendedWriter.WriteBuffer(buffer2) + if vc.writeDirect { + vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) + log.Debugln("XTLS Vision direct write start") + //time.Sleep(10 * time.Millisecond) + } + } + return err + } + /*if vc.writeDirect { + log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len()) + }*/ + return vc.ExtendedWriter.WriteBuffer(buffer) } func (vc *Conn) sendRequest(p []byte) bool { @@ -96,9 +281,6 @@ func (vc *Conn) sendRequest(p []byte) bool { } defer close(vc.handshake) - requestLen := 1 // protocol version - requestLen += 16 // UUID - requestLen += 1 // addons length var addonsBytes []byte if vc.addons != nil { addonsBytes, vc.err = proto.Marshal(vc.addons) @@ -106,19 +288,32 @@ func (vc *Conn) sendRequest(p []byte) bool { return true } } - requestLen += len(addonsBytes) - requestLen += 1 // command - if !vc.dst.Mux { - requestLen += 2 // port - requestLen += 1 // addr type - requestLen += len(vc.dst.Addr) - } - requestLen += len(p) + isVision := vc.IsXTLSVisionEnabled() - _buffer := buf.StackNewSize(requestLen) - defer buf.KeepAlive(_buffer) - buffer := buf.Dup(_buffer) - defer buffer.Release() + var buffer *buf.Buffer + if isVision { + _buffer := buf.StackNew() + defer buf.KeepAlive(_buffer) + buffer = buf.Dup(_buffer) + defer buffer.Release() + } else { + requestLen := 1 // protocol version + requestLen += 16 // UUID + requestLen += 1 // addons length + requestLen += len(addonsBytes) + requestLen += 1 // command + if !vc.dst.Mux { + requestLen += 2 // port + requestLen += 1 // addr type + requestLen += len(vc.dst.Addr) + } + requestLen += len(p) + + _buffer := buf.StackNewSize(requestLen) + defer buf.KeepAlive(_buffer) + buffer = buf.Dup(_buffer) + defer buffer.Release() + } buf.Must( buffer.WriteByte(Version), // protocol version @@ -143,15 +338,51 @@ func (vc *Conn) sendRequest(p []byte) bool { ) } - buf.Must(buf.Error(buffer.Write(p))) + if isVision && !vc.dst.UDP && !vc.dst.Mux { + if len(p) == 0 { + vc.packetsToFilter = 0 + vc.writeFilterApplicationData = false + WriteWithPadding(buffer, nil, commandPaddingEnd, vc.id) + } else { + vc.FilterTLS(p) + if vc.isTLS { + WriteWithPadding(buffer, p, commandPaddingContinue, vc.id) + } else { + buf.Must(buf.Error(buffer.Write(p))) + vc.readProcess = false + vc.writeFilterApplicationData = false + vc.packetsToFilter = 0 + } + } + } else { + buf.Must(buf.Error(buffer.Write(p))) + } - _, vc.err = vc.ExtendedConn.Write(buffer.Bytes()) + _, vc.err = vc.ExtendedWriter.Write(buffer.Bytes()) + if vc.err != nil { + return true + } + if isVision { + switch underlying := vc.tlsConn.(type) { + case *gotls.Conn: + if underlying.ConnectionState().Version != gotls.VersionTLS13 { + vc.err = ErrNotTLS13 + } + case *utls.UConn: + if underlying.ConnectionState().Version != utls.VersionTLS13 { + vc.err = ErrNotTLS13 + } + default: + vc.err = fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, vc.addons.Flow) + } + vc.tlsConn = nil + } return true } func (vc *Conn) recvResponse() error { var buf [1]byte - _, vc.err = io.ReadFull(vc.ExtendedConn, buf[:]) + _, vc.err = io.ReadFull(vc.ExtendedReader, buf[:]) if vc.err != nil { return vc.err } @@ -160,30 +391,46 @@ func (vc *Conn) recvResponse() error { return errors.New("unexpected response version") } - _, vc.err = io.ReadFull(vc.ExtendedConn, buf[:]) + _, vc.err = io.ReadFull(vc.ExtendedReader, buf[:]) if vc.err != nil { return vc.err } length := int64(buf[0]) if length != 0 { // addon data length > 0 - io.CopyN(io.Discard, vc.ExtendedConn, length) // just discard + io.CopyN(io.Discard, vc.ExtendedReader, length) // just discard } return nil } +func (vc *Conn) FrontHeadroom() int { + if vc.IsXTLSVisionEnabled() { + return paddingHeaderLen + } + return 0 +} + func (vc *Conn) Upstream() any { - return vc.ExtendedConn + if vc.tlsConn == nil { + return vc.Conn + } + return vc.tlsConn +} + +func (vc *Conn) IsXTLSVisionEnabled() bool { + return vc.addons != nil && vc.addons.Flow == XRV } // newConn return a Conn instance func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { c := &Conn{ - ExtendedConn: N.NewExtendedConn(conn), - id: client.uuid, - dst: dst, - handshake: make(chan struct{}), + ExtendedReader: N.NewExtendedReader(conn), + ExtendedWriter: N.NewExtendedWriter(conn), + Conn: conn, + id: client.uuid, + dst: dst, + handshake: make(chan struct{}), } if !dst.UDP && client.Addons != nil { @@ -204,15 +451,42 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { } else { return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow) } + case XRV: + c.packetsToFilter = 6 + c.readProcess = true + c.readFilterUUID = true + c.writeFilterApplicationData = true + c.addons = client.Addons + var t reflect.Type + var p uintptr + switch underlying := conn.(type) { + case *gotls.Conn: + c.Conn = underlying.NetConn() + c.tlsConn = underlying + t = reflect.TypeOf(underlying).Elem() + p = uintptr(unsafe.Pointer(underlying)) + case *utls.UConn: + c.Conn = underlying.NetConn() + c.tlsConn = underlying + t = reflect.TypeOf(underlying.Conn).Elem() + p = uintptr(unsafe.Pointer(underlying.Conn)) + case *tlsC.UConn: + c.Conn = underlying.NetConn() + c.tlsConn = underlying.UConn + t = reflect.TypeOf(underlying.Conn).Elem() + p = uintptr(unsafe.Pointer(underlying.Conn)) + default: + return nil, fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, client.Addons.Flow) + } + i, _ := t.FieldByName("input") + r, _ := t.FieldByName("rawInput") + c.input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset)) + c.rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset)) + if _, ok := c.Conn.(*net.TCPConn); !ok { + log.Debugln("XTLS underlying conn is not *net.TCPConn, got %s", reflect.TypeOf(conn).Name()) + } } } - //go func() { - // select { - // case <-c.handshake: - // case <-time.After(200 * time.Millisecond): - // c.sendRequest(nil) - // } - //}() return c, nil } diff --git a/transport/vless/filter.go b/transport/vless/filter.go new file mode 100644 index 00000000..15d595bc --- /dev/null +++ b/transport/vless/filter.go @@ -0,0 +1,79 @@ +package vless + +import ( + "bytes" + "encoding/binary" + + log "github.com/sirupsen/logrus" +) + +var ( + tls13SupportedVersions = []byte{0x00, 0x2b, 0x00, 0x02, 0x03, 0x04} + tlsClientHandshakeStart = []byte{0x16, 0x03} + tlsServerHandshakeStart = []byte{0x16, 0x03, 0x03} + tlsApplicationDataStart = []byte{0x17, 0x03, 0x03} + + tls13CipherSuiteMap = map[uint16]string{ + 0x1301: "TLS_AES_128_GCM_SHA256", + 0x1302: "TLS_AES_256_GCM_SHA384", + 0x1303: "TLS_CHACHA20_POLY1305_SHA256", + 0x1304: "TLS_AES_128_CCM_SHA256", + 0x1305: "TLS_AES_128_CCM_8_SHA256", + } +) + +const ( + tlsHandshakeTypeClientHello byte = 0x01 + tlsHandshakeTypeServerHello byte = 0x02 +) + +func (vc *Conn) FilterTLS(p []byte) (index int) { + if vc.packetsToFilter <= 0 { + return 0 + } + lenP := len(p) + vc.packetsToFilter -= 1 + if index = bytes.Index(p, tlsServerHandshakeStart); index != -1 { + if lenP >= index+5 && p[index+5] == tlsHandshakeTypeServerHello { + vc.remainingServerHello = binary.BigEndian.Uint16(p[index+3:]) + 5 + vc.isTLS = true + vc.isTLS12orAbove = true + if lenP-index >= 79 && vc.remainingServerHello >= 79 { + sessionIDLen := int(p[index+43]) + vc.cipher = binary.BigEndian.Uint16(p[index+43+sessionIDLen+1:]) + } + } + } else if index = bytes.Index(p, tlsClientHandshakeStart); index != -1 { + if lenP >= index+5 && p[index+5] == tlsHandshakeTypeClientHello { + vc.isTLS = true + } + } + + if vc.remainingServerHello > 0 { + end := vc.remainingServerHello + vc.remainingServerHello -= end + if end > uint16(lenP) { + end = uint16(lenP) + } + if bytes.Contains(p[index:end], tls13SupportedVersions) { + // TLS 1.3 Client Hello + cs, ok := tls13CipherSuiteMap[vc.cipher] + if ok && cs != "TLS_AES_128_CCM_8_SHA256" { + vc.enableXTLS = true + } + log.Debugln("XTLS Vision found TLS 1.3, packetLength=", lenP, ", CipherSuite=", cs) + vc.packetsToFilter = 0 + return + } else if vc.remainingServerHello < 0 { + log.Debugln("XTLS Vision found TLS 1.2, packetLength=", lenP) + vc.packetsToFilter = 0 + return + } + log.Debugln("XTLS Vision found inconclusive server hello, packetLength=", lenP, + ", remainingServerHelloBytes=", vc.remainingServerHello) + } + if vc.packetsToFilter <= 0 { + log.Debugln("XTLS Vision stop filtering") + } + return +} diff --git a/transport/vless/vision.go b/transport/vless/vision.go new file mode 100644 index 00000000..f87a6870 --- /dev/null +++ b/transport/vless/vision.go @@ -0,0 +1,69 @@ +package vless + +import ( + "bytes" + "encoding/binary" + "math/rand" + + "github.com/Dreamacro/clash/common/buf" + "github.com/Dreamacro/clash/log" + + "github.com/gofrs/uuid" +) + +const ( + paddingHeaderLen = 1 + 2 + 2 // =5 + + commandPaddingContinue byte = 0x00 + commandPaddingEnd byte = 0x01 + commandPaddingDirect byte = 0x02 +) + +func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID) { + contentLen := int32(len(p)) + var paddingLen int32 + if contentLen < 900 { + paddingLen = rand.Int31n(500) + 900 - contentLen + } + + if userUUID != nil { // unnecessary, but keep the same with Xray + buffer.Write(userUUID.Bytes()) + } + buffer.WriteByte(command) + binary.BigEndian.PutUint16(buffer.Extend(2), uint16(contentLen)) + binary.BigEndian.PutUint16(buffer.Extend(2), uint16(paddingLen)) + buffer.Write(p) + buffer.Extend(int(paddingLen)) + log.Debugln("XTLS Vision write padding1: command=%v, payloadLen=%v, paddingLen=%v", command, contentLen, paddingLen) +} + +func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID) { + contentLen := int32(buffer.Len()) + var paddingLen int32 + if contentLen < 900 { + paddingLen = rand.Int31n(500) + 900 - contentLen + } + + binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(paddingLen)) + binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(contentLen)) + buffer.ExtendHeader(1)[0] = command + if userUUID != nil { // unnecessary, but keep the same with Xray + copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes()) + } + buffer.Extend(int(paddingLen)) + log.Debugln("XTLS Vision write padding2: command=%d, payloadLen=%d, paddingLen=%d", command, contentLen, paddingLen) +} + +func ReshapeBuffer(buffer *buf.Buffer) *buf.Buffer { + if buffer.Len() <= buf.BufferSize-paddingHeaderLen { + return nil + } + cutAt := bytes.LastIndex(buffer.Bytes(), tlsApplicationDataStart) + if cutAt == -1 { + cutAt = buf.BufferSize / 2 + } + buffer2 := buf.New() + buffer2.Write(buffer.From(cutAt)) + buffer.Truncate(cutAt) + return buffer2 +} diff --git a/transport/vless/vless.go b/transport/vless/vless.go index 4b101703..6989374c 100644 --- a/transport/vless/vless.go +++ b/transport/vless/vless.go @@ -12,6 +12,7 @@ const ( XRO = "xtls-rprx-origin" XRD = "xtls-rprx-direct" XRS = "xtls-rprx-splice" + XRV = "xtls-rprx-vision" Version byte = 0 // protocol version. preview version is 0 ) diff --git a/transport/vless/xtls.go b/transport/vless/xtls.go index a1aea44f..3a319568 100644 --- a/transport/vless/xtls.go +++ b/transport/vless/xtls.go @@ -2,6 +2,7 @@ package vless import ( "context" + "errors" "net" tlsC "github.com/Dreamacro/clash/component/tls" @@ -9,6 +10,10 @@ import ( xtls "github.com/xtls/go" ) +var ( + ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") +) + type XTLSConfig struct { Host string SkipCertVerify bool From bce3aeb2188dbac377af6f879f34825a81c9d0f8 Mon Sep 17 00:00:00 2001 From: Hellojack <106379370+H1JK@users.noreply.github.com> Date: Sat, 25 Feb 2023 15:00:21 +0800 Subject: [PATCH 019/530] fix: Vision disable filter for non-TLS connections --- transport/vless/conn.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index eae8868e..fd1767cf 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -340,15 +340,20 @@ func (vc *Conn) sendRequest(p []byte) bool { if isVision && !vc.dst.UDP && !vc.dst.Mux { if len(p) == 0 { - vc.packetsToFilter = 0 - vc.writeFilterApplicationData = false WriteWithPadding(buffer, nil, commandPaddingEnd, vc.id) + + // disable XTLS + vc.readProcess = false + vc.writeFilterApplicationData = false + vc.packetsToFilter = 0 } else { vc.FilterTLS(p) if vc.isTLS { WriteWithPadding(buffer, p, commandPaddingContinue, vc.id) } else { buf.Must(buf.Error(buffer.Write(p))) + + // disable XTLS vc.readProcess = false vc.writeFilterApplicationData = false vc.packetsToFilter = 0 From 22726c1de847642591b67e9a45ffa3a05af126eb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 25 Feb 2023 15:05:24 +0800 Subject: [PATCH 020/530] fix: add version of shadow-tls plugin in docs/config.yaml --- docs/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/config.yaml b/docs/config.yaml index 35e85ecc..e1fc5d2e 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -309,6 +309,7 @@ proxies: plugin-opts: host: "cloud.tencent.com" password: "shadow_tls_password" + version: 2 # support 1/2/3 # vmess # cipher支持 auto/aes-128-gcm/chacha20-poly1305/none From e6377eac9bbb9804b85672bc640b899143ec457a Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 25 Feb 2023 17:20:38 +0800 Subject: [PATCH 021/530] chore: adjust config.yaml. --- docs/config.yaml | 458 ++++++++++++++++++++++++----------------------- 1 file changed, 236 insertions(+), 222 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index e1fc5d2e..f6e9502e 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -7,22 +7,17 @@ mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口 # tproxy-port: 7893 allow-lan: true # 允许局域网连接 -bind-address: "*" # 绑定IP地址,仅作用于 allow-lan 为 true,'*'表示所有地址 +bind-address: "*" # 绑定 IP 地址,仅作用于 allow-lan 为 true,'*'表示所有地址 -# find-process-mode has 3 values: always, strict, off +# find-process-mode has 3 values:always, strict, off # - always, 开启,强制匹配所有进程 -# - strict, 默认,由clash判断是否开启 +# - strict, 默认,由 clash 判断是否开启 # - off, 不匹配进程,推荐在路由器上使用此模式 find-process-mode: strict -# global-client-fingerprint:全局TLS指纹,优先低于proxy内的 client-fingerprint -# accepts "chrome","firefox","safari","ios","random","none" options. -# Utls is currently support TLS transport in TCP/grpc/WS/HTTP for VLESS/Vmess and trojan. -global-client-fingerprint: chrome - mode: rule -#自定义 geox-url +#自定义 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" @@ -32,16 +27,25 @@ log-level: debug # 日志等级 silent/error/warning/info/debug ipv6: true # 开启 IPv6 总开关,关闭阻断所有 IPv6 链接和屏蔽 DNS 请求 AAAA 记录 +tls: + certificate: string # 证书 PEM 格式,或者 证书的路径 + private-key: string # 证书对应的私钥 PEM 格式,或者私钥路径 + external-controller: 0.0.0.0:9093 # RESTful API 监听地址 external-controller-tls: 0.0.0.0:9443 # RESTful API HTTPS 监听地址,需要配置 tls 部分配置文件 -# secret: "123456" # `Authorization: Bearer ${secret}` +# secret: "123456" # `Authorization:Bearer ${secret}` -# tcp-concurrent: true # TCP并发连接所有IP, 将使用最快握手的TCP -external-ui: /path/to/ui/folder # 配置WEB UI目录,使用http://{{external-controller}}/ui 访问 +# tcp-concurrent: true # TCP 并发连接所有 IP, 将使用最快握手的 TCP +external-ui: /path/to/ui/folder # 配置 WEB UI 目录,使用 http://{{external-controller}}/ui 访问 # interface-name: en0 # 设置出口网卡 -# routing-mark: 6666 # 配置 fwmark 仅用于Linux +# 全局 TLS 指纹,优先低于 proxy 内的 client-fingerprint +# 可选: "chrome","firefox","safari","ios","random","none" options. +# Utls is currently support TLS transport in TCP/grpc/WS/HTTP for VLESS/Vmess and trojan. +global-client-fingerprint: chrome + +# routing-mark:6666 # 配置 fwmark 仅用于 Linux experimental: # 类似于 /etc/hosts, 仅支持配置单个 IP @@ -50,6 +54,13 @@ hosts: # '.dev': 127.0.0.1 # 'alpha.clash.dev': '::1' +profile: + # 存储 select 选择记录 + store-selected: false + + # 持久化 fake-ip + store-fake-ip: true + # Tun 配置 tun: enable: false @@ -75,10 +86,10 @@ tun: #- 1000 # exclude_uid_range: # 排除路由的的用户范围 # - 1000-99999 - + # Android 用户和应用规则仅在 Android 下被支持 # 并且需要 auto_route - + # include_android_user: # 限制被路由的 Android 用户 # - 0 # - 10 @@ -105,15 +116,13 @@ sniffer: # 是否使用嗅探结果作为实际访问,默认 true # 全局配置,优先级低于 sniffer.sniff 实际配置 override-destination: false - sniff: - # TLS 默认如果不配置 ports 默认嗅探 443 + sniff: # TLS 默认如果不配置 ports 默认嗅探 443 TLS: # ports: [443, 8443] - + # 默认嗅探 80 - HTTP: - # 需要嗅探的端口 - + HTTP: # 需要嗅探的端口 + ports: [80, 8080-8880] # 可覆盖 sniffer.override-destination override-destination: true @@ -128,7 +137,7 @@ sniffer: - tls - http # 强制对此域名进行嗅探 - + # 仅对白名单中的端口进行嗅探,默认为 443,80 # 已废弃,若 sniffer.sniff 配置则此项无效 port-whitelist: @@ -136,27 +145,8 @@ sniffer: - "443" # - 8000-9999 -# shadowsocks,vmess 入口配置(传入流量将和socks,mixed等入口一样按照mode所指定的方式进行匹配处理) -# ss-config: ss://2022-blake3-aes-256-gcm:vlmpIPSyHH6f4S8WVPdRIHIlzmB+GIRfoH3aNJ/t9Gg=@:23456 -# vmess-config: vmess://1:9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68@:12345 -# tuic服务器入口(传入流量将和socks,mixed等入口一样按照mode所指定的方式进行匹配处理) -#tuic-server: -# enable: true -# listen: 127.0.0.1:10443 -# token: -# - TOKEN -# certificate: ./server.crt -# private-key: ./server.key -# congestion-controller: bbr -# max-idle-time: 15000 -# authentication-timeout: 1000 -# alpn: -# - h3 -# max-udp-relay-packet-size: 1500 - -tunnels: - # one line config +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 # full yaml config @@ -165,12 +155,6 @@ tunnels: target: target.com proxy: proxy -profile: - # 存储select选择记录 - store-selected: false - - # 持久化fake-ip - store-fake-ip: true # DNS配置 dns: @@ -178,7 +162,7 @@ dns: prefer-h3: true # 开启 DoH 支持 HTTP/3,将并发尝试 listen: 0.0.0.0:53 # 开启 DNS 服务器监听 # ipv6: false # false 将返回 AAAA 的空结果 - + # 用于解析 nameserver,fallback 以及其他DNS服务器配置的,DNS 服务域名 # 只能使用纯 IP 地址,可使用加密 DNS default-nameserver: @@ -187,16 +171,16 @@ dns: - tls://1.12.12.12:853 - tls://223.5.5.5:853 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 @@ -210,20 +194,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 @@ -238,14 +222,53 @@ dns: # - '+.google.com' # - '+.facebook.com' # - '+.youtube.com' - + # 配置查询域名使用的 DNS 服务器 - nameserver-policy: - # 'www.baidu.com': '114.114.114.114' + nameserver-policy: # 'www.baidu.com': '114.114.114.114' # '+.internal.crop.com': '10.0.0.1' - "geosite:cn": "https://doh.pub/dns-query" - "www.baidu.com": [https://doh.pub/dns-query,https://dns.alidns.com/dns-query] -proxies: + "geosite:cn": + - https://doh.pub/dns-query + - https://dns.alidns.com/dns-query + "www.baidu.com": [https://doh.pub/dns-query, https://dns.alidns.com/dns-query] + +proxies: # socks5 + - name: "socks" + type: socks5 + server: server + port: 443 + # username: username + # password: password + # tls: true + # fingerprint: xxxx + # skip-cert-verify: true + # udp: true + # ip-version: ipv6 + + # http + - name: "http" + type: http + server: server + port: 443 + # username: username + # password: password + # tls: true # https + # skip-cert-verify: true + # 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" + type: snell + server: server + port: 44046 + psk: yourpsk + # version: 2 + # obfs-opts: + # mode: http # or tls + # host: bing.com + # Shadowsocks # cipher支持: # aes-128-gcm aes-192-gcm aes-256-gcm @@ -268,6 +291,7 @@ proxies: # UDP 则为双栈解析,获取结果中的第一个 IPv4 # ipv6-prefer 同 ipv4-prefer # 现有协议都支持此参数,TCP 效果仅在开启 tcp-concurrent 生效 + - name: "ss2" type: ss server: server @@ -278,7 +302,7 @@ proxies: plugin-opts: mode: tls # or http # host: bing.com - + - name: "ss3" type: ss server: server @@ -288,17 +312,17 @@ proxies: plugin: v2ray-plugin plugin-opts: mode: websocket # no QUIC now - # tls: true # wss - # 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取 - # 配置指纹将实现 SSL Pining 效果 - # fingerprint: xxxx - # skip-cert-verify: true - # host: bing.com - # path: "/" - # mux: true - # headers: - # custom: value - + # tls: true # wss + # 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取 + # 配置指纹将实现 SSL Pining 效果 + # fingerprint: xxxx + # skip-cert-verify: true + # host: bing.com + # path: "/" + # mux: true + # headers: + # custom: value + - name: "ss4" type: ss server: server @@ -310,7 +334,7 @@ proxies: host: "cloud.tencent.com" password: "shadow_tls_password" version: 2 # support 1/2/3 - + # vmess # cipher支持 auto/aes-128-gcm/chacha20-poly1305/none - name: "vmess" @@ -333,7 +357,7 @@ proxies: # Host: v2ray.com # max-early-data: 2048 # early-data-header-name: Sec-WebSocket-Protocol - + - name: "vmess-h2" type: vmess server: server @@ -349,7 +373,7 @@ proxies: - http.example.com - http-alt.example.com path: / - + - name: "vmess-http" type: vmess server: server @@ -360,15 +384,15 @@ proxies: # udp: true # network: http # http-opts: - # # method: "GET" - # # path: - # # - '/' - # # - '/video' - # # headers: - # # Connection: - # # - keep-alive + # method: "GET" + # path: + # - '/' + # - '/video' + # headers: + # Connection: + # - keep-alive # ip-version: ipv4 # 设置使用 IP 类型偏好,可选:ipv4,ipv6,dual,默认值:dual - + - name: vmess-grpc server: server port: 443 @@ -384,100 +408,7 @@ proxies: grpc-opts: grpc-service-name: "example" # ip-version: ipv4 - - # socks5 - - name: "socks" - type: socks5 - server: server - port: 443 - # username: username - # password: password - # tls: true - # fingerprint: xxxx - # skip-cert-verify: true - # udp: true - # ip-version: ipv6 - - # http - - name: "http" - type: http - server: server - port: 443 - # username: username - # password: password - # tls: true # https - # skip-cert-verify: true - # 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" - type: snell - server: server - port: 44046 - psk: yourpsk - # version: 2 - # obfs-opts: - # mode: http # or tls - # host: bing.com - - # Trojan - - name: "trojan" - type: trojan - server: server - port: 443 - password: yourpsk - # client-fingerprint: random # Available: "chrome","firefox","safari","random","none" - # fingerprint: xxxx - # udp: true - # sni: example.com # aka server name - # alpn: - # - h2 - # - http/1.1 - # skip-cert-verify: true - - - name: trojan-grpc - server: server - port: 443 - type: trojan - password: "example" - network: grpc - sni: example.com - # skip-cert-verify: true - # fingerprint: xxxx - udp: true - grpc-opts: - grpc-service-name: "example" - - - name: trojan-ws - server: server - port: 443 - type: trojan - password: "example" - network: ws - sni: example.com - # skip-cert-verify: true - # fingerprint: xxxx - udp: true - # ws-opts: - # path: /path - # headers: - # Host: example.com - - - name: "trojan-xtls" - type: trojan - server: server - port: 443 - password: yourpsk - flow: "xtls-rprx-direct" # xtls-rprx-origin xtls-rprx-direct - flow-show: true - # udp: true - # sni: example.com # aka server name - # skip-cert-verify: true - # fingerprint: xxxx - + # vless - name: "vless-tcp" type: vless @@ -490,7 +421,21 @@ proxies: # skip-cert-verify: true # fingerprint: xxxx # client-fingerprint: random # Available: "chrome","firefox","safari","random","none" - + + - name: "vless-vision" + type: vless + server: server + port: 443 + uuid: uuid + network: tcp + tls: true + udp: true + xudp: true + flow: xtls-rprx-vision # xtls-rprx-origin # enable XTLS + client-fingerprint: chrome + # fingerprint: xxxx + # skip-cert-verify: true + - name: "vless-ws" type: vless server: server @@ -507,6 +452,61 @@ proxies: path: "/" headers: Host: example.com + + # Trojan + - name: "trojan" + type: trojan + server: server + port: 443 + password: yourpsk + # client-fingerprint: random # Available: "chrome","firefox","safari","random","none" + # fingerprint: xxxx + # udp: true + # sni: example.com # aka server name + # alpn: + # - h2 + # - http/1.1 + # skip-cert-verify: true + + - name: trojan-grpc + server: server + port: 443 + type: trojan + password: "example" + network: grpc + sni: example.com + # skip-cert-verify: true + # fingerprint: xxxx + udp: true + grpc-opts: + grpc-service-name: "example" + + - name: trojan-ws + server: server + port: 443 + type: trojan + password: "example" + network: ws + sni: example.com + # skip-cert-verify: true + # fingerprint: xxxx + udp: true + # ws-opts: + # path: /path + # headers: + # Host: example.com + + - name: "trojan-xtls" + type: trojan + server: server + port: 443 + password: yourpsk + flow: "xtls-rprx-direct" # xtls-rprx-origin xtls-rprx-direct + flow-show: true + # udp: true + # sni: example.com # aka server name + # skip-cert-verify: true + # fingerprint: xxxx #hysteria - name: "hysteria" @@ -533,7 +533,8 @@ proxies: # disable_mtu_discovery: false # fingerprint: xxxx # fast-open: true # 支持 TCP 快速打开,默认为 false - + + # wireguard - name: "wg" type: wireguard server: 162.159.192.1 @@ -543,7 +544,9 @@ proxies: private-key: eCtXsJZ27+4PbhDkHnB923tkUn2Gj59wZw5wFA75MnU= public-key: Cr8hWlKvtDt7nrvf+f0brNQQzabAqrjfBvas9pmowjo= udp: true - # reserved: 'U4An' + reserved: "U4An" + + # tuic - name: tuic server: www.example.com port: 10443 @@ -552,16 +555,16 @@ proxies: # ip: 127.0.0.1 # for overwriting the DNS lookup result of the server address set in option 'server' # heartbeat-interval: 10000 # alpn: [h3] - # disable-sni: true + disable-sni: true reduce-rtt: true - # request-timeout: 8000 + request-timeout: 8000 udp-relay-mode: native # Available: "native", "quic". Default: "native" # congestion-controller: bbr # Available: "cubic", "new_reno", "bbr". Default: "cubic" # 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 - + # ShadowsocksR # The supported ciphers (encryption methods): all stream ciphers in ss # The supported obfses: @@ -582,8 +585,7 @@ proxies: # protocol-param: "#" # udp: true -proxy-groups: - # 代理链,若落地协议支持 UDP over TCP 则可支持 UDP +proxy-groups: # 代理链,若落地协议支持 UDP over TCP 则可支持 UDP # Traffic: clash <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet - name: "relay" type: relay @@ -592,7 +594,7 @@ proxy-groups: - vmess - ss1 - ss2 - + # url-test 将按照 url 测试结果使用延迟最低节点 - name: "auto" type: url-test @@ -604,7 +606,7 @@ proxy-groups: # lazy: true url: "https://cp.cloudflare.com/generate_204" interval: 300 - + # fallback 将按照 url 测试结果按照节点顺序选择 - name: "fallback-auto" type: fallback @@ -614,7 +616,7 @@ proxy-groups: - vmess1 url: "https://cp.cloudflare.com/generate_204" interval: 300 - + # load-balance 将按照算法随机选择节点 - name: "load-balance" type: load-balance @@ -624,8 +626,8 @@ proxy-groups: - vmess1 url: "https://cp.cloudflare.com/generate_204" interval: 300 - # strategy: consistent-hashing # 可选 round-robin 和 sticky-sessions - + # strategy: consistent-hashing # 可选 round-robin 和 sticky-sessions + # select 用户自行选择节点 - name: Proxy type: select @@ -635,7 +637,7 @@ proxy-groups: - ss2 - vmess1 - auto - + # 配置指定 interface-name 和 fwmark 的 DIRECT - name: en1 type: select @@ -643,7 +645,7 @@ proxy-groups: routing-mark: 6667 proxies: - DIRECT - + - name: UseProvider type: select filter: "HK|TW" # 正则表达式,过滤 provider1 中节点名包含 HK 或 TW @@ -690,7 +692,8 @@ rules: - DOMAIN-KEYWORD,google,ss1 - IP-CIDR,1.1.1.1/32,ss1 - IP-CIDR6,2409::/64,DIRECT - - SUB-RULE,(OR,((NETWORK,TCP),(NETWORK,UDP))),sub-rule-name1 # 当满足条件是 TCP 或 UDP 流量时,使用名为 sub-rule-name1 当规则集 + # 当满足条件是 TCP 或 UDP 流量时,使用名为 sub-rule-name1 的规则集 + - SUB-RULE,(OR,((NETWORK,TCP),(NETWORK,UDP))),sub-rule-name1 - SUB-RULE,(AND,((NETWORK,UDP))),sub-rule-name2 # 定义多个子规则集,规则将以分叉匹配,使用 SUB-RULE 使用 # google.com(not match)--> baidu.com(match) @@ -717,15 +720,6 @@ sub-rules: - IP-CIDR,8.8.8.8/32,ss1 - DOMAIN,dns.alidns.com,REJECT -tls: - certificate: string # 证书 PEM 格式,或者 证书的路径 - private-key: string # 证书对应的私钥 PEM 格式,或者私钥路径 - # 自定义证书验证,将加入 Clash 证书验证中,绝大多数 TLS 相关支持,如:DNS - # 可用于自定义证书的验证 - custom-certificates: - - certificate: string # 证书 PEM 格式,或者 证书的路径 - private-key: string # 证书对应的私钥 PEM 格式,或者私钥路径 - # 流量入站 listeners: - name: socks5-in-1 @@ -735,14 +729,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 @@ -750,14 +744,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 @@ -765,7 +759,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 @@ -774,7 +768,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 @@ -785,7 +779,7 @@ listeners: - username: 1 uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 alterId: 1 - + - name: tuic-in-1 type: tuic port: 10815 @@ -802,7 +796,7 @@ listeners: # alpn: # - h3 # max-udp-relay-packet-size: 1500 - + - name: tunnel-in-1 type: tunnel port: 10816 @@ -811,7 +805,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 @@ -827,25 +821,25 @@ listeners: inet6-address: # 必须手动设置ipv6地址段 - "fdfe:dcba:9877::1/126" # strict_route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 - # inet4_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 - # - 0.0.0.0/1 - # - 128.0.0.0/1 - # inet6_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 - # - "::/1" - # - "8000::/1" + # inet4_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 + # - 0.0.0.0/1 + # - 128.0.0.0/1 + # inet6_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 + # - "::/1" + # - "8000::/1" # endpoint_independent_nat: false # 启用独立于端点的 NAT # include_uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route # - 0 # include_uid_range: # 限制被路由的的用户范围 # - 1000-99999 # exclude_uid: # 排除路由的的用户 - #- 1000 + # - 1000 # exclude_uid_range: # 排除路由的的用户范围 # - 1000-99999 - + # Android 用户和应用规则仅在 Android 下被支持 # 并且需要 auto_route - + # include_android_user: # 限制被路由的 Android 用户 # - 0 # - 10 @@ -853,3 +847,23 @@ 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 +# vmess-config: vmess://1:9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68@:12345 + +# tuic服务器入口(传入流量将和socks,mixed等入口一样按照mode所指定的方式进行匹配处理) +# tuic-server: +# enable: true +# listen: 127.0.0.1:10443 +# token: +# - TOKEN +# certificate: ./server.crt +# private-key: ./server.key +# congestion-controller: bbr +# max-idle-time: 15000 +# authentication-timeout: 1000 +# alpn: +# - h3 +# max-udp-relay-packet-size: 1500 \ No newline at end of file From de92bc0234a6b0a2b36f6580361e2d768d3a8805 Mon Sep 17 00:00:00 2001 From: Hellojack <106379370+H1JK@users.noreply.github.com> Date: Sat, 25 Feb 2023 19:11:23 +0800 Subject: [PATCH 022/530] fix: Vision filter Client Hello --- transport/vless/conn.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index fd1767cf..4750276e 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -215,12 +215,19 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { return vc.err } } - if vc.writeFilterApplicationData && vc.isTLS { + if vc.writeFilterApplicationData { buffer2 := ReshapeBuffer(buffer) defer buffer2.Release() vc.FilterTLS(buffer.Bytes()) command := commandPaddingContinue - if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { + if !vc.isTLS { + command = commandPaddingEnd + + // disable XTLS + vc.readProcess = false + vc.writeFilterApplicationData = false + vc.packetsToFilter = 0 + } else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { command = commandPaddingEnd if vc.enableXTLS { command = commandPaddingDirect @@ -239,7 +246,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { //time.Sleep(10 * time.Millisecond) } if buffer2 != nil { - if vc.writeDirect { + if vc.writeDirect || !vc.isTLS { return vc.ExtendedWriter.WriteBuffer(buffer2) } vc.FilterTLS(buffer2.Bytes()) @@ -340,12 +347,7 @@ func (vc *Conn) sendRequest(p []byte) bool { if isVision && !vc.dst.UDP && !vc.dst.Mux { if len(p) == 0 { - WriteWithPadding(buffer, nil, commandPaddingEnd, vc.id) - - // disable XTLS - vc.readProcess = false - vc.writeFilterApplicationData = false - vc.packetsToFilter = 0 + WriteWithPadding(buffer, nil, commandPaddingContinue, vc.id) } else { vc.FilterTLS(p) if vc.isTLS { From a3b8c9c2339a03f5523a13c333cc0cb07a63de44 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 25 Feb 2023 19:41:01 +0800 Subject: [PATCH 023/530] fix: peek not work with some inbound --- common/net/bufconn.go | 4 ++++ tunnel/statistic/tracker.go | 12 ++++++------ tunnel/tunnel.go | 8 +++++--- 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/common/net/bufconn.go b/common/net/bufconn.go index 54326cf9..8087608c 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -27,6 +27,10 @@ func (c *BufferedConn) Reader() *bufio.Reader { return c.r } +func (c *BufferedConn) ResetPeeked() { + c.peeked = false +} + func (c *BufferedConn) Peeked() bool { return c.peeked } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 97dd7316..e21868c5 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -81,7 +81,7 @@ func (tt *tcpTracker) Upstream() any { return tt.Conn } -func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule) *tcpTracker { +func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64) *tcpTracker { uuid, _ := uuid.NewV4() if conn != nil { if tcpAddr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { @@ -100,8 +100,8 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R Metadata: metadata, Chain: conn.Chains(), Rule: "", - UploadTotal: atomic.NewInt64(0), - DownloadTotal: atomic.NewInt64(0), + UploadTotal: atomic.NewInt64(uploadTotal), + DownloadTotal: atomic.NewInt64(downloadTotal), }, extendedReader: N.NewExtendedReader(conn), extendedWriter: N.NewExtendedWriter(conn), @@ -147,7 +147,7 @@ func (ut *udpTracker) Close() error { return ut.PacketConn.Close() } -func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule) *udpTracker { +func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64) *udpTracker { uuid, _ := uuid.NewV4() metadata.RemoteDst = conn.RemoteDestination() @@ -160,8 +160,8 @@ func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, ru Metadata: metadata, Chain: conn.Chains(), Rule: "", - UploadTotal: atomic.NewInt64(0), - DownloadTotal: atomic.NewInt64(0), + UploadTotal: atomic.NewInt64(uploadTotal), + DownloadTotal: atomic.NewInt64(downloadTotal), }, } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index b9d0e594..90fd42be 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -322,7 +322,7 @@ func handleUDPConn(packet C.PacketAdapter) { } pCtx.InjectPacketConn(rawPc) - pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule) + pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0) switch true { case metadata.SpecialProxy != "": @@ -367,6 +367,7 @@ func handleTCPConn(connCtx C.ConnContext) { } conn := connCtx.Conn() + conn.ResetPeeked() if sniffer.Dispatcher.Enable() && sniffingEnable { sniffer.Dispatcher.TCPSniff(conn, metadata) } @@ -400,6 +401,7 @@ func handleTCPConn(connCtx C.ConnContext) { } var peekBytes []byte + var peekLen int ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout) defer cancel() @@ -415,7 +417,7 @@ func handleTCPConn(connCtx C.ConnContext) { if err != nil { return nil, err } - if peekLen := len(peekBytes); peekLen > 0 { + if peekLen = len(peekBytes); peekLen > 0 { _, _ = conn.Discard(peekLen) } return remoteConn, err @@ -436,7 +438,7 @@ func handleTCPConn(connCtx C.ConnContext) { return } - remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule) + remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule, 0, int64(peekLen)) defer func(remoteConn C.Conn) { _ = remoteConn.Close() }(remoteConn) From f565edd76dcd2f9db89c524310d1031052e96cbf Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 25 Feb 2023 22:01:20 +0800 Subject: [PATCH 024/530] chore: add custom ca trust --- component/tls/config.go | 48 +++++++++++++--------------------------- config/config.go | 11 ++++----- docs/config.yaml | 5 +++++ hub/executor/executor.go | 6 +++-- 4 files changed, 28 insertions(+), 42 deletions(-) diff --git a/component/tls/config.go b/component/tls/config.go index 39d1b1fd..50daad46 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -11,31 +11,30 @@ import ( "strings" "sync" - CN "github.com/Dreamacro/clash/common/net" - xtls "github.com/xtls/go" ) -var tlsCertificates = make([]tls.Certificate, 0) +var trustCert,_ = x509.SystemCertPool() var mutex sync.RWMutex var errNotMacth error = errors.New("certificate fingerprints do not match") -func AddCertificate(privateKey, certificate string) error { +func AddCertificate(certificate string) error { mutex.Lock() defer mutex.Unlock() - if cert, err := CN.ParseCert(certificate, privateKey); err != nil { - return err - } else { - tlsCertificates = append(tlsCertificates, cert) + if certificate == "" { + return fmt.Errorf("certificate is empty") + } + if ok := trustCert.AppendCertsFromPEM([]byte(certificate)); !ok { + return fmt.Errorf("add certificate failed") } return nil } -func GetCertificates() []tls.Certificate { - mutex.RLock() - defer mutex.RUnlock() - return tlsCertificates +func ResetCertificate(){ + mutex.Lock() + defer mutex.Unlock() + trustCert,_=x509.SystemCertPool() } func verifyFingerprint(fingerprint *[32]byte) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { @@ -87,10 +86,10 @@ func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config { if tlsConfig == nil { return &tls.Config{ - Certificates: tlsCertificates, + RootCAs: trustCert, } } - tlsConfig.Certificates = append(tlsConfig.Certificates, tlsCertificates...) + tlsConfig.RootCAs = trustCert return tlsConfig } @@ -107,29 +106,12 @@ func GetSpecifiedFingerprintXTLSConfig(tlsConfig *xtls.Config, fingerprint strin } func GetGlobalXTLSConfig(tlsConfig *xtls.Config) *xtls.Config { - xtlsCerts := make([]xtls.Certificate, len(tlsCertificates)) - for _, cert := range tlsCertificates { - tlsSsaList := make([]xtls.SignatureScheme, len(cert.SupportedSignatureAlgorithms)) - for _, ssa := range cert.SupportedSignatureAlgorithms { - tlsSsa := xtls.SignatureScheme(ssa) - tlsSsaList = append(tlsSsaList, tlsSsa) - } - xtlsCert := xtls.Certificate{ - Certificate: cert.Certificate, - PrivateKey: cert.PrivateKey, - OCSPStaple: cert.OCSPStaple, - SignedCertificateTimestamps: cert.SignedCertificateTimestamps, - Leaf: cert.Leaf, - SupportedSignatureAlgorithms: tlsSsaList, - } - xtlsCerts = append(xtlsCerts, xtlsCert) - } if tlsConfig == nil { return &xtls.Config{ - Certificates: xtlsCerts, + RootCAs: trustCert, } } - tlsConfig.Certificates = xtlsCerts + tlsConfig.RootCAs = trustCert return tlsConfig } diff --git a/config/config.go b/config/config.go index 24159d8e..76e5491b 100644 --- a/config/config.go +++ b/config/config.go @@ -120,13 +120,9 @@ type Profile struct { } type TLS struct { - RawCert `yaml:",inline"` - CustomTrustCert []RawCert `yaml:"custom-certifactes"` -} - -type RawCert struct { - Certificate string `yaml:"certificate"` - PrivateKey string `yaml:"private-key"` + Certificate string `yaml:"certificate"` + PrivateKey string `yaml:"private-key"` + CustomTrustCert []string `yaml:"custom-certifactes"` } // IPTables config @@ -447,6 +443,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } config.General = general + dialer.DefaultInterface.Store(config.General.Interface) proxies, providers, err := parseProxies(rawCfg) if err != nil { return nil, err diff --git a/docs/config.yaml b/docs/config.yaml index f6e9502e..771532d1 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -30,6 +30,11 @@ ipv6: true # 开启 IPv6 总开关,关闭阻断所有 IPv6 链接和屏蔽 DNS tls: certificate: string # 证书 PEM 格式,或者 证书的路径 private-key: string # 证书对应的私钥 PEM 格式,或者私钥路径 + custom-certifactes: + - | + -----BEGIN CERTIFICATE----- + format/pem... + -----END CERTIFICATE----- external-controller: 0.0.0.0:9093 # RESTful API 监听地址 external-controller-tls: 0.0.0.0:9443 # RESTful API HTTPS 监听地址,需要配置 tls 部分配置文件 diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 916f17c7..34f0f1a1 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -169,9 +169,11 @@ func updateExperimental(c *config.Config) { } func preUpdateExperimental(c *config.Config) { - CTLS.AddCertificate(c.TLS.PrivateKey, c.TLS.Certificate) + CTLS.ResetCertificate() for _, c := range c.TLS.CustomTrustCert { - CTLS.AddCertificate(c.PrivateKey, c.Certificate) + if err := CTLS.AddCertificate(c); err != nil { + log.Warnln("%s\nadd error: %s", c, err.Error()) + } } } From efbde4a179342b14bf8811f4ea42dbf77cca1988 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 26 Feb 2023 11:11:54 +0800 Subject: [PATCH 025/530] fix: reject's dial warning --- adapter/outbound/reject.go | 3 --- tunnel/tunnel.go | 5 +++++ 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index d5a9c823..43833238 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -53,9 +53,6 @@ func (rw *nopConn) Read(b []byte) (int, error) { } func (rw *nopConn) Write(b []byte) (int, error) { - if len(b) == 0 { - return 0, nil - } return 0, io.EOF } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 90fd42be..11458d38 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -410,6 +410,11 @@ func handleTCPConn(connCtx C.ConnContext) { if err != nil { return nil, err } + for _, chain := range remoteConn.Chains() { + if chain == "REJECT" { + return remoteConn, nil + } + } peekMutex.Lock() defer peekMutex.Unlock() peekBytes, _ = conn.Peek(conn.Buffered()) From 40ae019e1dcad6bd46177be49f39c1e0c5074f3c Mon Sep 17 00:00:00 2001 From: Hellojack <106379370+H1JK@users.noreply.github.com> Date: Sun, 26 Feb 2023 11:11:55 +0800 Subject: [PATCH 026/530] fix: Vision filter TLS 1.2 --- transport/vless/conn.go | 15 ++++++++++----- transport/vless/filter.go | 13 ++++++++----- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 4750276e..5817083d 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -133,15 +133,16 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { vc.readProcess = false return vc.ReadBuffer(buffer) case commandPaddingDirect: + needReturn := false if vc.input != nil { _, err := buffer.ReadFrom(vc.input) if err != nil { return err } if vc.input.Len() == 0 { + needReturn = true vc.input = nil - } - if buffer.IsFull() { + } else { // buffer is full return nil } } @@ -150,6 +151,7 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { if err != nil { return err } + needReturn = true if vc.rawInput.Len() == 0 { vc.rawInput = nil } @@ -159,6 +161,9 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { vc.ExtendedReader = N.NewExtendedReader(vc.Conn) log.Debugln("XTLS Vision direct read start") } + if needReturn { + return nil + } default: err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand) log.Debugln(err.Error()) @@ -489,9 +494,9 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { r, _ := t.FieldByName("rawInput") c.input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset)) c.rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset)) - if _, ok := c.Conn.(*net.TCPConn); !ok { - log.Debugln("XTLS underlying conn is not *net.TCPConn, got %s", reflect.TypeOf(conn).Name()) - } + // if _, ok := c.Conn.(*net.TCPConn); !ok { + // log.Debugln("XTLS underlying conn is not *net.TCPConn, got %T", c.Conn) + // } } } diff --git a/transport/vless/filter.go b/transport/vless/filter.go index 15d595bc..5e00b5c3 100644 --- a/transport/vless/filter.go +++ b/transport/vless/filter.go @@ -50,10 +50,13 @@ func (vc *Conn) FilterTLS(p []byte) (index int) { } if vc.remainingServerHello > 0 { - end := vc.remainingServerHello - vc.remainingServerHello -= end - if end > uint16(lenP) { - end = uint16(lenP) + end := int(vc.remainingServerHello) + if index+end > lenP { + end = lenP + vc.remainingServerHello -= uint16(end - index) + } else { + vc.remainingServerHello -= uint16(end) + end += index } if bytes.Contains(p[index:end], tls13SupportedVersions) { // TLS 1.3 Client Hello @@ -64,7 +67,7 @@ func (vc *Conn) FilterTLS(p []byte) (index int) { log.Debugln("XTLS Vision found TLS 1.3, packetLength=", lenP, ", CipherSuite=", cs) vc.packetsToFilter = 0 return - } else if vc.remainingServerHello < 0 { + } else if vc.remainingServerHello <= 0 { log.Debugln("XTLS Vision found TLS 1.2, packetLength=", lenP) vc.packetsToFilter = 0 return From 5e7d644efd0dcad4fe5b826c7ca0051c572b9746 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 26 Feb 2023 11:18:01 +0800 Subject: [PATCH 027/530] fix: ensure peekMutex is locked before handleSocket --- tunnel/tunnel.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 11458d38..c52400e8 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -469,6 +469,8 @@ func handleTCPConn(connCtx C.ConnContext) { ) } + peekMutex.Lock() + defer peekMutex.Unlock() handleSocket(connCtx, remoteConn) } From 97e14337e355a289b21227b8dcc9ba1d6d7e44e4 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 26 Feb 2023 11:24:49 +0800 Subject: [PATCH 028/530] refactor: tcp dial (#412) Non-concurrent support to try to connect in turn fix: serial dual stack dial --- component/dialer/dialer.go | 413 +++++++++++++++---------------------- hub/executor/executor.go | 6 +- 2 files changed, 170 insertions(+), 249 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 9ac9d719..ab2fe047 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -8,20 +8,19 @@ import ( "net/netip" "strings" "sync" + "time" "github.com/Dreamacro/clash/component/resolver" - - "go.uber.org/atomic" ) var ( - dialMux sync.Mutex - actualSingleDialContext = singleDialContext - actualDualStackDialContext = dualStackDialContext - tcpConcurrent = false - DisableIPv6 = false - ErrorInvalidedNetworkStack = errors.New("invalided network stack") - ErrorDisableIPv6 = errors.New("IPv6 is disabled, dialer cancel") + dialMux sync.Mutex + actualSingleStackDialContext = serialSingleStackDialContext + actualDualStackDialContext = serialDualStackDialContext + tcpConcurrent = false + ErrorInvalidedNetworkStack = errors.New("invalided network stack") + ErrorConnTimeout = errors.New("connect timeout") + fallbackTimeout = 300 * time.Millisecond ) func applyOptions(options ...Option) *option { @@ -56,7 +55,7 @@ func DialContext(ctx context.Context, network, address string, options ...Option switch network { case "tcp4", "tcp6", "udp4", "udp6": - return actualSingleDialContext(ctx, network, address, opt) + return actualSingleStackDialContext(ctx, network, address, opt) case "tcp", "udp": return actualDualStackDialContext(ctx, network, address, opt) default: @@ -89,11 +88,11 @@ func SetDial(concurrent bool) { dialMux.Lock() tcpConcurrent = concurrent if concurrent { - actualSingleDialContext = concurrentSingleDialContext + actualSingleStackDialContext = concurrentSingleStackDialContext actualDualStackDialContext = concurrentDualStackDialContext } else { - actualSingleDialContext = singleDialContext - actualDualStackDialContext = dualStackDialContext + actualSingleStackDialContext = serialSingleStackDialContext + actualDualStackDialContext = serialDualStackDialContext } dialMux.Unlock() @@ -114,10 +113,6 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po bindMarkToDialer(opt.routingMark, dialer, network, destination) } - if DisableIPv6 && destination.Is6() { - return nil, ErrorDisableIPv6 - } - address := net.JoinHostPort(destination.String(), port) if opt.tfo { return dialTFO(ctx, *dialer, network, address) @@ -125,146 +120,74 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po return dialer.DialContext(ctx, network, address) } -func singleDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { - host, port, err := net.SplitHostPort(address) +func serialSingleStackDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { + ips, port, err := parseAddr(ctx, network, address, opt.resolver) if err != nil { return nil, err } - - var ip netip.Addr - switch network { - case "tcp4", "udp4": - if opt.resolver == nil { - ip, err = resolver.ResolveIPv4ProxyServerHost(ctx, host) - } else { - ip, err = resolver.ResolveIPv4WithResolver(ctx, host, opt.resolver) - } - default: - if opt.resolver == nil { - ip, err = resolver.ResolveIPv6ProxyServerHost(ctx, host) - } else { - ip, err = resolver.ResolveIPv6WithResolver(ctx, host, opt.resolver) - } - } - if err != nil { - err = fmt.Errorf("dns resolve failed:%w", err) - return nil, err - } - - return dialContext(ctx, network, ip, port, opt) + return serialDialContext(ctx, network, ips, port, opt) } -func dualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { - host, port, err := net.SplitHostPort(address) +func serialDualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { + ips, port, err := parseAddr(ctx, network, address, opt.resolver) + if err != nil { + return nil, err + } + if opt.prefer != 4 && opt.prefer != 6 { + return serialDialContext(ctx, network, ips, port, opt) + } + return dualStackDialContext( + ctx, + func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ips, port, opt) }, + func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ips, port, opt) }, + opt.prefer == 4) +} + +func concurrentSingleStackDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { + ips, port, err := parseAddr(ctx, network, address, opt.resolver) if err != nil { return nil, err } - returned := make(chan struct{}) - defer close(returned) - - type dialResult struct { - net.Conn - error - resolved bool - ipv6 bool - done bool - } - results := make(chan dialResult) - var primary, fallback dialResult - - startRacer := func(ctx context.Context, network, host string, r resolver.Resolver, ipv6 bool) { - result := dialResult{ipv6: ipv6, done: true} - defer func() { - select { - case results <- result: - case <-returned: - if result.Conn != nil { - _ = result.Conn.Close() - } - } - }() - - var ip netip.Addr - if ipv6 { - if r == nil { - ip, result.error = resolver.ResolveIPv6ProxyServerHost(ctx, host) - } else { - ip, result.error = resolver.ResolveIPv6WithResolver(ctx, host, r) - } - } else { - if r == nil { - ip, result.error = resolver.ResolveIPv4ProxyServerHost(ctx, host) - } else { - ip, result.error = resolver.ResolveIPv4WithResolver(ctx, host, r) - } - } - if result.error != nil { - result.error = fmt.Errorf("dns resolve failed:%w", result.error) - return - } - result.resolved = true - - result.Conn, result.error = dialContext(ctx, network, ip, port, opt) - } - - go startRacer(ctx, network+"4", host, opt.resolver, false) - go startRacer(ctx, network+"6", host, opt.resolver, true) - - count := 2 - for i := 0; i < count; i++ { - select { - case res := <-results: - if res.error == nil { - return res.Conn, nil - } - - if !res.ipv6 { - primary = res - } else { - fallback = res - } - - if primary.done && fallback.done { - if primary.resolved { - return nil, primary.error - } else if fallback.resolved { - return nil, fallback.error - } else { - return nil, primary.error - } - } - case <-ctx.Done(): - err = ctx.Err() - break - } - } - - if err == nil { - err = fmt.Errorf("dual stack dial failed") + if conn, err := parallelDialContext(ctx, network, ips, port, opt); err != nil { + return nil, err } else { - err = fmt.Errorf("dual stack dial failed:%w", err) + return conn, nil } - return nil, err } -func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { +func concurrentDualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { + ips, port, err := parseAddr(ctx, network, address, opt.resolver) + if err != nil { + return nil, err + } + if opt.prefer != 4 && opt.prefer != 6 { + return parallelDialContext(ctx, network, ips, port, opt) + } + ipv4s, ipv6s := sortationAddr(ips) + return dualStackDialContext( + ctx, + func(ctx context.Context) (net.Conn, error) { + return parallelDialContext(ctx, network, ipv4s, port, opt) + }, + func(ctx context.Context) (net.Conn, error) { + return parallelDialContext(ctx, network, ipv6s, port, opt) + }, + opt.prefer == 4) +} + +func dualStackDialContext( + ctx context.Context, + ipv4DialFn func(ctx context.Context) (net.Conn, error), + ipv6DialFn func(ctx context.Context) (net.Conn, error), + preferIPv4 bool) (net.Conn, error) { + fallbackTicker := time.NewTicker(fallbackTimeout) + defer fallbackTicker.Stop() + results := make(chan dialResult) returned := make(chan struct{}) defer close(returned) - - type dialResult struct { - ip netip.Addr - net.Conn - error - isPrimary bool - done bool - } - - preferCount := atomic.NewInt32(0) - results := make(chan dialResult) - tcpRacer := func(ctx context.Context, ip netip.Addr) { - result := dialResult{ip: ip, done: true} - + racer := func(dial func(ctx context.Context) (net.Conn, error), isPrimary bool) { + result := dialResult{isPrimary: isPrimary} defer func() { select { case results <- result: @@ -274,140 +197,142 @@ func concurrentDialContext(ctx context.Context, network string, ips []netip.Addr } } }() - if strings.Contains(network, "tcp") { - network = "tcp" - } else { - network = "udp" - } - - if ip.Is6() { - network += "6" - if opt.prefer != 4 { - result.isPrimary = true - } - } - - if ip.Is4() { - network += "4" - if opt.prefer != 6 { - result.isPrimary = true - } - } - - if result.isPrimary { - preferCount.Add(1) - } - - result.Conn, result.error = dialContext(ctx, network, ip, port, opt) + result.Conn, result.error = dial(ctx) } - - for _, ip := range ips { - go tcpRacer(ctx, ip) - } - - connCount := len(ips) + go racer(ipv4DialFn, preferIPv4) + go racer(ipv6DialFn, !preferIPv4) var fallback dialResult - var primaryError error - var finalError error - for i := 0; i < connCount; i++ { + var err error + for { select { + case <-ctx.Done(): + if fallback.error == nil && fallback.Conn != nil { + return fallback.Conn, nil + } + return nil, fmt.Errorf("dual stack connect failed: %w", err) + case <-fallbackTicker.C: + if fallback.error == nil && fallback.Conn != nil { + return fallback.Conn, nil + } case res := <-results: if res.error == nil { if res.isPrimary { return res.Conn, nil - } else { - if !fallback.done || fallback.error != nil { - fallback = res - } - } - } else { - if res.isPrimary { - primaryError = res.error - preferCount.Add(-1) - if preferCount.Load() == 0 && fallback.done && fallback.error == nil { - return fallback.Conn, nil - } } + fallback = res } - case <-ctx.Done(): - if fallback.done && fallback.error == nil { - return fallback.Conn, nil - } - finalError = ctx.Err() - break + err = res.error } } - - if fallback.done && fallback.error == nil { - return fallback.Conn, nil - } - - if primaryError != nil { - return nil, primaryError - } - - if fallback.error != nil { - return nil, fallback.error - } - - if finalError == nil { - finalError = fmt.Errorf("all ips %v tcp shake hands failed", ips) - } else { - finalError = fmt.Errorf("concurrent dial failed:%w", finalError) - } - - return nil, finalError } -func concurrentSingleDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { +func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { + results := make(chan dialResult) + returned := make(chan struct{}) + defer close(returned) + tcpRacer := func(ctx context.Context, ip netip.Addr, port string) { + result := dialResult{isPrimary: true} + defer func() { + select { + case results <- result: + case <-returned: + if result.Conn != nil { + _ = result.Conn.Close() + } + } + }() + result.ip = ip + result.Conn, result.error = dialContext(ctx, network, ip, port, opt) + } + + for _, ip := range ips { + go tcpRacer(ctx, ip, port) + } + var err error + for { + select { + case <-ctx.Done(): + if err != nil { + return nil, err + } + if ctx.Err() == context.DeadlineExceeded { + return nil, ErrorConnTimeout + } + return nil, ctx.Err() + case res := <-results: + if res.error == nil { + return res.Conn, nil + } + err = res.error + } + } +} + +func serialDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { + var ( + conn net.Conn + err error + errs []error + ) + for _, ip := range ips { + if conn, err = dialContext(ctx, network, ip, port, opt); err == nil { + return conn, nil + } else { + errs = append(errs, err) + } + } + return nil, errors.Join(errs...) +} + +type dialResult struct { + ip netip.Addr + net.Conn + error + isPrimary bool +} + +func parseAddr(ctx context.Context, network, address string, preferResolver resolver.Resolver) ([]netip.Addr, string, error) { host, port, err := net.SplitHostPort(address) if err != nil { - return nil, err + return nil, "-1", err } var ips []netip.Addr switch network { case "tcp4", "udp4": - if opt.resolver == nil { + if preferResolver == nil { ips, err = resolver.LookupIPv4ProxyServerHost(ctx, host) } else { - ips, err = resolver.LookupIPv4WithResolver(ctx, host, opt.resolver) + ips, err = resolver.LookupIPv4WithResolver(ctx, host, preferResolver) } - default: - if opt.resolver == nil { + case "tcp6", "udp6": + if preferResolver == nil { ips, err = resolver.LookupIPv6ProxyServerHost(ctx, host) } else { - ips, err = resolver.LookupIPv6WithResolver(ctx, host, opt.resolver) + ips, err = resolver.LookupIPv6WithResolver(ctx, host, preferResolver) + } + default: + if preferResolver == nil { + ips, err = resolver.LookupIP(ctx, host) + } else { + ips, err = resolver.LookupIPWithResolver(ctx, host, preferResolver) } } - if err != nil { - err = fmt.Errorf("dns resolve failed:%w", err) - return nil, err + return nil, "-1", fmt.Errorf("dns resolve failed: %w", err) } - - return concurrentDialContext(ctx, network, ips, port, opt) + return ips, port, nil } -func concurrentDualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { - host, port, err := net.SplitHostPort(address) - if err != nil { - return nil, err +func sortationAddr(ips []netip.Addr) (ipv4s, ipv6s []netip.Addr) { + for _, v := range ips { + if v.Is4() || v.Is4In6() { + ipv4s = append(ipv4s, v) + } else { + ipv6s = append(ipv6s, v) + } } - - var ips []netip.Addr - if opt.resolver != nil { - ips, err = resolver.LookupIPWithResolver(ctx, host, opt.resolver) - } else { - ips, err = resolver.LookupIPProxyServerHost(ctx, host) - } - - if err != nil { - err = fmt.Errorf("dns resolve failed:%w", err) - return nil, err - } - - return concurrentDialContext(ctx, network, ips, port, opt) + return } type Dialer struct { diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 34f0f1a1..c55201cd 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -331,11 +331,7 @@ func updateTunnels(tunnels []LC.Tunnel) { func updateGeneral(general *config.General) { tunnel.SetMode(general.Mode) tunnel.SetFindProcessMode(general.FindProcessMode) - dialer.DisableIPv6 = !general.IPv6 - if !dialer.DisableIPv6 { - log.Infoln("Use IPv6") - } - resolver.DisableIPv6 = dialer.DisableIPv6 + resolver.DisableIPv6 =!general.IPv6 if general.TCPConcurrent { dialer.SetDial(general.TCPConcurrent) From 0a6705f43e1d47a6a5c0a8bc21542c6541ad4ead Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 26 Feb 2023 12:39:53 +0800 Subject: [PATCH 029/530] fix: ip version prefer not working --- component/dialer/dialer.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index ab2fe047..1925e86c 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -136,10 +136,11 @@ func serialDualStackDialContext(ctx context.Context, network, address string, op if opt.prefer != 4 && opt.prefer != 6 { return serialDialContext(ctx, network, ips, port, opt) } + ipv4s, ipv6s := sortationAddr(ips) return dualStackDialContext( ctx, - func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ips, port, opt) }, - func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ips, port, opt) }, + func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ipv4s, port, opt) }, + func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ipv6s, port, opt) }, opt.prefer == 4) } From 2cbfac2c89b77b654f4468bf515cb3b115ed650c Mon Sep 17 00:00:00 2001 From: Hellojack <106379370+H1JK@users.noreply.github.com> Date: Sun, 26 Feb 2023 13:04:12 +0800 Subject: [PATCH 030/530] fix: Filter slice index out of bounds --- transport/vless/filter.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/transport/vless/filter.go b/transport/vless/filter.go index 5e00b5c3..099d2de1 100644 --- a/transport/vless/filter.go +++ b/transport/vless/filter.go @@ -51,14 +51,18 @@ func (vc *Conn) FilterTLS(p []byte) (index int) { if vc.remainingServerHello > 0 { end := int(vc.remainingServerHello) - if index+end > lenP { + i := index + if i < 0 { + i = 0 + } + if i+end > lenP { end = lenP - vc.remainingServerHello -= uint16(end - index) + vc.remainingServerHello -= uint16(end - i) } else { vc.remainingServerHello -= uint16(end) - end += index + end += i } - if bytes.Contains(p[index:end], tls13SupportedVersions) { + if bytes.Contains(p[i:end], tls13SupportedVersions) { // TLS 1.3 Client Hello cs, ok := tls13CipherSuiteMap[vc.cipher] if ok && cs != "TLS_AES_128_CCM_8_SHA256" { From 0321fe93cf459471ed585dc428fd77eed87da9f0 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 26 Feb 2023 13:05:55 +0800 Subject: [PATCH 031/530] fix: replace self define "connect timeout" to os.ErrDeadlineExceeded --- component/dialer/dialer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 1925e86c..b9c897d2 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -6,6 +6,7 @@ import ( "fmt" "net" "net/netip" + "os" "strings" "sync" "time" @@ -19,7 +20,6 @@ var ( actualDualStackDialContext = serialDualStackDialContext tcpConcurrent = false ErrorInvalidedNetworkStack = errors.New("invalided network stack") - ErrorConnTimeout = errors.New("connect timeout") fallbackTimeout = 300 * time.Millisecond ) @@ -257,7 +257,7 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, return nil, err } if ctx.Err() == context.DeadlineExceeded { - return nil, ErrorConnTimeout + return nil, os.ErrDeadlineExceeded } return nil, ctx.Err() case res := <-results: From be5ce6249f1dd84cccbc0b4d9296badf62821456 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 26 Feb 2023 13:52:10 +0800 Subject: [PATCH 032/530] fix: dns resolve in dialer --- component/dialer/dialer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index b9c897d2..3d1be1d6 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -314,7 +314,7 @@ func parseAddr(ctx context.Context, network, address string, preferResolver reso } default: if preferResolver == nil { - ips, err = resolver.LookupIP(ctx, host) + ips, err = resolver.LookupIPProxyServerHost(ctx, host) } else { ips, err = resolver.LookupIPWithResolver(ctx, host, preferResolver) } @@ -328,7 +328,7 @@ func parseAddr(ctx context.Context, network, address string, preferResolver reso func sortationAddr(ips []netip.Addr) (ipv4s, ipv6s []netip.Addr) { for _, v := range ips { if v.Is4() || v.Is4In6() { - ipv4s = append(ipv4s, v) + ipv4s = append(ipv4s, v.Unmap()) } else { ipv6s = append(ipv6s, v) } From 3cd1c92162f83417cd1342268076ab7c6c90de01 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 26 Feb 2023 15:59:34 +0800 Subject: [PATCH 033/530] fix: uot client's WriteTo mistake --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 9c3b78ac..d6103297 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b + github.com/sagernet/sing v0.1.8-0.20230226075703-7def9588a57c github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e github.com/sagernet/sing-vmess v0.1.2 github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d diff --git a/go.sum b/go.sum index c06b8506..8a5a42e8 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b h1:Ji2AfGlc4j9AitobOx4k3BCj7eS5nSxL1cgaL81zvlo= -github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.1.8-0.20230226075703-7def9588a57c h1:PDkrM1NhN03w6AtmBxQldH/mmqNGbKhIi6uWdiTOf9g= +github.com/sagernet/sing v0.1.8-0.20230226075703-7def9588a57c/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e h1:S1fd0kB9aEU68dd269AQy783sUlFu/2fSh/4YYVJ/Oc= github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.2 h1:RbOZNAId2LrCai8epMoQXlf0XTrou0bfcw08hNBg6lM= From e6a35199e0d397d68994d4b6a9e8312073596260 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 26 Feb 2023 20:15:28 +0800 Subject: [PATCH 034/530] fix: dual stack serial dial --- component/dialer/dialer.go | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 3d1be1d6..d4c937e7 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -133,15 +133,12 @@ func serialDualStackDialContext(ctx context.Context, network, address string, op if err != nil { return nil, err } - if opt.prefer != 4 && opt.prefer != 6 { - return serialDialContext(ctx, network, ips, port, opt) - } ipv4s, ipv6s := sortationAddr(ips) return dualStackDialContext( ctx, func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ipv4s, port, opt) }, func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ipv6s, port, opt) }, - opt.prefer == 4) + opt.prefer) } func concurrentSingleStackDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { @@ -174,14 +171,14 @@ func concurrentDualStackDialContext(ctx context.Context, network, address string func(ctx context.Context) (net.Conn, error) { return parallelDialContext(ctx, network, ipv6s, port, opt) }, - opt.prefer == 4) + opt.prefer) } func dualStackDialContext( ctx context.Context, ipv4DialFn func(ctx context.Context) (net.Conn, error), ipv6DialFn func(ctx context.Context) (net.Conn, error), - preferIPv4 bool) (net.Conn, error) { + preferIPVersion int) (net.Conn, error) { fallbackTicker := time.NewTicker(fallbackTimeout) defer fallbackTicker.Stop() results := make(chan dialResult) @@ -200,8 +197,8 @@ func dualStackDialContext( }() result.Conn, result.error = dial(ctx) } - go racer(ipv4DialFn, preferIPv4) - go racer(ipv6DialFn, !preferIPv4) + go racer(ipv4DialFn, preferIPVersion != 6) + go racer(ipv6DialFn, preferIPVersion != 4) var fallback dialResult var err error for { From e1dd4ac9e79cabae47601004c84a652015f8c7fe Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 26 Feb 2023 20:38:32 +0800 Subject: [PATCH 035/530] chore: format code --- component/tls/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/component/tls/config.go b/component/tls/config.go index 50daad46..f0155d78 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -14,7 +14,7 @@ import ( xtls "github.com/xtls/go" ) -var trustCert,_ = x509.SystemCertPool() +var trustCert, _ = x509.SystemCertPool() var mutex sync.RWMutex var errNotMacth error = errors.New("certificate fingerprints do not match") @@ -31,10 +31,10 @@ func AddCertificate(certificate string) error { return nil } -func ResetCertificate(){ +func ResetCertificate() { mutex.Lock() defer mutex.Unlock() - trustCert,_=x509.SystemCertPool() + trustCert, _ = x509.SystemCertPool() } func verifyFingerprint(fingerprint *[32]byte) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { From d36f9c2ac811b41b8ded4e3bf34077608899594d Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 26 Feb 2023 21:01:44 +0800 Subject: [PATCH 036/530] fix: handle no IP address --- component/dialer/dialer.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index d4c937e7..3a37620d 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -218,13 +218,17 @@ func dualStackDialContext( return res.Conn, nil } fallback = res + } else { + err = res.error } - err = res.error } } } func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { + if len(ips) == 0 { + return nil, errors.New("no ip address") + } results := make(chan dialResult) returned := make(chan struct{}) defer close(returned) @@ -267,6 +271,9 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, } func serialDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { + if len(ips) == 0 { + return nil, errors.New("no ip address") + } var ( conn net.Conn err error From c8c078e78a97afa0f6bb2755573e5dff24c867f8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 26 Feb 2023 22:20:25 +0800 Subject: [PATCH 037/530] fix: golang1.19 can't compile --- component/dialer/dialer.go | 8 +++----- component/dialer/error.go | 18 ++++++++++++++++++ go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 component/dialer/error.go diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 3a37620d..2d3937c8 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -2,7 +2,6 @@ package dialer import ( "context" - "errors" "fmt" "net" "net/netip" @@ -19,7 +18,6 @@ var ( actualSingleStackDialContext = serialSingleStackDialContext actualDualStackDialContext = serialDualStackDialContext tcpConcurrent = false - ErrorInvalidedNetworkStack = errors.New("invalided network stack") fallbackTimeout = 300 * time.Millisecond ) @@ -227,7 +225,7 @@ func dualStackDialContext( func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { if len(ips) == 0 { - return nil, errors.New("no ip address") + return nil, ErrorNoIpAddress } results := make(chan dialResult) returned := make(chan struct{}) @@ -272,7 +270,7 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, func serialDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { if len(ips) == 0 { - return nil, errors.New("no ip address") + return nil, ErrorNoIpAddress } var ( conn net.Conn @@ -286,7 +284,7 @@ func serialDialContext(ctx context.Context, network string, ips []netip.Addr, po errs = append(errs, err) } } - return nil, errors.Join(errs...) + return nil, errorsJoin(errs...) } type dialResult struct { diff --git a/component/dialer/error.go b/component/dialer/error.go new file mode 100644 index 00000000..f2f6b4b7 --- /dev/null +++ b/component/dialer/error.go @@ -0,0 +1,18 @@ +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/go.mod b/go.mod index d6103297..401affac 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.8-0.20230226075703-7def9588a57c + github.com/sagernet/sing v0.1.8-0.20230226133421-e83948367009 github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e github.com/sagernet/sing-vmess v0.1.2 github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d diff --git a/go.sum b/go.sum index 8a5a42e8..79cbc722 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.8-0.20230226075703-7def9588a57c h1:PDkrM1NhN03w6AtmBxQldH/mmqNGbKhIi6uWdiTOf9g= -github.com/sagernet/sing v0.1.8-0.20230226075703-7def9588a57c/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.1.8-0.20230226133421-e83948367009 h1:KjrXGv09UlBl3Rj57XInk6u2TAxqpPfOJ2kUgV5B2lw= +github.com/sagernet/sing v0.1.8-0.20230226133421-e83948367009/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e h1:S1fd0kB9aEU68dd269AQy783sUlFu/2fSh/4YYVJ/Oc= github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.2 h1:RbOZNAId2LrCai8epMoQXlf0XTrou0bfcw08hNBg6lM= From c1199f1a8abc3088a8330cce50232e2ed6edff02 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 27 Feb 2023 00:26:49 +0800 Subject: [PATCH 038/530] chore: add early conn interface to decrease unneeded write --- adapter/outbound/shadowsocks.go | 16 +++++++++++--- adapter/outbound/vmess.go | 31 +++++++++++++++++++++++----- adapter/outboundgroup/fallback.go | 21 +++++++++++-------- adapter/outboundgroup/loadbalance.go | 22 ++++++++++++-------- adapter/outboundgroup/urltest.go | 22 ++++++++++++-------- common/convert/util.go | 3 ++- common/net/sing.go | 8 +++++++ component/dialer/tfo.go | 4 ++++ go.mod | 6 +++--- go.sum | 12 +++++------ listener/sing_shadowsocks/server.go | 3 ++- transport/vless/conn.go | 9 ++++++++ transport/vmess/websocket.go | 24 +++++++++++++++------ tunnel/tunnel.go | 25 +++++++++++++--------- 14 files changed, 144 insertions(+), 62 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 6e6a8d0a..aab5cf42 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -6,7 +6,9 @@ import ( "fmt" "net" "strconv" + "time" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" @@ -103,9 +105,17 @@ func (ss *ShadowSocks) streamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e } } if metadata.NetWork == C.UDP && ss.option.UDPOverTCP { - return ss.method.DialEarlyConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")), nil + if N.NeedHandshake(c) { + return ss.method.DialEarlyConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")), nil + } else { + return ss.method.DialConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")) + } + } + if N.NeedHandshake(c) { + return ss.method.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + } else { + return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) } - return ss.method.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil } // DialContext implements C.ProxyAdapter @@ -184,7 +194,7 @@ func (ss *ShadowSocks) SupportUOT() bool { func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) - method, err := shadowimpl.FetchMethod(option.Cipher, option.Password) + method, err := shadowimpl.FetchMethod(option.Cipher, option.Password, time.Now) if err != nil { return nil, fmt.Errorf("ss %s initialize error: %w", addr, err) } diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 2ae72069..25ffebf3 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -11,6 +11,7 @@ import ( "strings" "sync" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" tlsC "github.com/Dreamacro/clash/component/tls" @@ -213,12 +214,24 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { } if metadata.NetWork == C.UDP { if v.option.XUDP { - return v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + if N.NeedHandshake(c) { + return v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + } else { + return v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + } } else { - return v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + if N.NeedHandshake(c) { + return v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + } else { + return v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + } } } else { - return v.client.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + if N.NeedHandshake(c) { + return v.client.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + } else { + return v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + } } } @@ -289,9 +302,17 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o }(c) if v.option.XUDP { - c = v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + if N.NeedHandshake(c) { + c = v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + } else { + c, err = v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + } } else { - c = v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + if N.NeedHandshake(c) { + c = v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + } else { + c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + } } if err != nil { diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 066e8a37..d1d5e6b3 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -8,6 +8,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/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" @@ -35,15 +36,17 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata, opts . f.onDialFailed(proxy.Type(), err) } - c = &callback.FirstWriteCallBackConn{ - Conn: c, - Callback: func(err error) { - if err == nil { - f.onDialSuccess() - } else { - f.onDialFailed(proxy.Type(), err) - } - }, + if N.NeedHandshake(c) { + c = &callback.FirstWriteCallBackConn{ + Conn: c, + Callback: func(err error) { + if err == nil { + f.onDialSuccess() + } else { + f.onDialFailed(proxy.Type(), err) + } + }, + } } return c, err diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 9a010cf9..b89dba93 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -12,6 +12,7 @@ import ( "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/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" @@ -92,16 +93,19 @@ func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata, op lb.onDialFailed(proxy.Type(), err) } - c = &callback.FirstWriteCallBackConn{ - Conn: c, - Callback: func(err error) { - if err == nil { - lb.onDialSuccess() - } else { - lb.onDialFailed(proxy.Type(), err) - } - }, + if N.NeedHandshake(c) { + c = &callback.FirstWriteCallBackConn{ + Conn: c, + Callback: func(err error) { + if err == nil { + lb.onDialSuccess() + } else { + lb.onDialFailed(proxy.Type(), err) + } + }, + } } + return } diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 31eaf4a4..d340539c 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -7,6 +7,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/singledo" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" @@ -43,16 +44,19 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts .. u.onDialFailed(proxy.Type(), err) } - c = &callback.FirstWriteCallBackConn{ - Conn: c, - Callback: func(err error) { - if err == nil { - u.onDialSuccess() - } else { - u.onDialFailed(proxy.Type(), err) - } - }, + if N.NeedHandshake(c) { + c = &callback.FirstWriteCallBackConn{ + Conn: c, + Callback: func(err error) { + if err == nil { + u.onDialSuccess() + } else { + u.onDialFailed(proxy.Type(), err) + } + }, + } } + return c, err } diff --git a/common/convert/util.go b/common/convert/util.go index 03a48ecd..282d52d5 100644 --- a/common/convert/util.go +++ b/common/convert/util.go @@ -6,6 +6,7 @@ import ( "math/rand" "net/http" "strings" + "time" "github.com/gofrs/uuid" ) @@ -317,6 +318,6 @@ func SetUserAgent(header http.Header) { } func VerifyMethod(cipher, password string) (err error) { - _, err = shadowimpl.FetchMethod(cipher, password) + _, err = shadowimpl.FetchMethod(cipher, password, time.Now) return } diff --git a/common/net/sing.go b/common/net/sing.go index 342f2e95..5c980738 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -4,6 +4,7 @@ import ( "context" "net" + "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" "github.com/sagernet/sing/common/network" ) @@ -16,6 +17,13 @@ type ExtendedConn = network.ExtendedConn type ExtendedWriter = network.ExtendedWriter type ExtendedReader = network.ExtendedReader +func NeedHandshake(conn any) bool { + if earlyConn, isEarlyConn := common.Cast[network.EarlyConn](conn); isEarlyConn && earlyConn.NeedHandshake() { + return true + } + return false +} + // Relay copies between left and right bidirectionally. func Relay(leftConn, rightConn net.Conn) { _ = bufio.CopyConn(context.TODO(), leftConn, rightConn) diff --git a/component/dialer/tfo.go b/component/dialer/tfo.go index 2db2e91e..0041a976 100644 --- a/component/dialer/tfo.go +++ b/component/dialer/tfo.go @@ -105,6 +105,10 @@ func (c *tfoConn) Upstream() any { return c.Conn } +func (c *tfoConn) NeedHandshake() bool { + return c.Conn == nil +} + func dialTFO(ctx context.Context, netDialer net.Dialer, network, address string) (net.Conn, error) { ctx, cancel := context.WithCancel(ctx) dialer := tfo.Dialer{Dialer: netDialer, DisableTFO: false} diff --git a/go.mod b/go.mod index 401affac..f9beea8f 100644 --- a/go.mod +++ b/go.mod @@ -19,16 +19,16 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.32.0 - github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7 + github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 github.com/miekg/dns v1.1.50 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.8-0.20230226133421-e83948367009 + github.com/sagernet/sing v0.1.8-0.20230226150041-83d9121b04c6 github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e - github.com/sagernet/sing-vmess v0.1.2 + github.com/sagernet/sing-vmess v0.1.3-0.20230226144228-40c1abdb85be github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c diff --git a/go.sum b/go.sum index 79cbc722..1875b574 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65 h1:WUINdCB/UvSX9I github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65/go.mod h1:e3lCxh3TozKMWAsYTC7nBVnepAxPL/sNyScUFvmEoec= github.com/metacubex/quic-go v0.32.0 h1:dSD8LB4MSeBuD4otd8y1DUZcRdDcEB0Ax5esPOqn2Hw= github.com/metacubex/quic-go v0.32.0/go.mod h1:yParIzDYUd/t/pzFlDtZKhnvSqbUu0bPChlKEGmJStA= -github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7 h1:MNCGIpXhxXn9ck5bxfm/cW9Nr2FGQ5cakcGK0yKZcak= -github.com/metacubex/sing-shadowsocks v0.1.1-0.20230202072246-e2bef5f088c7/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ= +github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE= +github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d h1:oMzkrEoBdwn2/Vyu0n6/LAmvjxqsyFs+f2kqeg7kI8U= github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d/go.mod h1:WmbtxVPpJulKoQGwfnBMk4KSWzZ68sE/myTrQeN/5GE= github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 h1:d96mCF/LYyC9kULd2xwcXfP0Jd8klrOngmRxuUIZg/8= @@ -127,12 +127,12 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.8-0.20230226133421-e83948367009 h1:KjrXGv09UlBl3Rj57XInk6u2TAxqpPfOJ2kUgV5B2lw= -github.com/sagernet/sing v0.1.8-0.20230226133421-e83948367009/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.1.8-0.20230226150041-83d9121b04c6 h1:enq0WDXPUI2QyUUypRd2uiScoWKcs8jo+yB+K5hrdc8= +github.com/sagernet/sing v0.1.8-0.20230226150041-83d9121b04c6/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e h1:S1fd0kB9aEU68dd269AQy783sUlFu/2fSh/4YYVJ/Oc= github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= -github.com/sagernet/sing-vmess v0.1.2 h1:RbOZNAId2LrCai8epMoQXlf0XTrou0bfcw08hNBg6lM= -github.com/sagernet/sing-vmess v0.1.2/go.mod h1:9NSj8mZTx1JIY/HF9LaYRppUsVkysIN5tEFpNZujXxY= +github.com/sagernet/sing-vmess v0.1.3-0.20230226144228-40c1abdb85be h1:FoaWiy89hyRkP/KilUoGn6W/seyVBDZcdsYcJQEx5Hk= +github.com/sagernet/sing-vmess v0.1.3-0.20230226144228-40c1abdb85be/go.mod h1:9NSj8mZTx1JIY/HF9LaYRppUsVkysIN5tEFpNZujXxY= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 h1:gDXi/0uYe8dA48UyUI1LM2la5QYN0IvsDvR2H2+kFnA= diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 305a9496..5602a3ed 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -5,6 +5,7 @@ import ( "fmt" "net" "strings" + "time" "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/common/sockopt" @@ -63,7 +64,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C case common.Contains(shadowaead.List, config.Cipher): sl.service, err = shadowaead.NewService(config.Cipher, nil, config.Password, udpTimeout, h) case common.Contains(shadowaead_2022.List, config.Cipher): - sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h) + sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h, time.Now) default: err = fmt.Errorf("shadowsocks: unsupported method: %s", config.Cipher) return embedSS.New(config, tcpIn, udpIn) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 5817083d..4ee34405 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -430,6 +430,15 @@ func (vc *Conn) Upstream() any { return vc.tlsConn } +func (vc *Conn) NeedHandshake() bool { + select { + case <-vc.handshake: + return true + default: + } + return false +} + func (vc *Conn) IsXTLSVisionEnabled() bool { return vc.addons != nil && vc.addons.Flow == XRV } diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 71dabbdd..dfadb61a 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -301,15 +301,27 @@ func (wsedc *websocketWithEarlyDataConn) SetWriteDeadline(t time.Time) error { return wsedc.Conn.SetWriteDeadline(t) } -func (wsedc *websocketWithEarlyDataConn) LazyHeadroom() bool { - return wsedc.Conn == nil +func (wsedc *websocketWithEarlyDataConn) FrontHeadroom() int { + return 14 } func (wsedc *websocketWithEarlyDataConn) Upstream() any { - if wsedc.Conn == nil { // ensure return a nil interface not an interface with nil value - return nil - } - return wsedc.Conn + return wsedc.underlay +} + +//func (wsedc *websocketWithEarlyDataConn) LazyHeadroom() bool { +// return wsedc.Conn == nil +//} +// +//func (wsedc *websocketWithEarlyDataConn) Upstream() any { +// if wsedc.Conn == nil { // ensure return a nil interface not an interface with nil value +// return nil +// } +// return wsedc.Conn +//} + +func (wsedc *websocketWithEarlyDataConn) NeedHandshake() bool { + return wsedc.Conn == nil } func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) { diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index c52400e8..9e9db82b 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -13,6 +13,7 @@ import ( "github.com/jpillora/backoff" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/nat" P "github.com/Dreamacro/clash/component/process" "github.com/Dreamacro/clash/component/resolver" @@ -367,7 +368,7 @@ func handleTCPConn(connCtx C.ConnContext) { } conn := connCtx.Conn() - conn.ResetPeeked() + conn.ResetPeeked() // reset before sniffer if sniffer.Dispatcher.Enable() && sniffingEnable { sniffer.Dispatcher.TCPSniff(conn, metadata) } @@ -415,15 +416,17 @@ func handleTCPConn(connCtx C.ConnContext) { return remoteConn, nil } } - peekMutex.Lock() - defer peekMutex.Unlock() - peekBytes, _ = conn.Peek(conn.Buffered()) - _, err = remoteConn.Write(peekBytes) - if err != nil { - return nil, err - } - if peekLen = len(peekBytes); peekLen > 0 { - _, _ = conn.Discard(peekLen) + if N.NeedHandshake(remoteConn) { + peekMutex.Lock() + defer peekMutex.Unlock() + peekBytes, _ = conn.Peek(conn.Buffered()) + _, err = remoteConn.Write(peekBytes) + if err != nil { + return nil, err + } + if peekLen = len(peekBytes); peekLen > 0 { + _, _ = conn.Discard(peekLen) + } } return remoteConn, err }, func(err error) { @@ -469,8 +472,10 @@ func handleTCPConn(connCtx C.ConnContext) { ) } + _ = conn.SetReadDeadline(time.Now()) // stop unfinished peek peekMutex.Lock() defer peekMutex.Unlock() + _ = conn.SetReadDeadline(time.Time{}) // reset handleSocket(connCtx, remoteConn) } From 0b56fc7598a35644693ee8c314aa74122421c1f2 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 27 Feb 2023 01:06:41 +0800 Subject: [PATCH 039/530] fix: Vision filter TLS 1.2 Add magic from sing-box. https://github.com/SagerNet/sing-box/blob/5ce3ddee9be640c309a23341951434861dc4c2e0/transport/vless/vision.go#L199 --- transport/vless/conn.go | 22 ++++++++++++-------- transport/vless/filter.go | 43 ++++++++++++++++++++++----------------- 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 4ee34405..82450cf1 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -248,7 +248,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { if vc.writeDirect { vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) log.Debugln("XTLS Vision direct write start") - //time.Sleep(10 * time.Millisecond) + //time.Sleep(5 * time.Millisecond) } if buffer2 != nil { if vc.writeDirect || !vc.isTLS { @@ -393,22 +393,22 @@ func (vc *Conn) sendRequest(p []byte) bool { } func (vc *Conn) recvResponse() error { - var buf [1]byte - _, vc.err = io.ReadFull(vc.ExtendedReader, buf[:]) + var buffer [1]byte + _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) if vc.err != nil { return vc.err } - if buf[0] != Version { + if buffer[0] != Version { return errors.New("unexpected response version") } - _, vc.err = io.ReadFull(vc.ExtendedReader, buf[:]) + _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) if vc.err != nil { return vc.err } - length := int64(buf[0]) + length := int64(buffer[0]) if length != 0 { // addon data length > 0 io.CopyN(io.Discard, vc.ExtendedReader, length) // just discard } @@ -482,19 +482,23 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { var p uintptr switch underlying := conn.(type) { case *gotls.Conn: + //log.Debugln("type tls") c.Conn = underlying.NetConn() c.tlsConn = underlying t = reflect.TypeOf(underlying).Elem() p = uintptr(unsafe.Pointer(underlying)) case *utls.UConn: + //log.Debugln("type *utls.UConn") c.Conn = underlying.NetConn() c.tlsConn = underlying t = reflect.TypeOf(underlying.Conn).Elem() p = uintptr(unsafe.Pointer(underlying.Conn)) case *tlsC.UConn: + //log.Debugln("type *tlsC.UConn") c.Conn = underlying.NetConn() c.tlsConn = underlying.UConn t = reflect.TypeOf(underlying.Conn).Elem() + //log.Debugln("t:%v", t) p = uintptr(unsafe.Pointer(underlying.Conn)) default: return nil, fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, client.Addons.Flow) @@ -503,9 +507,9 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { r, _ := t.FieldByName("rawInput") c.input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset)) c.rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset)) - // if _, ok := c.Conn.(*net.TCPConn); !ok { - // log.Debugln("XTLS underlying conn is not *net.TCPConn, got %T", c.Conn) - // } + //if _, ok := c.Conn.(*net.TCPConn); !ok { + // log.Debugln("XTLS underlying conn is not *net.TCPConn, got %T", c.Conn) + //} } } diff --git a/transport/vless/filter.go b/transport/vless/filter.go index 099d2de1..e16100d5 100644 --- a/transport/vless/filter.go +++ b/transport/vless/filter.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/binary" - log "github.com/sirupsen/logrus" + "github.com/Dreamacro/clash/log" ) var ( @@ -27,24 +27,30 @@ const ( tlsHandshakeTypeServerHello byte = 0x02 ) -func (vc *Conn) FilterTLS(p []byte) (index int) { +func (vc *Conn) FilterTLS(buffer []byte) (index int) { if vc.packetsToFilter <= 0 { return 0 } - lenP := len(p) - vc.packetsToFilter -= 1 - if index = bytes.Index(p, tlsServerHandshakeStart); index != -1 { - if lenP >= index+5 && p[index+5] == tlsHandshakeTypeServerHello { - vc.remainingServerHello = binary.BigEndian.Uint16(p[index+3:]) + 5 - vc.isTLS = true - vc.isTLS12orAbove = true - if lenP-index >= 79 && vc.remainingServerHello >= 79 { - sessionIDLen := int(p[index+43]) - vc.cipher = binary.BigEndian.Uint16(p[index+43+sessionIDLen+1:]) + lenP := len(buffer) + vc.packetsToFilter-- + if index := bytes.Index(buffer, tlsServerHandshakeStart); index != -1 { + if lenP >= index+5 { + if buffer[0] == 22 && buffer[1] == 3 && buffer[2] == 3 { + vc.isTLS = true + if buffer[5] == tlsHandshakeTypeServerHello { + log.Debugln("isTLS12orAbove") + vc.remainingServerHello = binary.BigEndian.Uint16(buffer[index+3:]) + 5 + + vc.isTLS12orAbove = true + if lenP-index >= 79 && vc.remainingServerHello >= 79 { + sessionIDLen := int(buffer[index+43]) + vc.cipher = binary.BigEndian.Uint16(buffer[index+43+sessionIDLen+1:]) + } + } } } - } else if index = bytes.Index(p, tlsClientHandshakeStart); index != -1 { - if lenP >= index+5 && p[index+5] == tlsHandshakeTypeClientHello { + } else if index := bytes.Index(buffer, tlsClientHandshakeStart); index != -1 { + if lenP >= index+5 && buffer[index+5] == tlsHandshakeTypeClientHello { vc.isTLS = true } } @@ -62,22 +68,21 @@ func (vc *Conn) FilterTLS(p []byte) (index int) { vc.remainingServerHello -= uint16(end) end += i } - if bytes.Contains(p[i:end], tls13SupportedVersions) { + if bytes.Contains(buffer[i:end], tls13SupportedVersions) { // TLS 1.3 Client Hello cs, ok := tls13CipherSuiteMap[vc.cipher] if ok && cs != "TLS_AES_128_CCM_8_SHA256" { vc.enableXTLS = true } - log.Debugln("XTLS Vision found TLS 1.3, packetLength=", lenP, ", CipherSuite=", cs) + log.Debugln("XTLS Vision found TLS 1.3, packetLength= %d CipherSuite= %s", lenP, cs) vc.packetsToFilter = 0 return } else if vc.remainingServerHello <= 0 { - log.Debugln("XTLS Vision found TLS 1.2, packetLength=", lenP) + log.Debugln("XTLS Vision found TLS 1.2, packetLength= %d", lenP) vc.packetsToFilter = 0 return } - log.Debugln("XTLS Vision found inconclusive server hello, packetLength=", lenP, - ", remainingServerHelloBytes=", vc.remainingServerHello) + log.Debugln("XTLS Vision found inconclusive server hello, packetLength= %d,remainingServerHelloBytes= %d", lenP, vc.remainingServerHello) } if vc.packetsToFilter <= 0 { log.Debugln("XTLS Vision stop filtering") From 78100aa9634d529ea34acccab80be478fa784b6b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 27 Feb 2023 09:46:00 +0800 Subject: [PATCH 040/530] fix: vless NeedHandshake mistake --- transport/vless/conn.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 82450cf1..53dc7c85 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -433,10 +433,10 @@ func (vc *Conn) Upstream() any { func (vc *Conn) NeedHandshake() bool { select { case <-vc.handshake: - return true + return false default: } - return false + return true } func (vc *Conn) IsXTLSVisionEnabled() bool { From 76ccebf0994eaa3fccc072fb8904889cc5b2cf11 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 27 Feb 2023 09:46:16 +0800 Subject: [PATCH 041/530] chore: better REJECT process --- tunnel/tunnel.go | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 9e9db82b..d80893c9 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -406,29 +406,36 @@ func handleTCPConn(connCtx C.ConnContext) { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTCPTimeout) defer cancel() - remoteConn, err := retry(ctx, func(ctx context.Context) (C.Conn, error) { - remoteConn, err := proxy.DialContext(ctx, dialMetadata) + remoteConn, err := retry(ctx, func(ctx context.Context) (remoteConn C.Conn, err error) { + remoteConn, err = proxy.DialContext(ctx, dialMetadata) if err != nil { - return nil, err - } - for _, chain := range remoteConn.Chains() { - if chain == "REJECT" { - return remoteConn, nil - } + return } + if N.NeedHandshake(remoteConn) { + defer func() { + for _, chain := range remoteConn.Chains() { + if chain == "REJECT" { + err = nil + return + } + } + if err != nil { + remoteConn = nil + } + }() peekMutex.Lock() defer peekMutex.Unlock() peekBytes, _ = conn.Peek(conn.Buffered()) _, err = remoteConn.Write(peekBytes) if err != nil { - return nil, err + return } if peekLen = len(peekBytes); peekLen > 0 { _, _ = conn.Discard(peekLen) } } - return remoteConn, err + return }, func(err error) { if rule == nil { log.Warnln( From ecb2a5f3c6f16b806add47aebbe0072d993e3b53 Mon Sep 17 00:00:00 2001 From: Hellojack <106379370+H1JK@users.noreply.github.com> Date: Mon, 27 Feb 2023 12:02:44 +0800 Subject: [PATCH 042/530] adjust: Simplify VLESS handshake lock --- transport/vless/conn.go | 67 ++++++++++++++++++--------------------- transport/vless/filter.go | 13 ++++---- 2 files changed, 37 insertions(+), 43 deletions(-) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 53dc7c85..c8477090 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -33,8 +33,8 @@ type Conn struct { addons *Addons received bool - handshake chan struct{} handshakeMutex sync.Mutex + needHandshake bool err error tlsConn net.Conn @@ -181,19 +181,25 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { } func (vc *Conn) Write(p []byte) (int, error) { - select { - case <-vc.handshake: - default: - if vc.sendRequest(p) { + if vc.needHandshake { + vc.handshakeMutex.Lock() + if vc.needHandshake { + vc.needHandshake = false + if vc.sendRequest(p) { + vc.handshakeMutex.Unlock() + if vc.err != nil { + return 0, vc.err + } + return len(p), vc.err + } if vc.err != nil { + vc.handshakeMutex.Unlock() return 0, vc.err } - return len(p), vc.err - } - if vc.err != nil { - return 0, vc.err } + vc.handshakeMutex.Unlock() } + if vc.writeFilterApplicationData { _buffer := buf.StackNew() defer buf.KeepAlive(_buffer) @@ -210,16 +216,22 @@ func (vc *Conn) Write(p []byte) (int, error) { } func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { - select { - case <-vc.handshake: - default: - if vc.sendRequest(buffer.Bytes()) { - return vc.err - } - if vc.err != nil { - return vc.err + if vc.needHandshake { + vc.handshakeMutex.Lock() + if vc.needHandshake { + vc.needHandshake = false + if vc.sendRequest(buffer.Bytes()) { + vc.handshakeMutex.Unlock() + return vc.err + } + if vc.err != nil { + vc.handshakeMutex.Unlock() + return vc.err + } } + vc.handshakeMutex.Unlock() } + if vc.writeFilterApplicationData { buffer2 := ReshapeBuffer(buffer) defer buffer2.Release() @@ -281,18 +293,6 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { } func (vc *Conn) sendRequest(p []byte) bool { - vc.handshakeMutex.Lock() - defer vc.handshakeMutex.Unlock() - - select { - case <-vc.handshake: - // The handshake has been completed before. - // So return false to remind the caller. - return false - default: - } - defer close(vc.handshake) - var addonsBytes []byte if vc.addons != nil { addonsBytes, vc.err = proto.Marshal(vc.addons) @@ -431,12 +431,7 @@ func (vc *Conn) Upstream() any { } func (vc *Conn) NeedHandshake() bool { - select { - case <-vc.handshake: - return false - default: - } - return true + return vc.needHandshake } func (vc *Conn) IsXTLSVisionEnabled() bool { @@ -451,7 +446,7 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { Conn: conn, id: client.uuid, dst: dst, - handshake: make(chan struct{}), + needHandshake: true, } if !dst.UDP && client.Addons != nil { diff --git a/transport/vless/filter.go b/transport/vless/filter.go index e16100d5..3ddfb8b9 100644 --- a/transport/vless/filter.go +++ b/transport/vless/filter.go @@ -33,14 +33,13 @@ func (vc *Conn) FilterTLS(buffer []byte) (index int) { } lenP := len(buffer) vc.packetsToFilter-- - if index := bytes.Index(buffer, tlsServerHandshakeStart); index != -1 { + if index = bytes.Index(buffer, tlsServerHandshakeStart); index != -1 { if lenP >= index+5 { if buffer[0] == 22 && buffer[1] == 3 && buffer[2] == 3 { vc.isTLS = true if buffer[5] == tlsHandshakeTypeServerHello { - log.Debugln("isTLS12orAbove") + //log.Debugln("isTLS12orAbove") vc.remainingServerHello = binary.BigEndian.Uint16(buffer[index+3:]) + 5 - vc.isTLS12orAbove = true if lenP-index >= 79 && vc.remainingServerHello >= 79 { sessionIDLen := int(buffer[index+43]) @@ -49,7 +48,7 @@ func (vc *Conn) FilterTLS(buffer []byte) (index int) { } } } - } else if index := bytes.Index(buffer, tlsClientHandshakeStart); index != -1 { + } else if index = bytes.Index(buffer, tlsClientHandshakeStart); index != -1 { if lenP >= index+5 && buffer[index+5] == tlsHandshakeTypeClientHello { vc.isTLS = true } @@ -74,15 +73,15 @@ func (vc *Conn) FilterTLS(buffer []byte) (index int) { if ok && cs != "TLS_AES_128_CCM_8_SHA256" { vc.enableXTLS = true } - log.Debugln("XTLS Vision found TLS 1.3, packetLength= %d CipherSuite= %s", lenP, cs) + log.Debugln("XTLS Vision found TLS 1.3, packetLength=%d, CipherSuite=%s", lenP, cs) vc.packetsToFilter = 0 return } else if vc.remainingServerHello <= 0 { - log.Debugln("XTLS Vision found TLS 1.2, packetLength= %d", lenP) + log.Debugln("XTLS Vision found TLS 1.2, packetLength=%d", lenP) vc.packetsToFilter = 0 return } - log.Debugln("XTLS Vision found inconclusive server hello, packetLength= %d,remainingServerHelloBytes= %d", lenP, vc.remainingServerHello) + log.Debugln("XTLS Vision found inconclusive server hello, packetLength=%d, remainingServerHelloBytes=%d", lenP, vc.remainingServerHello) } if vc.packetsToFilter <= 0 { log.Debugln("XTLS Vision stop filtering") From e3e0e9796b5cca03f97f361f7c17a328586c0573 Mon Sep 17 00:00:00 2001 From: metacubex Date: Mon, 27 Feb 2023 23:02:45 +0800 Subject: [PATCH 043/530] chore: better workflow --- .github/workflows/build.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 66b694de..a47ff3fa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -221,6 +221,10 @@ jobs: tag: Prerelease-${{ github.ref_name }} deleteOnlyFromDrafts: false + - name: Set Env + run: echo "BUILDTIME=$(date -u)" >> $GITHUB_ENV + shell: bash + - name: Tag Repo uses: richardsimko/update-tag@v1.0.6 with: @@ -237,6 +241,10 @@ jobs: files: bin/* prerelease: true generate_release_notes: true + body: | + Release created at ${{ env.BUILDTIME }} + Synchronize ${{ github.ref_name }} branch code updates, keeping only the latest version +
Upload-Release: permissions: write-all From d55025ecaecbfada8feeab0b114db4697e90c1cc Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 28 Feb 2023 15:53:23 +0800 Subject: [PATCH 044/530] fix: udp loopback show "The requested address is not valid in its context." --- component/dialer/dialer.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 2d3937c8..478e9f19 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -347,7 +347,12 @@ func (d Dialer) DialContext(ctx context.Context, network, address string) (net.C } func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { - return ListenPacket(ctx, ParseNetwork(network, rAddrPort.Addr()), address, WithOption(d.Opt)) + opt := WithOption(d.Opt) + if rAddrPort.Addr().Unmap().IsLoopback() { + // avoid "The requested address is not valid in its context." + opt = WithInterface("") + } + return ListenPacket(ctx, ParseNetwork(network, rAddrPort.Addr()), address, opt) } func NewDialer(options ...Option) Dialer { From 6061f3d4fae1a5d3d7f1ae1a71e6b94fd1093987 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 28 Feb 2023 21:17:52 +0800 Subject: [PATCH 045/530] chore: add more utls fingerprints --- component/tls/utls.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/component/tls/utls.go b/component/tls/utls.go index 4724c9a5..a7189aa8 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -67,7 +67,22 @@ var Fingerprints = map[string]UClientHelloID{ "firefox": {&utls.HelloFirefox_Auto}, "safari": {&utls.HelloSafari_Auto}, "ios": {&utls.HelloIOS_Auto}, - "randomized": {&utls.HelloRandomized}, + "android": {&utls.HelloAndroid_11_OkHttp}, + "edge": {&utls.HelloEdge_Auto}, + "360": {&utls.Hello360_Auto}, + "qq": {&utls.HelloQQ_Auto}, + "random": {nil}, + "randomized": {nil}, +} + +func init() { + weights := utls.DefaultWeights + weights.TLSVersMax_Set_VersionTLS13 = 1 + weights.FirstKeyShare_Set_CurveP256 = 0 + randomized := utls.HelloRandomized + randomized.Seed, _ = utls.NewPRNGSeed() + randomized.Weights = &weights + Fingerprints["randomized"] = UClientHelloID{&randomized} } func copyConfig(c *tls.Config) *utls.Config { From 685fd49dd772bfe02e987418c85cf43e2556f2c6 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 1 Mar 2023 13:41:25 +0800 Subject: [PATCH 046/530] chore: better workflow --- .github/workflows/build.yml | 59 ++++++++++++++++++++++--------------- Dockerfile | 4 ++- Makefile | 3 ++ docker/file-name.sh | 17 +++++------ 4 files changed, 49 insertions(+), 34 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a47ff3fa..b40d155a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,35 +37,40 @@ jobs: id: "2", } - { - type: "WithoutCGO", - target: "linux-arm64 linux-mips64 linux-mips64le", - id: "3", - } + type: "WithoutCGO", + target: "linux-arm64 linux-mips64 linux-mips64le", + id: "3", + } - { - type: "WithoutCGO", - target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", - id: "4", - } + type: "WithoutCGO", + target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", + id: "4", + } - { - type: "WithoutCGO", - target: "freebsd-386 freebsd-amd64 freebsd-arm64", - id: "5", - } + type: "WithoutCGO", + target: "linux-386 linux-riscv64", + id: "5", + } - { - type: "WithoutCGO", - target: "windows-amd64-compatible windows-amd64 windows-386", - id: "6", - } + type: "WithoutCGO", + target: "freebsd-386 freebsd-amd64 freebsd-arm64", + id: "6", + } - { - type: "WithoutCGO", - target: "windows-arm64 windows-arm32v7", - id: "7", - } + type: "WithoutCGO", + target: "windows-amd64-compatible windows-amd64 windows-386", + id: "7", + } - { - type: "WithoutCGO", - target: "darwin-amd64 darwin-arm64 android-arm64", - id: "8", - } + type: "WithoutCGO", + target: "windows-arm64 windows-arm32v7", + id: "8", + } + - { + type: "WithoutCGO", + target: "darwin-amd64 darwin-arm64 android-arm64", + id: "9", + } - { type: "WithCGO", target: "windows/*", id: "1" } - { type: "WithCGO", target: "linux/386", id: "2" } - { type: "WithCGO", target: "linux/amd64", id: "3" } @@ -193,6 +198,10 @@ jobs: ls -la cd .. + - name: Save version + run: echo ${VERSION} > bin/version.txt + shell: bash + - uses: actions/upload-artifact@v3 if: ${{ success() }} with: @@ -329,5 +338,7 @@ jobs: linux/386 linux/amd64 linux/arm64/v8 + linux/arm/v7 + # linux/riscv64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/Dockerfile b/Dockerfile index 9c2e44c7..f5dcc307 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,6 @@ FROM alpine:latest as builder +ARG TARGETPLATFORM +RUN echo "I'm building for $TARGETPLATFORM" RUN apk add --no-cache gzip && \ mkdir /clash-config && \ @@ -10,7 +12,7 @@ COPY docker/file-name.sh /clash/file-name.sh WORKDIR /clash COPY bin/ bin/ RUN FILE_NAME=`sh file-name.sh` && echo $FILE_NAME && \ - FILE_NAME=`ls bin/ | egrep "$FILE_NAME.*"|awk NR==1` && \ + FILE_NAME=`ls bin/ | egrep "$FILE_NAME.*"|awk NR==1` && echo $FILE_NAME && \ mv bin/$FILE_NAME clash.gz && gzip -d clash.gz && echo "$FILE_NAME" > /clash-config/test FROM alpine:latest LABEL org.opencontainers.image.source="https://github.com/MetaCubeX/Clash.Meta" diff --git a/Makefile b/Makefile index f7a637a9..ecd1f5e6 100644 --- a/Makefile +++ b/Makefile @@ -101,6 +101,9 @@ linux-mips64: linux-mips64le: GOARCH=mips64le GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ +linux-riscv64: + GOARCH=riscv64 GOOS=linux $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ + android-arm64: GOARCH=arm64 GOOS=android $(GOBUILD) -o $(BINDIR)/$(NAME)-$@ diff --git a/docker/file-name.sh b/docker/file-name.sh index fb87cad0..1ac2cee0 100644 --- a/docker/file-name.sh +++ b/docker/file-name.sh @@ -1,26 +1,25 @@ #!/bin/sh os="clash.meta-linux-" -arch=`uname -m` -case $arch in - "x86_64") +case $TARGETPLATFORM in + "linux/amd64") arch="amd64-compatible" ;; - "x86") - arch="386-cgo" + "linux/386") + arch="386" ;; - "aarch64") + "linux/arm64") arch="arm64" ;; - "armv7l") + "linux/arm/v7") arch="armv7" ;; "riscv64") - arch="riscv64-cgo" + arch="riscv64" ;; *) echo "Unknown architecture" exit 1 ;; esac -file_name="$os$arch" +file_name="$os$arch-$(cat bin/version.txt)" echo $file_name \ No newline at end of file From e7613e4f8b508dc95bbf45a8acbdaf8d8f1f8462 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 1 Mar 2023 14:04:42 +0800 Subject: [PATCH 047/530] fix: loadbalance panic --- adapter/outboundgroup/loadbalance.go | 35 +++++++++++++++------------- adapter/outboundgroup/relay.go | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index b89dba93..7c7edd36 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -6,6 +6,7 @@ import ( "errors" "fmt" "net" + "sync" "time" "github.com/Dreamacro/clash/adapter/outbound" @@ -20,7 +21,7 @@ import ( "golang.org/x/net/publicsuffix" ) -type strategyFn = func(proxies []C.Proxy, metadata *C.Metadata) C.Proxy +type strategyFn = func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy type LoadBalance struct { *GroupBase @@ -127,21 +128,23 @@ func (lb *LoadBalance) SupportUDP() bool { } func strategyRoundRobin() strategyFn { - flag := true idx := 0 - return func(proxies []C.Proxy, metadata *C.Metadata) C.Proxy { + idxMutex := sync.Mutex{} + return func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy { + id := idx // value could be wrong due to no lock, but don't care if we don't touch + if touch { + idxMutex.Lock() + defer idxMutex.Unlock() + id = idx // get again by lock's protect, so it must be right + defer func() { + idx = id + }() + } + length := len(proxies) for i := 0; i < length; i++ { - flag = !flag - if flag { - idx = (idx - 1) % length - } else { - idx = (idx + 2) % length - } - if idx < 0 { - idx = idx + length - } - proxy := proxies[idx] + id = (id + 1) % length + proxy := proxies[id] if proxy.Alive() { return proxy } @@ -153,7 +156,7 @@ func strategyRoundRobin() strategyFn { func strategyConsistentHashing() strategyFn { maxRetry := 5 - return func(proxies []C.Proxy, metadata *C.Metadata) C.Proxy { + return func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy { key := uint64(murmur3.Sum32([]byte(getKey(metadata)))) buckets := int32(len(proxies)) for i := 0; i < maxRetry; i, key = i+1, key+1 { @@ -181,7 +184,7 @@ func strategyStickySessions() strategyFn { lruCache := cache.New[uint64, int]( cache.WithAge[uint64, int](int64(ttl.Seconds())), cache.WithSize[uint64, int](1000)) - return func(proxies []C.Proxy, metadata *C.Metadata) C.Proxy { + return func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy { key := uint64(murmur3.Sum32([]byte(getKeyWithSrcAndDst(metadata)))) length := len(proxies) idx, has := lruCache.Get(key) @@ -213,7 +216,7 @@ func strategyStickySessions() strategyFn { // Unwrap implements C.ProxyAdapter func (lb *LoadBalance) Unwrap(metadata *C.Metadata, touch bool) C.Proxy { proxies := lb.GetProxies(touch) - return lb.strategyFn(proxies, metadata) + return lb.strategyFn(proxies, metadata, true) } // MarshalJSON implements C.ProxyAdapter diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go index b466b1ff..e17ae132 100644 --- a/adapter/outboundgroup/relay.go +++ b/adapter/outboundgroup/relay.go @@ -176,7 +176,7 @@ func (r *Relay) proxies(metadata *C.Metadata, touch bool) ([]C.Proxy, []C.Proxy) } func (r *Relay) Addr() string { - proxies, _ := r.proxies(nil, true) + proxies, _ := r.proxies(nil, false) return proxies[len(proxies)-1].Addr() } From 4c1682b365ac809c33a91ff54cc7da5d6a5cf909 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 1 Mar 2023 16:55:26 +0800 Subject: [PATCH 048/530] chore: better release notes --- .github/workflows/build.yml | 84 ++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 39 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b40d155a..6a6ca73b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,40 +37,36 @@ jobs: id: "2", } - { - type: "WithoutCGO", - target: "linux-arm64 linux-mips64 linux-mips64le", - id: "3", - } + type: "WithoutCGO", + target: "linux-arm64 linux-mips64 linux-mips64le", + id: "3", + } - { - type: "WithoutCGO", - target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", - id: "4", - } + type: "WithoutCGO", + target: "linux-mips-softfloat linux-mips-hardfloat linux-mipsle-softfloat linux-mipsle-hardfloat", + id: "4", + } + - { type: "WithoutCGO", target: "linux-386 linux-riscv64", id: "5" } - { - type: "WithoutCGO", - target: "linux-386 linux-riscv64", - id: "5", - } + type: "WithoutCGO", + target: "freebsd-386 freebsd-amd64 freebsd-arm64", + id: "6", + } - { - type: "WithoutCGO", - target: "freebsd-386 freebsd-amd64 freebsd-arm64", - id: "6", - } + type: "WithoutCGO", + target: "windows-amd64-compatible windows-amd64 windows-386", + id: "7", + } - { - type: "WithoutCGO", - target: "windows-amd64-compatible windows-amd64 windows-386", - id: "7", - } + type: "WithoutCGO", + target: "windows-arm64 windows-arm32v7", + id: "8", + } - { - type: "WithoutCGO", - target: "windows-arm64 windows-arm32v7", - id: "8", - } - - { - type: "WithoutCGO", - target: "darwin-amd64 darwin-arm64 android-arm64", - id: "9", - } + type: "WithoutCGO", + target: "darwin-amd64 darwin-arm64 android-arm64", + id: "9", + } - { type: "WithCGO", target: "windows/*", id: "1" } - { type: "WithCGO", target: "linux/386", id: "2" } - { type: "WithCGO", target: "linux/amd64", id: "3" } @@ -113,10 +109,11 @@ jobs: - name: Set ENV run: | + sudo timedatectl set-timezone "Asia/Shanghai" echo "NAME=clash.meta" >> $GITHUB_ENV echo "REPO=${{ github.repository }}" >> $GITHUB_ENV echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV - echo "BUILDTIME=$(date -u)" >> $GITHUB_ENV + echo "BUILDTIME=$(date)" >> $GITHUB_ENV echo "BRANCH=$(git rev-parse --abbrev-ref HEAD)" >> $GITHUB_ENV shell: bash @@ -211,7 +208,7 @@ jobs: Upload-Prerelease: permissions: write-all if: ${{ github.ref_type=='branch' }} - needs: [ Build ] + needs: [Build] runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v3 @@ -231,7 +228,8 @@ jobs: deleteOnlyFromDrafts: false - name: Set Env - run: echo "BUILDTIME=$(date -u)" >> $GITHUB_ENV + run: | + echo "BUILDTIME=$(date)" >> $GITHUB_ENV shell: bash - name: Tag Repo @@ -241,24 +239,32 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - run: | + echo 'Release created at ${{ env.BUILDTIME }} + Synchronize ${{ github.ref_name }} branch code updates, keeping only the latest version +
+ ### release version + `default(not specified in file name)`: compiled with GOAMD64=v3 + `cgo`: support lwip tun stack, compiled with GOAMD64=v1 + `compatible`: compiled with GOAMD64=v1 + Check details between different architectural levels [here](https://github.com/golang/go/wiki/MinimumRequirements#amd64).' > release.txt + - name: Upload Prerelease uses: softprops/action-gh-release@v1 if: ${{ success() }} with: tag: ${{ github.ref_name }} tag_name: Prerelease-${{ github.ref_name }} - files: bin/* + files: | + bin/* prerelease: true generate_release_notes: true - body: | - Release created at ${{ env.BUILDTIME }} - Synchronize ${{ github.ref_name }} branch code updates, keeping only the latest version -
+ body_path: release.txt Upload-Release: permissions: write-all if: ${{ github.ref_type=='tag' }} - needs: [ Build ] + needs: [Build] runs-on: ubuntu-latest steps: - uses: actions/download-artifact@v3 @@ -281,7 +287,7 @@ jobs: Docker: permissions: write-all - needs: [ Build ] + needs: [Build] runs-on: ubuntu-latest steps: - name: Checkout repository From 02395413bacc4630de9757d308b9e07737b0be61 Mon Sep 17 00:00:00 2001 From: kunish Date: Thu, 2 Mar 2023 14:39:57 +0800 Subject: [PATCH 049/530] chore: better release notes --- .github/workflows/build.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a6ca73b..ea5c8142 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -240,14 +240,16 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - echo 'Release created at ${{ env.BUILDTIME }} + cat > release.txt << 'EOF' + Release created at ${{ env.BUILDTIME }} Synchronize ${{ github.ref_name }} branch code updates, keeping only the latest version
### release version `default(not specified in file name)`: compiled with GOAMD64=v3 `cgo`: support lwip tun stack, compiled with GOAMD64=v1 `compatible`: compiled with GOAMD64=v1 - Check details between different architectural levels [here](https://github.com/golang/go/wiki/MinimumRequirements#amd64).' > release.txt + Check details between different architectural levels [here](https://github.com/golang/go/wiki/MinimumRequirements#amd64). + EOF - name: Upload Prerelease uses: softprops/action-gh-release@v1 From 838c5c7770a5e5e8b79b41af7868010cf9c99d0d Mon Sep 17 00:00:00 2001 From: kunish Date: Thu, 2 Mar 2023 15:09:40 +0800 Subject: [PATCH 050/530] ci: set prerelease notes timezone of release create time to Asia/Shanghai --- .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 ea5c8142..537c7d14 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -229,7 +229,7 @@ jobs: - name: Set Env run: | - echo "BUILDTIME=$(date)" >> $GITHUB_ENV + echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV shell: bash - name: Tag Repo From da27be6de5e4780965e807015101c0e483bfbd7d Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 4 Mar 2023 09:44:36 +0800 Subject: [PATCH 051/530] chore: add sni of tuic in demo --- docs/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/config.yaml b/docs/config.yaml index 771532d1..438875d2 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -569,6 +569,7 @@ proxies: # socks5 # 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 From bccc6aa8d1cb402373ba0b68e665d0f2f8b1894f Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 4 Mar 2023 18:33:05 +0800 Subject: [PATCH 052/530] chore: Better REJECT conn --- adapter/outbound/reject.go | 45 ++++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index 43833238..a469ed2a 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -6,6 +6,7 @@ import ( "net" "time" + "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" ) @@ -16,12 +17,12 @@ type Reject struct { // DialContext implements C.ProxyAdapter func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { - return NewConn(&nopConn{}, r), nil + return NewConn(nopConn{}, r), nil } // ListenPacketContext implements C.ProxyAdapter func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { - return newPacketConn(&nopPacketConn{}, r), nil + return newPacketConn(nopPacketConn{}, r), nil } func NewReject() *Reject { @@ -48,27 +49,37 @@ func NewPass() *Reject { type nopConn struct{} -func (rw *nopConn) Read(b []byte) (int, error) { +func (rw nopConn) Read(b []byte) (int, error) { return 0, io.EOF } -func (rw *nopConn) Write(b []byte) (int, error) { +func (rw nopConn) ReadBuffer(buffer *buf.Buffer) error { + return io.EOF +} + +func (rw nopConn) Write(b []byte) (int, error) { return 0, io.EOF } -func (rw *nopConn) Close() error { return nil } -func (rw *nopConn) LocalAddr() net.Addr { return nil } -func (rw *nopConn) RemoteAddr() net.Addr { return nil } -func (rw *nopConn) SetDeadline(time.Time) error { return nil } -func (rw *nopConn) SetReadDeadline(time.Time) error { return nil } -func (rw *nopConn) SetWriteDeadline(time.Time) error { return nil } +func (rw nopConn) WriteBuffer(buffer *buf.Buffer) error { + return io.EOF +} + +func (rw nopConn) Close() error { return nil } +func (rw nopConn) LocalAddr() net.Addr { return nil } +func (rw nopConn) RemoteAddr() net.Addr { return nil } +func (rw nopConn) SetDeadline(time.Time) error { return nil } +func (rw nopConn) SetReadDeadline(time.Time) error { return nil } +func (rw nopConn) SetWriteDeadline(time.Time) error { return nil } + +var udpAddrIPv4Unspecified = &net.UDPAddr{IP: net.IPv4zero, Port: 0} 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 &net.UDPAddr{IP: net.IPv4zero, Port: 0} } -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) 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 } From 8771fa5c17e8eb430739eb125bc283f3dc0b32df Mon Sep 17 00:00:00 2001 From: H1JK <106379370+h1jk@users.noreply.github.com> Date: Sat, 4 Mar 2023 21:47:06 +0800 Subject: [PATCH 053/530] chore: Vision padding upgrade --- transport/vless/conn.go | 28 ++++++++++++++-------------- transport/vless/vision.go | 23 +++++++++++++++++------ 2 files changed, 31 insertions(+), 20 deletions(-) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index c8477090..1f7d2cb3 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -241,7 +241,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { command = commandPaddingEnd // disable XTLS - vc.readProcess = false + //vc.readProcess = false vc.writeFilterApplicationData = false vc.packetsToFilter = 0 } else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { @@ -252,7 +252,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { } vc.writeFilterApplicationData = false } - ApplyPadding(buffer, command, nil) + ApplyPadding(buffer, command, nil, vc.isTLS) err := vc.ExtendedWriter.WriteBuffer(buffer) if err != nil { return err @@ -276,7 +276,7 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { } vc.writeFilterApplicationData = false } - ApplyPadding(buffer2, command, nil) + ApplyPadding(buffer2, command, nil, vc.isTLS) err = vc.ExtendedWriter.WriteBuffer(buffer2) if vc.writeDirect { vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) @@ -352,19 +352,19 @@ func (vc *Conn) sendRequest(p []byte) bool { if isVision && !vc.dst.UDP && !vc.dst.Mux { if len(p) == 0 { - WriteWithPadding(buffer, nil, commandPaddingContinue, vc.id) + WriteWithPadding(buffer, nil, commandPaddingContinue, vc.id, vc.isTLS) } else { vc.FilterTLS(p) - if vc.isTLS { - WriteWithPadding(buffer, p, commandPaddingContinue, vc.id) - } else { - buf.Must(buf.Error(buffer.Write(p))) - - // disable XTLS - vc.readProcess = false - vc.writeFilterApplicationData = false - vc.packetsToFilter = 0 - } + //if vc.isTLS { + WriteWithPadding(buffer, p, commandPaddingContinue, vc.id, vc.isTLS) + //} else { + // buf.Must(buf.Error(buffer.Write(p))) + // + // // disable XTLS + // vc.readProcess = false + // vc.writeFilterApplicationData = false + // vc.packetsToFilter = 0 + //} } } else { buf.Must(buf.Error(buffer.Write(p))) diff --git a/transport/vless/vision.go b/transport/vless/vision.go index f87a6870..14d701b4 100644 --- a/transport/vless/vision.go +++ b/transport/vless/vision.go @@ -19,16 +19,22 @@ const ( commandPaddingDirect byte = 0x02 ) -func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID) { +func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID, paddingTLS bool) { contentLen := int32(len(p)) var paddingLen int32 - if contentLen < 900 { + if contentLen < 900 && paddingTLS { + log.Debugln("long padding") paddingLen = rand.Int31n(500) + 900 - contentLen + } else { + paddingLen = rand.Int31n(256) + } + if paddingLen > buf.BufferSize-21-contentLen { + paddingLen = buf.BufferSize - 21 - contentLen } - if userUUID != nil { // unnecessary, but keep the same with Xray buffer.Write(userUUID.Bytes()) } + buffer.WriteByte(command) binary.BigEndian.PutUint16(buffer.Extend(2), uint16(contentLen)) binary.BigEndian.PutUint16(buffer.Extend(2), uint16(paddingLen)) @@ -37,13 +43,18 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid log.Debugln("XTLS Vision write padding1: command=%v, payloadLen=%v, paddingLen=%v", command, contentLen, paddingLen) } -func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID) { +func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) { contentLen := int32(buffer.Len()) var paddingLen int32 - if contentLen < 900 { + if contentLen < 900 && paddingTLS { + log.Debugln("long padding") paddingLen = rand.Int31n(500) + 900 - contentLen + } else { + paddingLen = rand.Int31n(256) + } + if paddingLen > buf.BufferSize-21-contentLen { + paddingLen = buf.BufferSize - 21 - contentLen } - binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(paddingLen)) binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(contentLen)) buffer.ExtendHeader(1)[0] = command From 3b037acb01eb1e5691c9f4261733a9a4f6189d49 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 4 Mar 2023 23:41:41 +0800 Subject: [PATCH 054/530] chore: Update dependencies --- go.mod | 12 ++++++------ go.sum | 24 ++++++++++++------------ listener/sing_tun/server.go | 2 +- listener/sing_tun/server_notwindows.go | 4 ++-- listener/sing_tun/server_windows.go | 4 ++-- 5 files changed, 23 insertions(+), 23 deletions(-) diff --git a/go.mod b/go.mod index f9beea8f..0b02e67d 100644 --- a/go.mod +++ b/go.mod @@ -20,15 +20,15 @@ require ( github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.32.0 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 - github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d + github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 github.com/miekg/dns v1.1.50 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.8-0.20230226150041-83d9121b04c6 - github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e - github.com/sagernet/sing-vmess v0.1.3-0.20230226144228-40c1abdb85be + github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a + github.com/sagernet/sing-shadowtls v0.1.0 + github.com/sagernet/sing-vmess v0.1.3-0.20230303082804-627cc46ae68b github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c @@ -41,7 +41,7 @@ require ( go.uber.org/automaxprocs v1.5.1 golang.org/x/crypto v0.6.0 golang.org/x/exp v0.0.0-20221205204356-47842c84f3db - golang.org/x/net v0.6.0 + golang.org/x/net v0.7.0 golang.org/x/sync v0.1.0 golang.org/x/sys v0.5.0 google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d @@ -63,7 +63,7 @@ require ( github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/mdlayher/socket v0.4.0 // indirect - github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65 // indirect + github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 1875b574..d2aae570 100644 --- a/go.sum +++ b/go.sum @@ -87,14 +87,14 @@ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= -github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65 h1:WUINdCB/UvSX9I+wN+y5xVEisPrXA73rxkoHK5DMyZs= -github.com/metacubex/gvisor v0.0.0-20230222112937-bdbcd206ec65/go.mod h1:e3lCxh3TozKMWAsYTC7nBVnepAxPL/sNyScUFvmEoec= +github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005 h1:0TEvReK/D6YLszjGj/bdx4d7amQSjQ2X/98r4ZiUbxU= +github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= github.com/metacubex/quic-go v0.32.0 h1:dSD8LB4MSeBuD4otd8y1DUZcRdDcEB0Ax5esPOqn2Hw= github.com/metacubex/quic-go v0.32.0/go.mod h1:yParIzDYUd/t/pzFlDtZKhnvSqbUu0bPChlKEGmJStA= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= -github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d h1:oMzkrEoBdwn2/Vyu0n6/LAmvjxqsyFs+f2kqeg7kI8U= -github.com/metacubex/sing-tun v0.1.1-0.20230222113101-fbfa2dab826d/go.mod h1:WmbtxVPpJulKoQGwfnBMk4KSWzZ68sE/myTrQeN/5GE= +github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 h1:oQLThm1a8E7hHmoM9XF2cO0FZPsHVynC4YXW4b3liUI= +github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3/go.mod h1:b/19bRRhwampNPV+1gVDyDsQHmuGDaplxPQkwJh1kj4= github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 h1:d96mCF/LYyC9kULd2xwcXfP0Jd8klrOngmRxuUIZg/8= github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4/go.mod h1:p2VpJuxRefgVMxc8cmatMGSFNvYbjMYMsXJOe7qFstw= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= @@ -127,12 +127,12 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.8-0.20230226150041-83d9121b04c6 h1:enq0WDXPUI2QyUUypRd2uiScoWKcs8jo+yB+K5hrdc8= -github.com/sagernet/sing v0.1.8-0.20230226150041-83d9121b04c6/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= -github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e h1:S1fd0kB9aEU68dd269AQy783sUlFu/2fSh/4YYVJ/Oc= -github.com/sagernet/sing-shadowtls v0.0.0-20230221130515-dac782ca098e/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= -github.com/sagernet/sing-vmess v0.1.3-0.20230226144228-40c1abdb85be h1:FoaWiy89hyRkP/KilUoGn6W/seyVBDZcdsYcJQEx5Hk= -github.com/sagernet/sing-vmess v0.1.3-0.20230226144228-40c1abdb85be/go.mod h1:9NSj8mZTx1JIY/HF9LaYRppUsVkysIN5tEFpNZujXxY= +github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a h1:NvhI/8DMFt2yV3eoYhw6P/XyWzzIKkMiGvFglJbWHWg= +github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= +github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= +github.com/sagernet/sing-vmess v0.1.3-0.20230303082804-627cc46ae68b h1:NZeF0ATeJwe4W3gTJNeIfTB6yBxai665q1HvDOaWmmU= +github.com/sagernet/sing-vmess v0.1.3-0.20230303082804-627cc46ae68b/go.mod h1:9NSj8mZTx1JIY/HF9LaYRppUsVkysIN5tEFpNZujXxY= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 h1:gDXi/0uYe8dA48UyUI1LM2la5QYN0IvsDvR2H2+kFnA= @@ -190,8 +190,8 @@ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.6.0 h1:L4ZwwTvKW9gr0ZMS1yrHD9GZhIuVjOBBnaKH+SPQK0Q= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= 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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 3abef12d..06215c73 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -221,7 +221,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte err = E.Cause(err, "build android rules") return } - tunIf, err := tunOpen(tunOptions) + tunIf, err := tunNew(tunOptions) if err != nil { err = E.Cause(err, "configure tun interface") return diff --git a/listener/sing_tun/server_notwindows.go b/listener/sing_tun/server_notwindows.go index d3280c5c..eda79dc0 100644 --- a/listener/sing_tun/server_notwindows.go +++ b/listener/sing_tun/server_notwindows.go @@ -6,6 +6,6 @@ import ( tun "github.com/metacubex/sing-tun" ) -func tunOpen(options tun.Options) (tun.Tun, error) { - return tun.Open(options) +func tunNew(options tun.Options) (tun.Tun, error) { + return tun.New(options) } diff --git a/listener/sing_tun/server_windows.go b/listener/sing_tun/server_windows.go index 7b745cac..9584f32f 100644 --- a/listener/sing_tun/server_windows.go +++ b/listener/sing_tun/server_windows.go @@ -8,11 +8,11 @@ import ( tun "github.com/metacubex/sing-tun" ) -func tunOpen(options tun.Options) (tunIf tun.Tun, err error) { +func tunNew(options tun.Options) (tunIf tun.Tun, err error) { maxRetry := 3 for i := 0; i < maxRetry; i++ { timeBegin := time.Now() - tunIf, err = tun.Open(options) + tunIf, err = tun.New(options) if err == nil { return } From ae966833a4066c10df803d1ff157fd0782407596 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 5 Mar 2023 11:00:14 +0800 Subject: [PATCH 055/530] chore: Generate UUID from fastrand --- adapter/outbound/base.go | 5 ++--- adapter/provider/healthcheck.go | 4 ++-- common/convert/util.go | 7 ++++--- common/utils/uuid.go | 11 +++++++++-- context/conn.go | 3 ++- context/dns.go | 3 ++- context/packetconn.go | 3 ++- go.mod | 1 + go.sum | 2 ++ transport/tuic/server.go | 9 +++++---- tunnel/statistic/tracker.go | 5 +++-- 11 files changed, 34 insertions(+), 19 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index d51655d8..b69311f6 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -8,10 +8,9 @@ import ( "strings" 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/gofrs/uuid" ) type Base struct { @@ -35,7 +34,7 @@ func (b *Base) Name() string { // Id implements C.ProxyAdapter func (b *Base) Id() string { if b.id == "" { - id, err := uuid.NewV6() + id, err := utils.UnsafeUUIDGenerator.NewV6() if err != nil { b.id = b.name } else { diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 16b9ad61..6f79cd05 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -6,10 +6,10 @@ import ( "github.com/Dreamacro/clash/common/batch" "github.com/Dreamacro/clash/common/singledo" + "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - "github.com/gofrs/uuid" "go.uber.org/atomic" ) @@ -77,7 +77,7 @@ func (hc *HealthCheck) touch() { func (hc *HealthCheck) check() { _, _, _ = hc.singleDo.Do(func() (struct{}, error) { id := "" - if uid, err := uuid.NewV4(); err == nil { + if uid, err := utils.UnsafeUUIDGenerator.NewV4(); err == nil { id = uid.String() } log.Debugln("Start New Health Checking {%s}", id) diff --git a/common/convert/util.go b/common/convert/util.go index 282d52d5..47e8d992 100644 --- a/common/convert/util.go +++ b/common/convert/util.go @@ -2,13 +2,14 @@ package convert import ( "encoding/base64" - "github.com/metacubex/sing-shadowsocks/shadowimpl" "math/rand" "net/http" "strings" "time" - "github.com/gofrs/uuid" + "github.com/Dreamacro/clash/common/utils" + + "github.com/metacubex/sing-shadowsocks/shadowimpl" ) var hostsSuffix = []string{ @@ -293,7 +294,7 @@ var ( ) func RandHost() string { - id, _ := uuid.NewV4() + id, _ := utils.UnsafeUUIDGenerator.NewV4() base := strings.ToLower(base64.RawURLEncoding.EncodeToString(id.Bytes())) base = strings.ReplaceAll(base, "-", "") base = strings.ReplaceAll(base, "_", "") diff --git a/common/utils/uuid.go b/common/utils/uuid.go index 66e176ed..d043ae37 100644 --- a/common/utils/uuid.go +++ b/common/utils/uuid.go @@ -2,15 +2,22 @@ package utils import ( "github.com/gofrs/uuid" + "github.com/zhangyunhao116/fastrand" ) -var uuidNamespace, _ = uuid.FromString("00000000-0000-0000-0000-000000000000") +type fastRandReader struct{} + +func (r fastRandReader) Read(p []byte) (int, error) { + return fastrand.Read(p) +} + +var UnsafeUUIDGenerator = uuid.NewGenWithOptions(uuid.WithRandomReader(fastRandReader{})) // UUIDMap https://github.com/XTLS/Xray-core/issues/158#issue-783294090 func UUIDMap(str string) (uuid.UUID, error) { u, err := uuid.FromString(str) if err != nil { - return uuid.NewV5(uuidNamespace, str), nil + return UnsafeUUIDGenerator.NewV5(uuid.Nil, str), nil } return u, nil } diff --git a/context/conn.go b/context/conn.go index b695ac4d..35ea788d 100644 --- a/context/conn.go +++ b/context/conn.go @@ -1,6 +1,7 @@ package context import ( + "github.com/Dreamacro/clash/common/utils" "net" N "github.com/Dreamacro/clash/common/net" @@ -16,7 +17,7 @@ type ConnContext struct { } func NewConnContext(conn net.Conn, metadata *C.Metadata) *ConnContext { - id, _ := uuid.NewV4() + id, _ := utils.UnsafeUUIDGenerator.NewV4() return &ConnContext{ id: id, diff --git a/context/dns.go b/context/dns.go index 59130961..80a4c988 100644 --- a/context/dns.go +++ b/context/dns.go @@ -2,6 +2,7 @@ package context import ( "context" + "github.com/Dreamacro/clash/common/utils" "github.com/gofrs/uuid" "github.com/miekg/dns" @@ -22,7 +23,7 @@ type DNSContext struct { } func NewDNSContext(ctx context.Context, msg *dns.Msg) *DNSContext { - id, _ := uuid.NewV4() + id, _ := utils.UnsafeUUIDGenerator.NewV4() return &DNSContext{ Context: ctx, diff --git a/context/packetconn.go b/context/packetconn.go index 3b005141..87a9290a 100644 --- a/context/packetconn.go +++ b/context/packetconn.go @@ -3,6 +3,7 @@ package context import ( "net" + "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/gofrs/uuid" @@ -15,7 +16,7 @@ type PacketConnContext struct { } func NewPacketConnContext(metadata *C.Metadata) *PacketConnContext { - id, _ := uuid.NewV4() + id, _ := utils.UnsafeUUIDGenerator.NewV4() return &PacketConnContext{ id: id, metadata: metadata, diff --git a/go.mod b/go.mod index 0b02e67d..1444da40 100644 --- a/go.mod +++ b/go.mod @@ -36,6 +36,7 @@ require ( github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.1 github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 + github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.6 go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 diff --git a/go.sum b/go.sum index d2aae570..7774aa64 100644 --- a/go.sum +++ b/go.sum @@ -162,6 +162,8 @@ github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1 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/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= +github.com/zhangyunhao116/fastrand v0.3.0/go.mod h1:0v5KgHho0VE6HU192HnY15de/oDS8UrbBChIFjIhBtc= 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.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk= diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 2830b324..e8dee8d6 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -11,13 +11,14 @@ import ( "sync/atomic" "time" - "github.com/gofrs/uuid" - "github.com/metacubex/quic-go" - 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/gofrs/uuid" + "github.com/metacubex/quic-go" ) type ServerOption struct { @@ -55,7 +56,7 @@ func (s *Server) Serve() error { return err } SetCongestionController(conn, s.CongestionController) - uuid, err := uuid.NewV4() + uuid, err := utils.UnsafeUUIDGenerator.NewV4() if err != nil { return err } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index e21868c5..bb5678b8 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -6,6 +6,7 @@ import ( "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/gofrs/uuid" @@ -82,7 +83,7 @@ func (tt *tcpTracker) Upstream() any { } func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64) *tcpTracker { - uuid, _ := uuid.NewV4() + uuid, _ := utils.UnsafeUUIDGenerator.NewV4() if conn != nil { if tcpAddr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { metadata.RemoteDst = tcpAddr.IP.String() @@ -148,7 +149,7 @@ func (ut *udpTracker) Close() error { } func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64) *udpTracker { - uuid, _ := uuid.NewV4() + uuid, _ := utils.UnsafeUUIDGenerator.NewV4() metadata.RemoteDst = conn.RemoteDestination() ut := &udpTracker{ From 2f36c9d66dd2ddd458e99fcb2953b9c0da02078b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 6 Mar 2023 00:49:34 +0800 Subject: [PATCH 056/530] chore: better workflow --- .github/workflows/build.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 537c7d14..dc43a10e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,6 +16,11 @@ on: - Alpha - Beta - Meta + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + env: REGISTRY: docker.io jobs: From ad6336231ccc98cf0fdbcaedf88d5585439054a4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 6 Mar 2023 12:59:53 +0800 Subject: [PATCH 057/530] doc: update config.yaml --- docs/config.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/config.yaml b/docs/config.yaml index 438875d2..13c5a83c 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -550,6 +550,8 @@ proxies: # socks5 public-key: Cr8hWlKvtDt7nrvf+f0brNQQzabAqrjfBvas9pmowjo= udp: true reserved: "U4An" + # 数组格式也是合法的 + # reserved: [209,98,59] # tuic - name: tuic From 6a97ab9ecb83cfb84e35167cd92b90a5c63c54c2 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 6 Mar 2023 18:10:14 +0800 Subject: [PATCH 058/530] chore: use fastrand to replace math/rand --- common/convert/util.go | 6 +++--- common/pool/alloc_test.go | 4 ++-- component/resolver/resolver.go | 8 ++++---- dns/client.go | 4 ++-- dns/resolver.go | 8 ++++---- transport/hysteria/conns/udp/hop.go | 7 ++++--- transport/hysteria/conns/wechat/obfs.go | 10 ++++++---- transport/hysteria/core/client.go | 12 ++++++------ transport/hysteria/obfs/xplus.go | 17 +++++------------ transport/simple-obfs/http.go | 7 ++++--- transport/simple-obfs/tls.go | 11 ++++------- transport/ssr/obfs/http_simple.go | 11 ++++++----- transport/ssr/obfs/random_head.go | 7 ++++--- transport/ssr/obfs/tls1.2_ticket_auth.go | 11 ++++++----- transport/ssr/protocol/auth_aes128_sha1.go | 17 +++++++++-------- transport/ssr/protocol/auth_sha1_v4.go | 7 ++++--- transport/ssr/protocol/base.go | 7 ++++--- transport/ssr/protocol/protocol.go | 5 +++-- transport/tuic/client.go | 8 ++++---- transport/tuic/congestion/bbr_sender.go | 4 ++-- transport/vless/vision.go | 11 +++++------ transport/vmess/conn.go | 12 ++++-------- transport/vmess/h2.go | 4 ++-- transport/vmess/http.go | 9 +++++---- transport/vmess/vmess.go | 7 ++++--- transport/vmess/websocket.go | 6 +++--- 26 files changed, 109 insertions(+), 111 deletions(-) diff --git a/common/convert/util.go b/common/convert/util.go index 47e8d992..4f86e616 100644 --- a/common/convert/util.go +++ b/common/convert/util.go @@ -2,7 +2,6 @@ package convert import ( "encoding/base64" - "math/rand" "net/http" "strings" "time" @@ -10,6 +9,7 @@ import ( "github.com/Dreamacro/clash/common/utils" "github.com/metacubex/sing-shadowsocks/shadowimpl" + "github.com/zhangyunhao116/fastrand" ) var hostsSuffix = []string{ @@ -303,11 +303,11 @@ func RandHost() string { prefix += string(buf[6:8]) + "-" prefix += string(buf[len(buf)-8:]) - return prefix + hostsSuffix[rand.Intn(hostsLen)] + return prefix + hostsSuffix[fastrand.Intn(hostsLen)] } func RandUserAgent() string { - return userAgents[rand.Intn(uaLen)] + return userAgents[fastrand.Intn(uaLen)] } func SetUserAgent(header http.Header) { diff --git a/common/pool/alloc_test.go b/common/pool/alloc_test.go index 3d063315..30aa5c53 100644 --- a/common/pool/alloc_test.go +++ b/common/pool/alloc_test.go @@ -1,10 +1,10 @@ package pool import ( - "math/rand" "testing" "github.com/stretchr/testify/assert" + "github.com/zhangyunhao116/fastrand" ) func TestAllocGet(t *testing.T) { @@ -43,6 +43,6 @@ func TestAllocPutThenGet(t *testing.T) { func BenchmarkMSB(b *testing.B) { for i := 0; i < b.N; i++ { - msb(rand.Int()) + msb(fastrand.Int()) } } diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index fa1e7c02..3fd53527 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "math/rand" "net" "net/netip" "strings" @@ -13,6 +12,7 @@ import ( "github.com/Dreamacro/clash/component/trie" "github.com/miekg/dns" + "github.com/zhangyunhao116/fastrand" ) var ( @@ -96,7 +96,7 @@ func ResolveIPv4WithResolver(ctx context.Context, host string, r Resolver) (neti } else if len(ips) == 0 { return netip.Addr{}, fmt.Errorf("%w: %s", ErrIPNotFound, host) } - return ips[rand.Intn(len(ips))], nil + return ips[fastrand.Intn(len(ips))], nil } // ResolveIPv4 with a host, return ipv4 @@ -153,7 +153,7 @@ func ResolveIPv6WithResolver(ctx context.Context, host string, r Resolver) (neti } else if len(ips) == 0 { return netip.Addr{}, fmt.Errorf("%w: %s", ErrIPNotFound, host) } - return ips[rand.Intn(len(ips))], nil + return ips[fastrand.Intn(len(ips))], nil } func ResolveIPv6(ctx context.Context, host string) (netip.Addr, error) { @@ -202,7 +202,7 @@ func ResolveIPWithResolver(ctx context.Context, host string, r Resolver) (netip. } else if len(ips) == 0 { return netip.Addr{}, fmt.Errorf("%w: %s", ErrIPNotFound, host) } - return ips[rand.Intn(len(ips))], nil + return ips[fastrand.Intn(len(ips))], nil } // ResolveIP with a host, return ip diff --git a/dns/client.go b/dns/client.go index c5a52281..936a5882 100644 --- a/dns/client.go +++ b/dns/client.go @@ -4,7 +4,6 @@ import ( "context" "crypto/tls" "fmt" - "math/rand" "net" "net/netip" "strings" @@ -16,6 +15,7 @@ import ( "github.com/Dreamacro/clash/component/resolver" D "github.com/miekg/dns" + "github.com/zhangyunhao116/fastrand" ) type client struct { @@ -68,7 +68,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) } else if len(ips) == 0 { return nil, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, c.host) } - ip = ips[rand.Intn(len(ips))] + ip = ips[fastrand.Intn(len(ips))] } network := "udp" diff --git a/dns/resolver.go b/dns/resolver.go index ac8917ca..59b1ee06 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "math/rand" "net/netip" "strings" "time" @@ -20,6 +19,7 @@ import ( "github.com/Dreamacro/clash/log" D "github.com/miekg/dns" + "github.com/zhangyunhao116/fastrand" "golang.org/x/sync/singleflight" ) @@ -113,7 +113,7 @@ func (r *Resolver) ResolveIP(ctx context.Context, host string) (ip netip.Addr, e } else if len(ips) == 0 { return netip.Addr{}, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host) } - return ips[rand.Intn(len(ips))], nil + return ips[fastrand.Intn(len(ips))], nil } // LookupIPv4 request with TypeA @@ -129,7 +129,7 @@ func (r *Resolver) ResolveIPv4(ctx context.Context, host string) (ip netip.Addr, } else if len(ips) == 0 { return netip.Addr{}, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host) } - return ips[rand.Intn(len(ips))], nil + return ips[fastrand.Intn(len(ips))], nil } // LookupIPv6 request with TypeAAAA @@ -145,7 +145,7 @@ func (r *Resolver) ResolveIPv6(ctx context.Context, host string) (ip netip.Addr, } else if len(ips) == 0 { return netip.Addr{}, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host) } - return ips[rand.Intn(len(ips))], nil + return ips[fastrand.Intn(len(ips))], nil } func (r *Resolver) shouldIPFallback(ip netip.Addr) bool { diff --git a/transport/hysteria/conns/udp/hop.go b/transport/hysteria/conns/udp/hop.go index 53830ae4..447a7592 100644 --- a/transport/hysteria/conns/udp/hop.go +++ b/transport/hysteria/conns/udp/hop.go @@ -2,7 +2,6 @@ package udp import ( "errors" - "math/rand" "net" "strconv" "strings" @@ -12,6 +11,8 @@ import ( "github.com/Dreamacro/clash/transport/hysteria/obfs" "github.com/Dreamacro/clash/transport/hysteria/utils" + + "github.com/zhangyunhao116/fastrand" ) const ( @@ -85,7 +86,7 @@ func NewObfsUDPHopClientPacketConn(server string, serverPorts string, hopInterva serverAddrs: serverAddrs, hopInterval: hopInterval, obfs: obfs, - addrIndex: rand.Intn(len(serverAddrs)), + addrIndex: fastrand.Intn(len(serverAddrs)), recvQueue: make(chan *udpPacket, packetQueueSize), closeChan: make(chan struct{}), bufPool: sync.Pool{ @@ -176,7 +177,7 @@ func (c *ObfsUDPHopClientPacketConn) hop(dialer utils.PacketDialer, rAddr net.Ad _ = trySetPacketConnWriteBuffer(c.currentConn, c.writeBufferSize) } go c.recvRoutine(c.currentConn) - c.addrIndex = rand.Intn(len(c.serverAddrs)) + c.addrIndex = fastrand.Intn(len(c.serverAddrs)) } func (c *ObfsUDPHopClientPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { diff --git a/transport/hysteria/conns/wechat/obfs.go b/transport/hysteria/conns/wechat/obfs.go index 815aa52f..d13cca55 100644 --- a/transport/hysteria/conns/wechat/obfs.go +++ b/transport/hysteria/conns/wechat/obfs.go @@ -2,12 +2,14 @@ package wechat import ( "encoding/binary" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/hysteria/obfs" - "math/rand" "net" "sync" "time" + + "github.com/Dreamacro/clash/log" + "github.com/Dreamacro/clash/transport/hysteria/obfs" + + "github.com/zhangyunhao116/fastrand" ) const udpBufferSize = 65535 @@ -29,7 +31,7 @@ func NewObfsWeChatUDPConn(orig net.PacketConn, obfs obfs.Obfuscator) *ObfsWeChat obfs: obfs, readBuf: make([]byte, udpBufferSize), writeBuf: make([]byte, udpBufferSize), - sn: rand.Uint32() & 0xFFFF, + sn: fastrand.Uint32() & 0xFFFF, } } diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index 1df14242..e0f3a0dd 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -6,20 +6,20 @@ import ( "crypto/tls" "errors" "fmt" - "math/rand" "net" "strconv" "sync" "time" - "github.com/lunixbochs/struc" - "github.com/metacubex/quic-go" - "github.com/metacubex/quic-go/congestion" - "github.com/Dreamacro/clash/transport/hysteria/obfs" "github.com/Dreamacro/clash/transport/hysteria/pmtud_fix" "github.com/Dreamacro/clash/transport/hysteria/transport" "github.com/Dreamacro/clash/transport/hysteria/utils" + + "github.com/lunixbochs/struc" + "github.com/metacubex/quic-go" + "github.com/metacubex/quic-go/congestion" + "github.com/zhangyunhao116/fastrand" ) var ( @@ -408,7 +408,7 @@ func (c *quicPktConn) WriteTo(p []byte, addr string) error { if err != nil { if errSize, ok := err.(quic.ErrMessageTooLarge); ok { // need to frag - msg.MsgID = uint16(rand.Intn(0xFFFF)) + 1 // msgID must be > 0 when fragCount > 1 + msg.MsgID = uint16(fastrand.Intn(0xFFFF)) + 1 // msgID must be > 0 when fragCount > 1 fragMsgs := fragUDPMessage(msg, int(errSize)) for _, fragMsg := range fragMsgs { msgBuf.Reset() diff --git a/transport/hysteria/obfs/xplus.go b/transport/hysteria/obfs/xplus.go index dd636452..171bf281 100644 --- a/transport/hysteria/obfs/xplus.go +++ b/transport/hysteria/obfs/xplus.go @@ -2,9 +2,8 @@ package obfs import ( "crypto/sha256" - "math/rand" - "sync" - "time" + + "github.com/zhangyunhao116/fastrand" ) // [salt][obfuscated payload] @@ -12,16 +11,12 @@ import ( const saltLen = 16 type XPlusObfuscator struct { - Key []byte - RandSrc *rand.Rand - - lk sync.Mutex + Key []byte } func NewXPlusObfuscator(key []byte) *XPlusObfuscator { return &XPlusObfuscator{ - Key: key, - RandSrc: rand.New(rand.NewSource(time.Now().UnixNano())), + Key: key, } } @@ -40,9 +35,7 @@ func (x *XPlusObfuscator) Deobfuscate(in []byte, out []byte) int { } func (x *XPlusObfuscator) Obfuscate(in []byte, out []byte) int { - x.lk.Lock() - _, _ = x.RandSrc.Read(out[:saltLen]) // salt - x.lk.Unlock() + _, _ = fastrand.Read(out[:saltLen]) // salt // Obfuscate the payload key := sha256.Sum256(append(x.Key, out[:saltLen]...)) for i, c := range in { diff --git a/transport/simple-obfs/http.go b/transport/simple-obfs/http.go index a06bad23..80db34ba 100644 --- a/transport/simple-obfs/http.go +++ b/transport/simple-obfs/http.go @@ -5,11 +5,12 @@ import ( "encoding/base64" "fmt" "io" - "math/rand" "net" "net/http" "github.com/Dreamacro/clash/common/pool" + + "github.com/zhangyunhao116/fastrand" ) // HTTPObfs is shadowsocks http simple-obfs implementation @@ -63,9 +64,9 @@ func (ho *HTTPObfs) Read(b []byte) (int, error) { func (ho *HTTPObfs) Write(b []byte) (int, error) { if ho.firstRequest { randBytes := make([]byte, 16) - rand.Read(randBytes) + fastrand.Read(randBytes) req, _ := http.NewRequest("GET", fmt.Sprintf("http://%s/", ho.host), bytes.NewBuffer(b[:])) - req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", rand.Int()%54, rand.Int()%2)) + req.Header.Set("User-Agent", fmt.Sprintf("curl/7.%d.%d", fastrand.Int()%54, fastrand.Int()%2)) req.Header.Set("Upgrade", "websocket") req.Header.Set("Connection", "Upgrade") req.Host = ho.host diff --git a/transport/simple-obfs/tls.go b/transport/simple-obfs/tls.go index fed8a483..f41e3263 100644 --- a/transport/simple-obfs/tls.go +++ b/transport/simple-obfs/tls.go @@ -4,16 +4,13 @@ import ( "bytes" "encoding/binary" "io" - "math/rand" "net" "time" "github.com/Dreamacro/clash/common/pool" -) -func init() { - rand.Seed(time.Now().Unix()) -} + "github.com/zhangyunhao116/fastrand" +) const ( chunkSize = 1 << 14 // 2 ** 14 == 16 * 1024 @@ -130,8 +127,8 @@ func NewTLSObfs(conn net.Conn, server string) net.Conn { func makeClientHelloMsg(data []byte, server string) []byte { random := make([]byte, 28) sessionID := make([]byte, 32) - rand.Read(random) - rand.Read(sessionID) + fastrand.Read(random) + fastrand.Read(sessionID) buf := &bytes.Buffer{} diff --git a/transport/ssr/obfs/http_simple.go b/transport/ssr/obfs/http_simple.go index c1ea7673..c91cca49 100644 --- a/transport/ssr/obfs/http_simple.go +++ b/transport/ssr/obfs/http_simple.go @@ -4,12 +4,13 @@ import ( "bytes" "encoding/hex" "io" - "math/rand" "net" "strconv" "strings" "github.com/Dreamacro/clash/common/pool" + + "github.com/zhangyunhao116/fastrand" ) func init() { @@ -81,7 +82,7 @@ func (c *httpConn) Write(b []byte) (int, error) { bLength := len(b) headDataLength := bLength if bLength-headLength > 64 { - headDataLength = headLength + rand.Intn(65) + headDataLength = headLength + fastrand.Intn(65) } headData := b[:headDataLength] b = b[headDataLength:] @@ -99,7 +100,7 @@ func (c *httpConn) Write(b []byte) (int, error) { } } hosts := strings.Split(host, ",") - host = hosts[rand.Intn(len(hosts))] + host = hosts[fastrand.Intn(len(hosts))] buf := pool.GetBuffer() defer pool.PutBuffer(buf) @@ -118,7 +119,7 @@ func (c *httpConn) Write(b []byte) (int, error) { buf.WriteString(body + "\r\n\r\n") } else { buf.WriteString("User-Agent: ") - buf.WriteString(userAgent[rand.Intn(len(userAgent))]) + buf.WriteString(userAgent[fastrand.Intn(len(userAgent))]) buf.WriteString("\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8\r\nAccept-Language: en-US,en;q=0.8\r\nAccept-Encoding: gzip, deflate\r\n") if c.post { packBoundary(buf) @@ -146,7 +147,7 @@ func packBoundary(buf *bytes.Buffer) { buf.WriteString("Content-Type: multipart/form-data; boundary=") set := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" for i := 0; i < 32; i++ { - buf.WriteByte(set[rand.Intn(62)]) + buf.WriteByte(set[fastrand.Intn(62)]) } buf.WriteString("\r\n") } diff --git a/transport/ssr/obfs/random_head.go b/transport/ssr/obfs/random_head.go index b10b01c5..4c55d951 100644 --- a/transport/ssr/obfs/random_head.go +++ b/transport/ssr/obfs/random_head.go @@ -3,10 +3,11 @@ package obfs import ( "encoding/binary" "hash/crc32" - "math/rand" "net" "github.com/Dreamacro/clash/common/pool" + + "github.com/zhangyunhao116/fastrand" ) func init() { @@ -53,10 +54,10 @@ func (c *randomHeadConn) Write(b []byte) (int, error) { c.buf = append(c.buf, b...) if !c.hasSentHeader { c.hasSentHeader = true - dataLength := rand.Intn(96) + 4 + dataLength := fastrand.Intn(96) + 4 buf := pool.Get(dataLength + 4) defer pool.Put(buf) - rand.Read(buf[:dataLength]) + fastrand.Read(buf[:dataLength]) binary.LittleEndian.PutUint32(buf[dataLength:], 0xffffffff-crc32.ChecksumIEEE(buf[:dataLength])) _, err := c.Conn.Write(buf) return len(b), err diff --git a/transport/ssr/obfs/tls1.2_ticket_auth.go b/transport/ssr/obfs/tls1.2_ticket_auth.go index 10f2786a..af945133 100644 --- a/transport/ssr/obfs/tls1.2_ticket_auth.go +++ b/transport/ssr/obfs/tls1.2_ticket_auth.go @@ -4,13 +4,14 @@ import ( "bytes" "crypto/hmac" "encoding/binary" - "math/rand" "net" "strings" "time" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/transport/ssr/tools" + + "github.com/zhangyunhao116/fastrand" ) func init() { @@ -25,7 +26,7 @@ type tls12Ticket struct { func newTLS12Ticket(b *Base) Obfs { r := &tls12Ticket{Base: b, authData: &authData{}} - rand.Read(r.clientID[:]) + fastrand.Read(r.clientID[:]) return r } @@ -90,7 +91,7 @@ func (c *tls12TicketConn) Write(b []byte) (int, error) { buf := pool.GetBuffer() defer pool.PutBuffer(buf) for len(b) > 2048 { - size := rand.Intn(4096) + 100 + size := fastrand.Intn(4096) + 100 if len(b) < size { size = len(b) } @@ -196,7 +197,7 @@ func packSNIData(buf *bytes.Buffer, u string) { } func (c *tls12TicketConn) packTicketBuf(buf *bytes.Buffer, u string) { - length := 16 * (rand.Intn(17) + 8) + length := 16 * (fastrand.Intn(17) + 8) buf.Write([]byte{0, 0x23}) binary.Write(buf, binary.BigEndian, uint16(length)) tools.AppendRandBytes(buf, length) @@ -221,6 +222,6 @@ func (t *tls12Ticket) getHost() string { host = "" } hosts := strings.Split(host, ",") - host = hosts[rand.Intn(len(hosts))] + host = hosts[fastrand.Intn(len(hosts))] return host } diff --git a/transport/ssr/protocol/auth_aes128_sha1.go b/transport/ssr/protocol/auth_aes128_sha1.go index 7b4da962..4de48151 100644 --- a/transport/ssr/protocol/auth_aes128_sha1.go +++ b/transport/ssr/protocol/auth_aes128_sha1.go @@ -4,7 +4,6 @@ import ( "bytes" "encoding/binary" "math" - "math/rand" "net" "strconv" "strings" @@ -12,6 +11,8 @@ import ( "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/ssr/tools" + + "github.com/zhangyunhao116/fastrand" ) type ( @@ -64,7 +65,7 @@ func (a *authAES128) initUserData() { } if len(a.userKey) == 0 { a.userKey = a.Key - rand.Read(a.userID[:]) + fastrand.Read(a.userID[:]) } } @@ -198,7 +199,7 @@ func (a *authAES128) packData(poolBuf *bytes.Buffer, data []byte, fullDataLength } func trapezoidRandom(max int, d float64) int { - base := rand.Float64() + base := fastrand.Float64() if d-0 > 1e-6 { a := 1 - d base = (math.Sqrt(a*a+4*d*base) - a) / (2 * d) @@ -219,10 +220,10 @@ func (a *authAES128) getRandDataLengthForPackData(dataLength, fullDataLength int if revLength > -1460 { return trapezoidRandom(revLength+1460, -0.3) } - return rand.Intn(32) + return fastrand.Intn(32) } if dataLength > 900 { - return rand.Intn(revLength) + return fastrand.Intn(revLength) } return trapezoidRandom(revLength, -0.3) } @@ -247,7 +248,7 @@ func (a *authAES128) packAuthData(poolBuf *bytes.Buffer, data []byte) { copy(macKey, a.iv) copy(macKey[len(a.iv):], a.Key) - poolBuf.WriteByte(byte(rand.Intn(256))) + poolBuf.WriteByte(byte(fastrand.Intn(256))) poolBuf.Write(a.hmac(macKey, poolBuf.Bytes())[:6]) poolBuf.Write(a.userID[:]) err := a.authData.putEncryptedData(poolBuf, a.userKey, [2]int{packedAuthDataLength, randDataLength}, a.salt) @@ -263,9 +264,9 @@ func (a *authAES128) packAuthData(poolBuf *bytes.Buffer, data []byte) { func (a *authAES128) getRandDataLengthForPackAuthData(size int) int { if size > 400 { - return rand.Intn(512) + return fastrand.Intn(512) } - return rand.Intn(1024) + return fastrand.Intn(1024) } func (a *authAES128) packRandData(poolBuf *bytes.Buffer, size int) { diff --git a/transport/ssr/protocol/auth_sha1_v4.go b/transport/ssr/protocol/auth_sha1_v4.go index 30392c9e..9e814ac2 100644 --- a/transport/ssr/protocol/auth_sha1_v4.go +++ b/transport/ssr/protocol/auth_sha1_v4.go @@ -5,11 +5,12 @@ import ( "encoding/binary" "hash/adler32" "hash/crc32" - "math/rand" "net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/transport/ssr/tools" + + "github.com/zhangyunhao116/fastrand" ) func init() { @@ -176,7 +177,7 @@ func (a *authSHA1V4) getRandDataLength(size int) int { return 0 } if size > 400 { - return rand.Intn(256) + return fastrand.Intn(256) } - return rand.Intn(512) + return fastrand.Intn(512) } diff --git a/transport/ssr/protocol/base.go b/transport/ssr/protocol/base.go index 4bf799b3..a826bec8 100644 --- a/transport/ssr/protocol/base.go +++ b/transport/ssr/protocol/base.go @@ -6,13 +6,14 @@ import ( "crypto/cipher" "encoding/base64" "encoding/binary" - "math/rand" "sync" "time" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/shadowsocks/core" + + "github.com/zhangyunhao116/fastrand" ) type Base struct { @@ -37,8 +38,8 @@ func (a *authData) next() *authData { a.mutex.Lock() defer a.mutex.Unlock() if a.connectionID > 0xff000000 || a.connectionID == 0 { - rand.Read(a.clientID[:]) - a.connectionID = rand.Uint32() & 0xffffff + fastrand.Read(a.clientID[:]) + a.connectionID = fastrand.Uint32() & 0xffffff } a.connectionID++ copy(r.clientID[:], a.clientID[:]) diff --git a/transport/ssr/protocol/protocol.go b/transport/ssr/protocol/protocol.go index 41bd984c..5b86ecb9 100644 --- a/transport/ssr/protocol/protocol.go +++ b/transport/ssr/protocol/protocol.go @@ -4,8 +4,9 @@ import ( "bytes" "errors" "fmt" - "math/rand" "net" + + "github.com/zhangyunhao116/fastrand" ) var ( @@ -68,7 +69,7 @@ func getHeadSize(b []byte, defaultValue int) int { func getDataLength(b []byte) int { bLength := len(b) - dataLength := getHeadSize(b, 30) + rand.Intn(32) + dataLength := getHeadSize(b, 30) + fastrand.Intn(32) if bLength < dataLength { return bLength } diff --git a/transport/tuic/client.go b/transport/tuic/client.go index d3f511df..4932dc9b 100644 --- a/transport/tuic/client.go +++ b/transport/tuic/client.go @@ -6,19 +6,19 @@ import ( "context" "crypto/tls" "errors" - "math/rand" "net" "runtime" "sync" "sync/atomic" "time" - "github.com/metacubex/quic-go" - 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/metacubex/quic-go" + "github.com/zhangyunhao116/fastrand" ) var ( @@ -352,7 +352,7 @@ func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Met pipe1, pipe2 := net.Pipe() var connId uint32 for { - connId = rand.Uint32() + connId = fastrand.Uint32() _, loaded := t.udpInputMap.LoadOrStore(connId, pipe1) if !loaded { break diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index 5adbd0b7..d848a9a8 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -5,11 +5,11 @@ package congestion import ( "fmt" "math" - "math/rand" "net" "time" "github.com/metacubex/quic-go/congestion" + "github.com/zhangyunhao116/fastrand" ) const ( @@ -780,7 +780,7 @@ func (b *bbrSender) EnterProbeBandwidthMode(now time.Time) { // Pick a random offset for the gain cycle out of {0, 2..7} range. 1 is // excluded because in that case increased gain and decreased gain would not // follow each other. - b.cycleCurrentOffset = rand.Int() % (GainCycleLength - 1) + b.cycleCurrentOffset = fastrand.Int() % (GainCycleLength - 1) if b.cycleCurrentOffset >= 1 { b.cycleCurrentOffset += 1 } diff --git a/transport/vless/vision.go b/transport/vless/vision.go index 14d701b4..d817c912 100644 --- a/transport/vless/vision.go +++ b/transport/vless/vision.go @@ -3,12 +3,11 @@ package vless import ( "bytes" "encoding/binary" - "math/rand" - "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/log" "github.com/gofrs/uuid" + "github.com/zhangyunhao116/fastrand" ) const ( @@ -24,9 +23,9 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid var paddingLen int32 if contentLen < 900 && paddingTLS { log.Debugln("long padding") - paddingLen = rand.Int31n(500) + 900 - contentLen + paddingLen = fastrand.Int31n(500) + 900 - contentLen } else { - paddingLen = rand.Int31n(256) + paddingLen = fastrand.Int31n(256) } if paddingLen > buf.BufferSize-21-contentLen { paddingLen = buf.BufferSize - 21 - contentLen @@ -48,9 +47,9 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding var paddingLen int32 if contentLen < 900 && paddingTLS { log.Debugln("long padding") - paddingLen = rand.Int31n(500) + 900 - contentLen + paddingLen = fastrand.Int31n(500) + 900 - contentLen } else { - paddingLen = rand.Int31n(256) + paddingLen = fastrand.Int31n(256) } if paddingLen > buf.BufferSize-21-contentLen { paddingLen = buf.BufferSize - 21 - contentLen diff --git a/transport/vmess/conn.go b/transport/vmess/conn.go index cc3155ee..292137ab 100644 --- a/transport/vmess/conn.go +++ b/transport/vmess/conn.go @@ -11,17 +11,13 @@ import ( "errors" "hash/fnv" "io" - "math/rand" "net" "time" + "github.com/zhangyunhao116/fastrand" "golang.org/x/crypto/chacha20poly1305" ) -func init() { - rand.Seed(time.Now().UnixNano()) -} - // Conn wrapper a net.Conn with vmess protocol type Conn struct { net.Conn @@ -76,7 +72,7 @@ func (vc *Conn) sendRequest() error { buf.WriteByte(vc.respV) buf.WriteByte(OptionChunkStream) - p := rand.Intn(16) + p := fastrand.Intn(16) // P Sec Reserve Cmd buf.WriteByte(byte(p<<4) | byte(vc.security)) buf.WriteByte(0) @@ -94,7 +90,7 @@ func (vc *Conn) sendRequest() error { // padding if p > 0 { padding := make([]byte, p) - rand.Read(padding) + fastrand.Read(padding) buf.Write(padding) } @@ -200,7 +196,7 @@ func hashTimestamp(t time.Time) []byte { // newConn return a Conn instance func newConn(conn net.Conn, id *ID, dst *DstAddr, security Security, isAead bool) (*Conn, error) { randBytes := make([]byte, 33) - rand.Read(randBytes) + fastrand.Read(randBytes) reqBodyIV := make([]byte, 16) reqBodyKey := make([]byte, 16) copy(reqBodyIV[:], randBytes[:16]) diff --git a/transport/vmess/h2.go b/transport/vmess/h2.go index d4e81607..6901f61e 100644 --- a/transport/vmess/h2.go +++ b/transport/vmess/h2.go @@ -2,11 +2,11 @@ package vmess import ( "io" - "math/rand" "net" "net/http" "net/url" + "github.com/zhangyunhao116/fastrand" "golang.org/x/net/http2" ) @@ -26,7 +26,7 @@ type H2Config struct { func (hc *h2Conn) establishConn() error { preader, pwriter := io.Pipe() - host := hc.cfg.Hosts[rand.Intn(len(hc.cfg.Hosts))] + host := hc.cfg.Hosts[fastrand.Intn(len(hc.cfg.Hosts))] path := hc.cfg.Path // TODO: connect use VMess Host instead of H2 Host req := http.Request{ diff --git a/transport/vmess/http.go b/transport/vmess/http.go index 1c09e215..c4f27c4c 100644 --- a/transport/vmess/http.go +++ b/transport/vmess/http.go @@ -4,10 +4,11 @@ import ( "bufio" "bytes" "fmt" - "math/rand" "net" "net/http" "net/textproto" + + "github.com/zhangyunhao116/fastrand" ) type httpConn struct { @@ -51,16 +52,16 @@ func (hc *httpConn) Write(b []byte) (int, error) { return hc.Conn.Write(b) } - path := hc.cfg.Path[rand.Intn(len(hc.cfg.Path))] + path := hc.cfg.Path[fastrand.Intn(len(hc.cfg.Path))] host := hc.cfg.Host if header := hc.cfg.Headers["Host"]; len(header) != 0 { - host = header[rand.Intn(len(header))] + host = header[fastrand.Intn(len(header))] } u := fmt.Sprintf("http://%s%s", host, path) req, _ := http.NewRequest("GET", u, bytes.NewBuffer(b)) for key, list := range hc.cfg.Headers { - req.Header.Set(key, list[rand.Intn(len(list))]) + req.Header.Set(key, list[fastrand.Intn(len(list))]) } req.ContentLength = int64(len(b)) if err := req.Write(hc.Conn); err != nil { diff --git a/transport/vmess/vmess.go b/transport/vmess/vmess.go index d7c8edb4..ee7ce121 100644 --- a/transport/vmess/vmess.go +++ b/transport/vmess/vmess.go @@ -2,12 +2,13 @@ package vmess import ( "fmt" - "github.com/Dreamacro/clash/common/utils" - "math/rand" "net" "runtime" + "github.com/Dreamacro/clash/common/utils" + "github.com/gofrs/uuid" + "github.com/zhangyunhao116/fastrand" ) // Version of vmess @@ -77,7 +78,7 @@ type Config struct { // StreamConn return a Conn with net.Conn and DstAddr func (c *Client) StreamConn(conn net.Conn, dst *DstAddr) (net.Conn, error) { - r := rand.Intn(len(c.user)) + r := fastrand.Intn(len(c.user)) return newConn(conn, c.user[r], dst, c.security, c.isAead) } diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index dfadb61a..5fcaa0b8 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -8,9 +8,7 @@ import ( "encoding/binary" "errors" "fmt" - "io" - "math/rand" "net" "net/http" "net/url" @@ -22,7 +20,9 @@ import ( "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/gorilla/websocket" + "github.com/zhangyunhao116/fastrand" ) type websocketConn struct { @@ -120,7 +120,7 @@ func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { binary.BigEndian.PutUint64(header[2:], uint64(dataLen)) } - maskKey := rand.Uint32() + maskKey := fastrand.Uint32() binary.LittleEndian.PutUint32(header[1+payloadBitLength:], maskKey) N.MaskWebSocket(maskKey, data) From 7c34964f878f6c0411067576b80c9492160f0d8c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 6 Mar 2023 19:15:12 +0800 Subject: [PATCH 059/530] fix: dns resolver --- component/resolver/resolver.go | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index 3fd53527..6ae2d7c2 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -69,10 +69,6 @@ func LookupIPv4WithResolver(ctx context.Context, host string, r Resolver) ([]net return r.LookupIPv4(ctx, host) } - if DefaultResolver != nil { - return DefaultResolver.LookupIPv4(ctx, host) - } - ipAddrs, err := net.DefaultResolver.LookupNetIP(ctx, "ip4", host) if err != nil { return nil, err @@ -126,9 +122,6 @@ func LookupIPv6WithResolver(ctx context.Context, host string, r Resolver) ([]net if r != nil { return r.LookupIPv6(ctx, host) } - if DefaultResolver != nil { - return DefaultResolver.LookupIPv6(ctx, host) - } ipAddrs, err := net.DefaultResolver.LookupNetIP(ctx, "ip6", host) if err != nil { @@ -172,7 +165,7 @@ func LookupIPWithResolver(ctx context.Context, host string, r Resolver) ([]netip } return r.LookupIP(ctx, host) } else if DisableIPv6 { - return LookupIPv4(ctx, host) + return LookupIPv4WithResolver(ctx, host, r) } if ip, err := netip.ParseAddr(host); err == nil { From 545a79d406515809690f6b111388188a3e46501b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 6 Mar 2023 23:23:05 +0800 Subject: [PATCH 060/530] chore: cleanup dialer's code --- component/dialer/dialer.go | 98 +++++++++++++------------------------- hub/executor/executor.go | 6 +-- hub/route/configs.go | 2 +- 3 files changed, 37 insertions(+), 69 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 478e9f19..f53435fb 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -13,6 +13,8 @@ import ( "github.com/Dreamacro/clash/component/resolver" ) +type dialFunc func(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) + var ( dialMux sync.Mutex actualSingleStackDialContext = serialSingleStackDialContext @@ -51,11 +53,16 @@ func DialContext(ctx context.Context, network, address string, options ...Option network = fmt.Sprintf("%s%d", network, opt.network) } + ips, port, err := parseAddr(ctx, network, address, opt.resolver) + if err != nil { + return nil, err + } + switch network { case "tcp4", "tcp6", "udp4", "udp6": - return actualSingleStackDialContext(ctx, network, address, opt) + return actualSingleStackDialContext(ctx, network, ips, port, opt) case "tcp", "udp": - return actualDualStackDialContext(ctx, network, address, opt) + return actualDualStackDialContext(ctx, network, ips, port, opt) default: return nil, ErrorInvalidedNetworkStack } @@ -82,8 +89,9 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio return lc.ListenPacket(ctx, network, address) } -func SetDial(concurrent bool) { +func SetTcpConcurrent(concurrent bool) { dialMux.Lock() + defer dialMux.Unlock() tcpConcurrent = concurrent if concurrent { actualSingleStackDialContext = concurrentSingleStackDialContext @@ -92,11 +100,11 @@ func SetDial(concurrent bool) { actualSingleStackDialContext = serialSingleStackDialContext actualDualStackDialContext = serialDualStackDialContext } - - dialMux.Unlock() } -func GetDial() bool { +func GetTcpConcurrent() bool { + dialMux.Lock() + defer dialMux.Unlock() return tcpConcurrent } @@ -118,71 +126,35 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po return dialer.DialContext(ctx, network, address) } -func serialSingleStackDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { - ips, port, err := parseAddr(ctx, network, address, opt.resolver) - if err != nil { - return nil, err - } +func serialSingleStackDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { return serialDialContext(ctx, network, ips, port, opt) } -func serialDualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { - ips, port, err := parseAddr(ctx, network, address, opt.resolver) - if err != nil { - return nil, err - } - ipv4s, ipv6s := sortationAddr(ips) - return dualStackDialContext( - ctx, - func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ipv4s, port, opt) }, - func(ctx context.Context) (net.Conn, error) { return serialDialContext(ctx, network, ipv6s, port, opt) }, - opt.prefer) +func serialDualStackDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { + return dualStackDialContext(ctx, serialDialContext, network, ips, port, opt) } -func concurrentSingleStackDialContext(ctx context.Context, network string, address string, opt *option) (net.Conn, error) { - ips, port, err := parseAddr(ctx, network, address, opt.resolver) - if err != nil { - return nil, err - } - - if conn, err := parallelDialContext(ctx, network, ips, port, opt); err != nil { - return nil, err - } else { - return conn, nil - } +func concurrentSingleStackDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { + return parallelDialContext(ctx, network, ips, port, opt) } -func concurrentDualStackDialContext(ctx context.Context, network, address string, opt *option) (net.Conn, error) { - ips, port, err := parseAddr(ctx, network, address, opt.resolver) - if err != nil { - return nil, err - } +func concurrentDualStackDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { if opt.prefer != 4 && opt.prefer != 6 { return parallelDialContext(ctx, network, ips, port, opt) } - ipv4s, ipv6s := sortationAddr(ips) - return dualStackDialContext( - ctx, - func(ctx context.Context) (net.Conn, error) { - return parallelDialContext(ctx, network, ipv4s, port, opt) - }, - func(ctx context.Context) (net.Conn, error) { - return parallelDialContext(ctx, network, ipv6s, port, opt) - }, - opt.prefer) + return dualStackDialContext(ctx, parallelDialContext, network, ips, port, opt) } -func dualStackDialContext( - ctx context.Context, - ipv4DialFn func(ctx context.Context) (net.Conn, error), - ipv6DialFn func(ctx context.Context) (net.Conn, error), - preferIPVersion int) (net.Conn, error) { +func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { + ipv4s, ipv6s := sortationAddr(ips) + preferIPVersion := opt.prefer + fallbackTicker := time.NewTicker(fallbackTimeout) defer fallbackTicker.Stop() results := make(chan dialResult) returned := make(chan struct{}) defer close(returned) - racer := func(dial func(ctx context.Context) (net.Conn, error), isPrimary bool) { + racer := func(ips []netip.Addr, isPrimary bool) { result := dialResult{isPrimary: isPrimary} defer func() { select { @@ -193,10 +165,10 @@ func dualStackDialContext( } } }() - result.Conn, result.error = dial(ctx) + result.Conn, result.error = dialFn(ctx, network, ips, port, opt) } - go racer(ipv4DialFn, preferIPVersion != 6) - go racer(ipv6DialFn, preferIPVersion != 4) + go racer(ipv4s, preferIPVersion != 6) + go racer(ipv6s, preferIPVersion != 4) var fallback dialResult var err error for { @@ -230,7 +202,7 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, results := make(chan dialResult) returned := make(chan struct{}) defer close(returned) - tcpRacer := func(ctx context.Context, ip netip.Addr, port string) { + racer := func(ctx context.Context, ip netip.Addr) { result := dialResult{isPrimary: true} defer func() { select { @@ -246,7 +218,7 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, } for _, ip := range ips { - go tcpRacer(ctx, ip, port) + go racer(ctx, ip) } var err error for { @@ -272,13 +244,9 @@ func serialDialContext(ctx context.Context, network string, ips []netip.Addr, po if len(ips) == 0 { return nil, ErrorNoIpAddress } - var ( - conn net.Conn - err error - errs []error - ) + var errs []error for _, ip := range ips { - if conn, err = dialContext(ctx, network, ip, port, opt); err == nil { + if conn, err := dialContext(ctx, network, ip, port, opt); err == nil { return conn, nil } else { errs = append(errs, err) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index c55201cd..d6ff7851 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -128,7 +128,7 @@ func GetGeneral() *config.General { GeodataLoader: G.LoaderName(), Interface: dialer.DefaultInterface.Load(), Sniffing: tunnel.IsSniffing(), - TCPConcurrent: dialer.GetDial(), + TCPConcurrent: dialer.GetTcpConcurrent(), } return general @@ -331,10 +331,10 @@ func updateTunnels(tunnels []LC.Tunnel) { func updateGeneral(general *config.General) { tunnel.SetMode(general.Mode) tunnel.SetFindProcessMode(general.FindProcessMode) - resolver.DisableIPv6 =!general.IPv6 + resolver.DisableIPv6 = !general.IPv6 if general.TCPConcurrent { - dialer.SetDial(general.TCPConcurrent) + dialer.SetTcpConcurrent(general.TCPConcurrent) log.Infoln("Use tcp concurrent") } diff --git a/hub/route/configs.go b/hub/route/configs.go index 9e630b29..50e3cd13 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -228,7 +228,7 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { } if general.TcpConcurrent != nil { - dialer.SetDial(*general.TcpConcurrent) + dialer.SetTcpConcurrent(*general.TcpConcurrent) } if general.InterfaceName != nil { From 9cc7fdaca9009d00abb41ee38f4eca0d70b6c45f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 7 Mar 2023 09:30:51 +0800 Subject: [PATCH 061/530] chore: wireguard using internal dialer --- adapter/outbound/wireguard.go | 42 ++++++++++++++++++++++------------- component/dialer/dialer.go | 24 ++++++++++++++------ component/dialer/options.go | 14 ++++++++++++ 3 files changed, 57 insertions(+), 23 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index e3dafbbf..e5d7cf3f 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -34,7 +34,7 @@ type WireGuard struct { bind *wireguard.ClientBind device *device.Device tunDevice wireguard.Device - dialer *wgDialer + dialer *wgSingDialer startOnce sync.Once startErr error } @@ -56,16 +56,28 @@ type WireGuardOption struct { PersistentKeepalive int `proxy:"persistent-keepalive,omitempty"` } -type wgDialer struct { - options []dialer.Option +type wgSingDialer struct { + dialer dialer.Dialer } -func (d *wgDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - return dialer.DialContext(ctx, network, destination.String(), d.options...) +var _ N.Dialer = &wgSingDialer{} + +func (d *wgSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + return d.dialer.DialContext(ctx, network, destination.String()) } -func (d *wgDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - return dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", destination.Addr), "", d.options...) +func (d *wgSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + return d.dialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) +} + +type wgNetDialer struct { + tunDevice wireguard.Device +} + +var _ dialer.NetDialer = &wgNetDialer{} + +func (d wgNetDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + return d.tunDevice.DialContext(ctx, network, M.ParseSocksaddr(address)) } func NewWireGuard(option WireGuardOption) (*WireGuard, error) { @@ -79,7 +91,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, - dialer: &wgDialer{}, + dialer: &wgSingDialer{dialer: dialer.NewDialer()}, } runtime.SetFinalizer(outbound, closeWireGuard) @@ -199,7 +211,8 @@ func closeWireGuard(w *WireGuard) { } func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { - w.dialer.options = opts + options := w.Base.DialOptions(opts...) + w.dialer.dialer = dialer.NewDialer(options...) var conn net.Conn w.startOnce.Do(func() { w.startErr = w.tunDevice.Start() @@ -208,12 +221,8 @@ func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts return nil, w.startErr } if !metadata.Resolved() { - var addrs []netip.Addr - addrs, err = resolver.LookupIP(ctx, metadata.Host) - if err != nil { - return nil, err - } - conn, err = N.DialSerial(ctx, w.tunDevice, "tcp", M.ParseSocksaddr(metadata.RemoteAddress()), addrs) + 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))) @@ -228,7 +237,8 @@ func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts } func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { - w.dialer.options = opts + options := w.Base.DialOptions(opts...) + w.dialer.dialer = dialer.NewDialer(options...) var pc net.PacketConn w.startOnce.Do(func() { w.startErr = w.tunDevice.Start() diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index f53435fb..025f7034 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -109,7 +109,19 @@ func GetTcpConcurrent() bool { } func dialContext(ctx context.Context, network string, destination netip.Addr, port string, opt *option) (net.Conn, error) { - dialer := &net.Dialer{} + address := net.JoinHostPort(destination.String(), port) + + netDialer := opt.netDialer + switch netDialer.(type) { + case nil: + netDialer = &net.Dialer{} + case *net.Dialer: + netDialer = &*netDialer.(*net.Dialer) // make a copy + default: + return netDialer.DialContext(ctx, network, address) + } + + dialer := netDialer.(*net.Dialer) if opt.interfaceName != "" { if err := bindIfaceToDialer(opt.interfaceName, dialer, network, destination); err != nil { return nil, err @@ -118,8 +130,6 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po if opt.routingMark != 0 { bindMarkToDialer(opt.routingMark, dialer, network, destination) } - - address := net.JoinHostPort(destination.String(), port) if opt.tfo { return dialTFO(ctx, *dialer, network, address) } @@ -307,15 +317,15 @@ func sortationAddr(ips []netip.Addr) (ipv4s, ipv6s []netip.Addr) { } type Dialer struct { - Opt option + opt option } func (d Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { - return DialContext(ctx, network, address, WithOption(d.Opt)) + return DialContext(ctx, network, address, WithOption(d.opt)) } func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { - opt := WithOption(d.Opt) + opt := WithOption(d.opt) if rAddrPort.Addr().Unmap().IsLoopback() { // avoid "The requested address is not valid in its context." opt = WithInterface("") @@ -325,5 +335,5 @@ func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddr func NewDialer(options ...Option) Dialer { opt := applyOptions(options...) - return Dialer{Opt: *opt} + return Dialer{opt: *opt} } diff --git a/component/dialer/options.go b/component/dialer/options.go index 1c4e7bfc..372a2e63 100644 --- a/component/dialer/options.go +++ b/component/dialer/options.go @@ -1,6 +1,9 @@ package dialer import ( + "context" + "net" + "github.com/Dreamacro/clash/component/resolver" "go.uber.org/atomic" @@ -12,6 +15,10 @@ var ( DefaultRoutingMark = atomic.NewInt32(0) ) +type NetDialer interface { + DialContext(ctx context.Context, network, address string) (net.Conn, error) +} + type option struct { interfaceName string addrReuse bool @@ -20,6 +27,7 @@ type option struct { prefer int tfo bool resolver resolver.Resolver + netDialer NetDialer } type Option func(opt *option) @@ -76,6 +84,12 @@ func WithTFO(tfo bool) Option { } } +func WithNetDialer(netDialer NetDialer) Option { + return func(opt *option) { + opt.netDialer = netDialer + } +} + func WithOption(o option) Option { return func(opt *option) { *opt = o From a0ad12c45b04c1fbceaeb3e5a9db8240ce8a6d53 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 7 Mar 2023 14:11:38 +0800 Subject: [PATCH 062/530] =?UTF-8?q?fix:=20sing-vmess=20listener=E2=80=98s?= =?UTF-8?q?=20"cipher:=20message=20authentication=20failed"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 1444da40..f8a2dc19 100644 --- a/go.mod +++ b/go.mod @@ -26,9 +26,9 @@ require ( github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a + github.com/sagernet/sing v0.1.8-0.20230307054559-0560a4da412b github.com/sagernet/sing-shadowtls v0.1.0 - github.com/sagernet/sing-vmess v0.1.3-0.20230303082804-627cc46ae68b + github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c diff --git a/go.sum b/go.sum index 7774aa64..d68126bf 100644 --- a/go.sum +++ b/go.sum @@ -127,12 +127,12 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a h1:NvhI/8DMFt2yV3eoYhw6P/XyWzzIKkMiGvFglJbWHWg= -github.com/sagernet/sing v0.1.8-0.20230303052048-c875a4ffab1a/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.1.8-0.20230307054559-0560a4da412b h1:wxqf3O+cLHm1ZWEQG1DRwApwLlTV/NLKGqF1kNCk3Ms= +github.com/sagernet/sing v0.1.8-0.20230307054559-0560a4da412b/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= -github.com/sagernet/sing-vmess v0.1.3-0.20230303082804-627cc46ae68b h1:NZeF0ATeJwe4W3gTJNeIfTB6yBxai665q1HvDOaWmmU= -github.com/sagernet/sing-vmess v0.1.3-0.20230303082804-627cc46ae68b/go.mod h1:9NSj8mZTx1JIY/HF9LaYRppUsVkysIN5tEFpNZujXxY= +github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc h1:vqlYWupvVDRpvv2F+RtECJN+VbuKjLtmQculQvOecls= +github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc/go.mod h1:V14iffGwhZPU2S7wgIiPlLWXygSjAXazYzD1w0ejBl4= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 h1:gDXi/0uYe8dA48UyUI1LM2la5QYN0IvsDvR2H2+kFnA= From 04ae812a1179433b8579ffde29b2ee6adaf75040 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 7 Mar 2023 15:52:50 +0800 Subject: [PATCH 063/530] chore: try to fix slice out of bound. --- transport/vless/vision.go | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/transport/vless/vision.go b/transport/vless/vision.go index d817c912..b80fbb71 100644 --- a/transport/vless/vision.go +++ b/transport/vless/vision.go @@ -3,6 +3,8 @@ package vless import ( "bytes" "encoding/binary" + "sync" + "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/log" @@ -18,18 +20,19 @@ const ( commandPaddingDirect byte = 0x02 ) +var mutex sync.RWMutex + func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID, paddingTLS bool) { contentLen := int32(len(p)) + mutex.Lock() var paddingLen int32 if contentLen < 900 && paddingTLS { - log.Debugln("long padding") + //log.Debugln("long padding") paddingLen = fastrand.Int31n(500) + 900 - contentLen } else { paddingLen = fastrand.Int31n(256) } - if paddingLen > buf.BufferSize-21-contentLen { - paddingLen = buf.BufferSize - 21 - contentLen - } + mutex.Unlock() if userUUID != nil { // unnecessary, but keep the same with Xray buffer.Write(userUUID.Bytes()) } @@ -38,28 +41,30 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid binary.BigEndian.PutUint16(buffer.Extend(2), uint16(contentLen)) binary.BigEndian.PutUint16(buffer.Extend(2), uint16(paddingLen)) buffer.Write(p) + buffer.Extend(int(paddingLen)) log.Debugln("XTLS Vision write padding1: command=%v, payloadLen=%v, paddingLen=%v", command, contentLen, paddingLen) } func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) { contentLen := int32(buffer.Len()) + mutex.Lock() var paddingLen int32 if contentLen < 900 && paddingTLS { - log.Debugln("long padding") + //log.Debugln("long padding") paddingLen = fastrand.Int31n(500) + 900 - contentLen } else { paddingLen = fastrand.Int31n(256) } - if paddingLen > buf.BufferSize-21-contentLen { - paddingLen = buf.BufferSize - 21 - contentLen - } + mutex.Unlock() + binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(paddingLen)) binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(contentLen)) buffer.ExtendHeader(1)[0] = command if userUUID != nil { // unnecessary, but keep the same with Xray copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes()) } + buffer.Extend(int(paddingLen)) log.Debugln("XTLS Vision write padding2: command=%d, payloadLen=%d, paddingLen=%d", command, contentLen, paddingLen) } From 6040803b60a0207c292fa3eb8d0b9cdb1ceac13a Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 7 Mar 2023 16:34:57 +0800 Subject: [PATCH 064/530] chore: do not apply padding for nonTLS packet with contentLen over 900 --- transport/vless/vision.go | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/transport/vless/vision.go b/transport/vless/vision.go index b80fbb71..857d9150 100644 --- a/transport/vless/vision.go +++ b/transport/vless/vision.go @@ -24,13 +24,15 @@ var mutex sync.RWMutex func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID, paddingTLS bool) { contentLen := int32(len(p)) - mutex.Lock() var paddingLen int32 - if contentLen < 900 && paddingTLS { - //log.Debugln("long padding") - paddingLen = fastrand.Int31n(500) + 900 - contentLen - } else { - paddingLen = fastrand.Int31n(256) + mutex.Lock() + if contentLen < 900 { + if paddingTLS { + //log.Debugln("long padding") + paddingLen = fastrand.Int31n(500) + 900 - contentLen + } else { + paddingLen = fastrand.Int31n(256) + } } mutex.Unlock() if userUUID != nil { // unnecessary, but keep the same with Xray @@ -48,13 +50,15 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) { contentLen := int32(buffer.Len()) - mutex.Lock() var paddingLen int32 - if contentLen < 900 && paddingTLS { - //log.Debugln("long padding") - paddingLen = fastrand.Int31n(500) + 900 - contentLen - } else { - paddingLen = fastrand.Int31n(256) + mutex.Lock() + if contentLen < 900 { + if paddingTLS { + //log.Debugln("long padding") + paddingLen = fastrand.Int31n(500) + 900 - contentLen + } else { + paddingLen = fastrand.Int31n(256) + } } mutex.Unlock() From 1e6f0f28f64f15cc56ffbb0194e7b8746285508f Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 8 Mar 2023 00:19:20 +0800 Subject: [PATCH 065/530] chore: change default geo* url --- config/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index 76e5491b..efb5b4cf 100644 --- a/config/config.go +++ b/config/config.go @@ -415,9 +415,9 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { StoreSelected: true, }, GeoXUrl: RawGeoXUrl{ - GeoIp: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geoip.dat", - Mmdb: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb", - GeoSite: "https://ghproxy.com/https://raw.githubusercontent.com/Loyalsoldier/v2ray-rules-dat/release/geosite.dat", + 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", }, } From 76a8fe38394457611d337d546cab5d6fe9606b22 Mon Sep 17 00:00:00 2001 From: H1JK Date: Wed, 8 Mar 2023 17:18:46 +0800 Subject: [PATCH 066/530] feat: Support REALITY protocol --- adapter/outbound/reality.go | 41 +++++++++ adapter/outbound/trojan.go | 37 ++++---- adapter/outbound/vless.go | 9 +- adapter/outbound/vmess.go | 59 +++++++------ component/tls/reality.go | 163 ++++++++++++++++++++++++++++++++++++ go.mod | 2 +- go.sum | 4 +- transport/trojan/trojan.go | 22 +++-- transport/vmess/tls.go | 24 ++++-- 9 files changed, 305 insertions(+), 56 deletions(-) create mode 100644 adapter/outbound/reality.go create mode 100644 component/tls/reality.go diff --git a/adapter/outbound/reality.go b/adapter/outbound/reality.go new file mode 100644 index 00000000..05f49d11 --- /dev/null +++ b/adapter/outbound/reality.go @@ -0,0 +1,41 @@ +package outbound + +import ( + "encoding/base64" + "encoding/hex" + "errors" + + tlsC "github.com/Dreamacro/clash/component/tls" + + "golang.org/x/crypto/curve25519" +) + +type RealityOptions struct { + ServerName string `proxy:"server-name"` + PublicKey string `proxy:"public-key"` + ShortID string `proxy:"short-id"` +} + +func (o RealityOptions) Parse() (*tlsC.RealityConfig, error) { + if o.PublicKey != "" || o.ServerName != "" { + if o.PublicKey != "" && o.ServerName != "" { + config := new(tlsC.RealityConfig) + + n, err := base64.RawURLEncoding.Decode(config.PublicKey[:], []byte(o.PublicKey)) + if err != nil || n != curve25519.ScalarSize { + return nil, errors.New("invalid REALITY public key") + } + + config.ShortID, err = hex.DecodeString(o.ShortID) + if err != nil { + return nil, errors.New("invalid REALITY short ID") + } + + config.ServerName = o.ServerName + + return config, nil + } + return nil, errors.New("invalid REALITY protocol option") + } + return nil, nil +} diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index beedd614..d36bd40c 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -30,21 +30,22 @@ type Trojan struct { type TrojanOption struct { BasicOption - Name string `proxy:"name"` - Server string `proxy:"server"` - Port int `proxy:"port"` - Password string `proxy:"password"` - ALPN []string `proxy:"alpn,omitempty"` - SNI string `proxy:"sni,omitempty"` - SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` - Fingerprint string `proxy:"fingerprint,omitempty"` - UDP bool `proxy:"udp,omitempty"` - Network string `proxy:"network,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"` + Name string `proxy:"name"` + Server string `proxy:"server"` + Port int `proxy:"port"` + Password string `proxy:"password"` + ALPN []string `proxy:"alpn,omitempty"` + SNI string `proxy:"sni,omitempty"` + SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` + Fingerprint string `proxy:"fingerprint,omitempty"` + UDP bool `proxy:"udp,omitempty"` + Network string `proxy:"network,omitempty"` + 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"` } func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) { @@ -244,6 +245,12 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { tOption.ServerName = option.SNI } + var err error + tOption.Reality, err = option.RealityOpts.Parse() + if err != nil { + return nil, err + } + t := &Trojan{ Base: &Base{ name: option.Name, diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 010af23c..435beee9 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -41,6 +41,8 @@ type Vless struct { gunTLSConfig *tls.Config gunConfig *gun.Config transport *gun.TransportWrap + + realityConfig *tlsC.RealityConfig } type VlessOption struct { @@ -57,6 +59,7 @@ type VlessOption struct { XUDP bool `proxy:"xudp,omitempty"` PacketEncoding string `proxy:"packet-encoding,omitempty"` Network string `proxy:"network,omitempty"` + RealityOpts RealityOptions `proxy:"reality-opts,omitempty"` HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"` HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"` GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` @@ -78,7 +81,6 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { switch v.option.Network { case "ws": - host, port, _ := net.SplitHostPort(v.addr) wsOpts := &vmess.WebsocketConfig{ Host: host, @@ -190,6 +192,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) SkipCertVerify: v.option.SkipCertVerify, FingerPrint: v.option.Fingerprint, ClientFingerprint: v.option.ClientFingerprint, + Reality: v.realityConfig, } if isH2 { @@ -554,7 +557,11 @@ func NewVless(option VlessOption) (*Vless, error) { v.gunConfig = gunConfig v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint) + } + v.realityConfig, err = v.option.RealityOpts.Parse() + if err != nil { + return nil, err } return v, nil diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 25ffebf3..f9e7205b 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -35,32 +35,35 @@ type Vmess struct { gunTLSConfig *tls.Config gunConfig *gun.Config transport *gun.TransportWrap + + realityConfig *tlsC.RealityConfig } type VmessOption struct { BasicOption - Name string `proxy:"name"` - Server string `proxy:"server"` - Port int `proxy:"port"` - UUID string `proxy:"uuid"` - AlterID int `proxy:"alterId"` - Cipher string `proxy:"cipher"` - UDP bool `proxy:"udp,omitempty"` - Network string `proxy:"network,omitempty"` - TLS bool `proxy:"tls,omitempty"` - SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` - Fingerprint string `proxy:"fingerprint,omitempty"` - ServerName string `proxy:"servername,omitempty"` - HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"` - HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"` - GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` - WSOpts WSOptions `proxy:"ws-opts,omitempty"` - PacketAddr bool `proxy:"packet-addr,omitempty"` - XUDP bool `proxy:"xudp,omitempty"` - PacketEncoding string `proxy:"packet-encoding,omitempty"` - GlobalPadding bool `proxy:"global-padding,omitempty"` - AuthenticatedLength bool `proxy:"authenticated-length,omitempty"` - ClientFingerprint string `proxy:"client-fingerprint,omitempty"` + Name string `proxy:"name"` + Server string `proxy:"server"` + Port int `proxy:"port"` + UUID string `proxy:"uuid"` + AlterID int `proxy:"alterId"` + Cipher string `proxy:"cipher"` + UDP bool `proxy:"udp,omitempty"` + Network string `proxy:"network,omitempty"` + TLS bool `proxy:"tls,omitempty"` + SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` + Fingerprint string `proxy:"fingerprint,omitempty"` + ServerName string `proxy:"servername,omitempty"` + RealityOpts RealityOptions `proxy:"reality-opts,omitempty"` + HTTPOpts HTTPOptions `proxy:"http-opts,omitempty"` + HTTP2Opts HTTP2Options `proxy:"h2-opts,omitempty"` + GrpcOpts GrpcOptions `proxy:"grpc-opts,omitempty"` + WSOpts WSOptions `proxy:"ws-opts,omitempty"` + PacketAddr bool `proxy:"packet-addr,omitempty"` + XUDP bool `proxy:"xudp,omitempty"` + PacketEncoding string `proxy:"packet-encoding,omitempty"` + GlobalPadding bool `proxy:"global-padding,omitempty"` + AuthenticatedLength bool `proxy:"authenticated-length,omitempty"` + ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } type HTTPOptions struct { @@ -95,7 +98,6 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { switch v.option.Network { case "ws": - host, port, _ := net.SplitHostPort(v.addr) wsOpts := &clashVMess.WebsocketConfig{ Host: host, @@ -144,12 +146,12 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { Host: host, SkipCertVerify: v.option.SkipCertVerify, ClientFingerprint: v.option.ClientFingerprint, + Reality: v.realityConfig, } if v.option.ServerName != "" { tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(c, tlsOpts) if err != nil { return nil, err @@ -172,6 +174,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { SkipCertVerify: v.option.SkipCertVerify, NextProtos: []string{"h2"}, ClientFingerprint: v.option.ClientFingerprint, + Reality: v.realityConfig, } if v.option.ServerName != "" { @@ -199,6 +202,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { Host: host, SkipCertVerify: v.option.SkipCertVerify, ClientFingerprint: v.option.ClientFingerprint, + Reality: v.realityConfig, } if v.option.ServerName != "" { @@ -452,8 +456,13 @@ func NewVmess(option VmessOption) (*Vmess, error) { v.gunConfig = gunConfig v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint) - } + + v.realityConfig, err = v.option.RealityOpts.Parse() + if err != nil { + return nil, err + } + return v, nil } diff --git a/component/tls/reality.go b/component/tls/reality.go new file mode 100644 index 00000000..cdad690f --- /dev/null +++ b/component/tls/reality.go @@ -0,0 +1,163 @@ +package tls + +import ( + "bytes" + "context" + "crypto/aes" + "crypto/cipher" + "crypto/ed25519" + "crypto/hmac" + "crypto/sha256" + "crypto/sha512" + "crypto/tls" + "crypto/x509" + "encoding/binary" + "errors" + "net" + "net/http" + "reflect" + "strings" + "time" + "unsafe" + + "github.com/Dreamacro/clash/log" + + utls "github.com/sagernet/utls" + "github.com/zhangyunhao116/fastrand" + "golang.org/x/crypto/curve25519" + "golang.org/x/crypto/hkdf" + "golang.org/x/net/http2" +) + +type RealityConfig struct { + ServerName string + PublicKey [curve25519.ScalarSize]byte + ShortID []byte +} + +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{ + serverName: realityConfig.ServerName, + } + uConfig := copyConfig(tlsConfig) + uConfig.ServerName = realityConfig.ServerName + uConfig.InsecureSkipVerify = true + uConfig.SessionTicketsDisabled = true + uConfig.VerifyPeerCertificate = verifier.VerifyPeerCertificate + clientID := utls.ClientHelloID{ + Client: fingerprint.Client, + Version: fingerprint.Version, + Seed: fingerprint.Seed, + } + uConn := utls.UClient(conn, uConfig, clientID) + verifier.UConn = uConn + err := uConn.BuildHandshakeState() + if err != nil { + return nil, err + } + + hello := uConn.HandshakeState.Hello + hello.SessionId = make([]byte, 32) + copy(hello.Raw[39:], hello.SessionId) + + var nowTime time.Time + if uConfig.Time != nil { + nowTime = uConfig.Time() + } else { + nowTime = time.Now() + } + binary.BigEndian.PutUint64(hello.SessionId, uint64(nowTime.Unix())) + + hello.SessionId[0] = 1 + hello.SessionId[1] = 7 + hello.SessionId[2] = 5 + copy(hello.SessionId[8:], realityConfig.ShortID) + + //log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16]) + + authKey := uConn.HandshakeState.State13.EcdheParams.SharedKey(realityConfig.PublicKey[:]) + if authKey == nil { + return nil, errors.New("nil auth_key") + } + verifier.authKey = authKey + _, err = hkdf.New(sha256.New, authKey, hello.Random[:20], []byte("REALITY")).Read(authKey) + 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) + copy(hello.Raw[39:], hello.SessionId) + //log.Debugln("REALITY hello.sessionId: %v", hello.SessionId) + //log.Debugln("REALITY uConn.AuthKey: %v", authKey) + + err = uConn.HandshakeContext(ctx) + if err != nil { + return nil, err + } + + log.Debugln("REALITY Authentication: %v", verifier.verified) + + if !verifier.verified { + go realityClientFallback(uConn, uConfig.ServerName, clientID) + return nil, errors.New("REALITY authentication failed") + } + + return uConn, nil + } + return nil, errors.New("unknown uTLS fingerprint") +} + +func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) { + defer uConn.Close() + client := &http.Client{ + Transport: &http2.Transport{ + DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) { + return uConn, nil + }, + }, + } + request, _ := http.NewRequest("GET", "https://"+serverName, nil) + request.Header.Set("User-Agent", fingerprint.Client) + request.AddCookie(&http.Cookie{Name: "padding", Value: strings.Repeat("0", fastrand.Intn(32)+30)}) + response, err := client.Do(request) + if err != nil { + return + } + //_, _ = io.Copy(io.Discard, response.Body) + time.Sleep(time.Duration(5 + fastrand.Int63n(10))) + response.Body.Close() + client.CloseIdleConnections() +} + +type realityVerifier struct { + *utls.UConn + serverName string + authKey []byte + verified bool +} + +func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { + p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates") + certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset)) + if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok { + h := hmac.New(sha512.New, c.authKey) + h.Write(pub) + if bytes.Equal(h.Sum(nil), certs[0].Signature) { + c.verified = true + return nil + } + } + opts := x509.VerifyOptions{ + DNSName: c.serverName, + Intermediates: x509.NewCertPool(), + } + for _, cert := range certs[1:] { + opts.Intermediates.AddCert(cert) + } + if _, err := certs[0].Verify(opts); err != nil { + return err + } + return nil +} diff --git a/go.mod b/go.mod index f8a2dc19..21287160 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d - github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 + github.com/sagernet/utls v0.0.0-20230225061716-536a007c8b01 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index d68126bf..8c100900 100644 --- a/go.sum +++ b/go.sum @@ -135,8 +135,8 @@ github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc h1:vqlYWupvV github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc/go.mod h1:V14iffGwhZPU2S7wgIiPlLWXygSjAXazYzD1w0ejBl4= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= -github.com/sagernet/utls v0.0.0-20230220130002-c08891932056 h1:gDXi/0uYe8dA48UyUI1LM2la5QYN0IvsDvR2H2+kFnA= -github.com/sagernet/utls v0.0.0-20230220130002-c08891932056/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= +github.com/sagernet/utls v0.0.0-20230225061716-536a007c8b01 h1:m4MI13+NRKddIvbdSN0sFHK8w5ROTa60Zi9diZ7EE08= +github.com/sagernet/utls v0.0.0-20230225061716-536a007c8b01/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index e336d9db..8eae8237 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -19,6 +19,7 @@ import ( "github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/vless" "github.com/Dreamacro/clash/transport/vmess" + xtls "github.com/xtls/go" ) @@ -54,6 +55,7 @@ type Option struct { Flow string FlowShow bool ClientFingerprint string + Reality *tlsC.RealityConfig } type WebsocketOption struct { @@ -117,16 +119,24 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { } if len(t.option.ClientFingerprint) != 0 { - utlsConn, valid := vmess.GetUtlsConnWithClientFingerprint(conn, t.option.ClientFingerprint, tlsConfig) - if valid { + 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 { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) defer cancel() - - err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx) - return utlsConn, err - + 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) diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 711c342d..f020d273 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -3,6 +3,7 @@ package vmess import ( "context" "crypto/tls" + "errors" "net" tlsC "github.com/Dreamacro/clash/component/tls" @@ -15,6 +16,7 @@ type TLSConfig struct { FingerPrint string ClientFingerprint string NextProtos []string + Reality *tlsC.RealityConfig } func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { @@ -34,15 +36,25 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { } if len(cfg.ClientFingerprint) != 0 { - utlsConn, valid := GetUtlsConnWithClientFingerprint(conn, cfg.ClientFingerprint, tlsConfig) - if valid { + if cfg.Reality == nil { + utlsConn, valid := GetUTLSConn(conn, cfg.ClientFingerprint, tlsConfig) + if valid { + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) + defer cancel() + + err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx) + return utlsConn, err + } + } else { ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) defer cancel() - - err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx) - return utlsConn, err + return tlsC.GetRealityConn(ctx, conn, cfg.ClientFingerprint, tlsConfig, cfg.Reality) } } + if cfg.Reality != nil { + return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint") + } + tlsConn := tls.Client(conn, tlsConfig) ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) @@ -52,7 +64,7 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { return tlsConn, err } -func GetUtlsConnWithClientFingerprint(conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config) (net.Conn, bool) { +func GetUTLSConn(conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config) (net.Conn, bool) { if fingerprint, exists := tlsC.GetFingerprint(ClientFingerprint); exists { utlsConn := tlsC.UClient(conn, tlsConfig, fingerprint) From 8ba7ce73d8cf37bca9b39c160955c6d6afe45d34 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 8 Mar 2023 19:12:51 +0800 Subject: [PATCH 067/530] Update config.yaml --- docs/config.yaml | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 13c5a83c..03b35cc8 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -436,11 +436,29 @@ proxies: # socks5 tls: true udp: true xudp: true - flow: xtls-rprx-vision # xtls-rprx-origin # enable XTLS + flow: xtls-rprx-vision client-fingerprint: chrome # fingerprint: xxxx # skip-cert-verify: true - + + - name: "vless-reality-vision" + type: vless + server: server + port: 443 + uuid: uuid + network: tcp + tls: true + udp: true + xudp: true + flow: xtls-rprx-vision + reality-opts: + server-name: www.microsoft.com + public-key: xxx + short-id: xxx + client-fingerprint: chrome + # fingerprint: xxxx + # skip-cert-verify: true + - name: "vless-ws" type: vless server: server @@ -874,4 +892,4 @@ listeners: # authentication-timeout: 1000 # alpn: # - h3 -# max-udp-relay-packet-size: 1500 \ No newline at end of file +# max-udp-relay-packet-size: 1500 From 921b2c3aa4157ec7d02b7baa0ec7c6d4cb49b59d Mon Sep 17 00:00:00 2001 From: H1JK Date: Wed, 8 Mar 2023 20:28:12 +0800 Subject: [PATCH 068/530] feat: REALITY use proxy servername --- adapter/outbound/reality.go | 34 ++++++++++++++-------------------- component/tls/reality.go | 18 +++++++++--------- docs/config.yaml | 8 +++----- 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/adapter/outbound/reality.go b/adapter/outbound/reality.go index 05f49d11..9d892f96 100644 --- a/adapter/outbound/reality.go +++ b/adapter/outbound/reality.go @@ -11,31 +11,25 @@ import ( ) type RealityOptions struct { - ServerName string `proxy:"server-name"` - PublicKey string `proxy:"public-key"` - ShortID string `proxy:"short-id"` + PublicKey string `proxy:"public-key"` + ShortID string `proxy:"short-id"` } func (o RealityOptions) Parse() (*tlsC.RealityConfig, error) { - if o.PublicKey != "" || o.ServerName != "" { - if o.PublicKey != "" && o.ServerName != "" { - config := new(tlsC.RealityConfig) + if o.PublicKey != "" { + config := new(tlsC.RealityConfig) - n, err := base64.RawURLEncoding.Decode(config.PublicKey[:], []byte(o.PublicKey)) - if err != nil || n != curve25519.ScalarSize { - return nil, errors.New("invalid REALITY public key") - } - - config.ShortID, err = hex.DecodeString(o.ShortID) - if err != nil { - return nil, errors.New("invalid REALITY short ID") - } - - config.ServerName = o.ServerName - - return config, nil + n, err := base64.RawURLEncoding.Decode(config.PublicKey[:], []byte(o.PublicKey)) + if err != nil || n != curve25519.ScalarSize { + return nil, errors.New("invalid REALITY public key") } - return nil, errors.New("invalid REALITY protocol option") + + config.ShortID, err = hex.DecodeString(o.ShortID) + if err != nil { + return nil, errors.New("invalid REALITY short ID") + } + + return config, nil } return nil, nil } diff --git a/component/tls/reality.go b/component/tls/reality.go index cdad690f..732613d8 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -30,21 +30,21 @@ import ( ) type RealityConfig struct { - ServerName string - PublicKey [curve25519.ScalarSize]byte - ShortID []byte + PublicKey [curve25519.ScalarSize]byte + ShortID []byte } 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{ - serverName: realityConfig.ServerName, + serverName: tlsConfig.ServerName, + } + uConfig := &utls.Config{ + ServerName: tlsConfig.ServerName, + InsecureSkipVerify: true, + SessionTicketsDisabled: true, + VerifyPeerCertificate: verifier.VerifyPeerCertificate, } - uConfig := copyConfig(tlsConfig) - uConfig.ServerName = realityConfig.ServerName - uConfig.InsecureSkipVerify = true - uConfig.SessionTicketsDisabled = true - uConfig.VerifyPeerCertificate = verifier.VerifyPeerCertificate clientID := utls.ClientHelloID{ Client: fingerprint.Client, Version: fingerprint.Version, diff --git a/docs/config.yaml b/docs/config.yaml index 03b35cc8..971ca124 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -451,13 +451,11 @@ proxies: # socks5 udp: true xudp: true flow: xtls-rprx-vision + servername: www.microsoft.com # REALITY servername reality-opts: - server-name: www.microsoft.com public-key: xxx - short-id: xxx - client-fingerprint: chrome - # fingerprint: xxxx - # skip-cert-verify: true + short-id: xxx # optional + client-fingerprint: chrome # cannot be empty - name: "vless-ws" type: vless From 0c984644b46de51876f809d2211bb60448fed503 Mon Sep 17 00:00:00 2001 From: metacubex Date: Thu, 9 Mar 2023 01:31:43 +0800 Subject: [PATCH 069/530] chore: parse the allowInsecure field for the trojan uri scheme --- common/convert/converter.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/convert/converter.go b/common/convert/converter.go index 7d896d53..abd07a94 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -83,7 +83,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { trojan["port"] = urlTrojan.Port() trojan["password"] = urlTrojan.User.Username() trojan["udp"] = true - trojan["skip-cert-verify"] = false + trojan["skip-cert-verify"], _ = strconv.ParseBool(query.Get("allowInsecure")) sni := query.Get("sni") if sni != "" { From bae61a81522adbde70086366a4e3c84c9554677e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 9 Mar 2023 10:41:07 +0800 Subject: [PATCH 070/530] fix: tuic server close with error message --- transport/tuic/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transport/tuic/server.go b/transport/tuic/server.go index e8dee8d6..fb8a30d3 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -89,7 +89,7 @@ type serverHandler struct { func (s *serverHandler) handle() { time.AfterFunc(s.AuthenticationTimeout, func() { s.authOnce.Do(func() { - _ = s.quicConn.CloseWithError(AuthenticationTimeout, "") + _ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout") s.authOk = false close(s.authCh) }) @@ -239,7 +239,7 @@ func (s *serverHandler) handleUniStream() (err error) { } s.authOnce.Do(func() { if !ok { - _ = s.quicConn.CloseWithError(AuthenticationFailed, "") + _ = s.quicConn.CloseWithError(AuthenticationFailed, "AuthenticationFailed") } s.authOk = ok close(s.authCh) From a454a7f736500364e8c985f473502fa48db6b585 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 9 Mar 2023 11:09:36 +0800 Subject: [PATCH 071/530] fix: load-balance's touch not effected --- adapter/outboundgroup/loadbalance.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 7c7edd36..703444da 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -216,7 +216,7 @@ func strategyStickySessions() strategyFn { // Unwrap implements C.ProxyAdapter func (lb *LoadBalance) Unwrap(metadata *C.Metadata, touch bool) C.Proxy { proxies := lb.GetProxies(touch) - return lb.strategyFn(proxies, metadata, true) + return lb.strategyFn(proxies, metadata, touch) } // MarshalJSON implements C.ProxyAdapter From a973a6c7d2e8f2ccc787d8604956699db48ebf56 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 9 Mar 2023 12:33:29 +0800 Subject: [PATCH 072/530] chore: update utls library --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 21287160..26e47b8c 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d - github.com/sagernet/utls v0.0.0-20230225061716-536a007c8b01 + github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index 8c100900..49666074 100644 --- a/go.sum +++ b/go.sum @@ -135,8 +135,8 @@ github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc h1:vqlYWupvV github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc/go.mod h1:V14iffGwhZPU2S7wgIiPlLWXygSjAXazYzD1w0ejBl4= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= -github.com/sagernet/utls v0.0.0-20230225061716-536a007c8b01 h1:m4MI13+NRKddIvbdSN0sFHK8w5ROTa60Zi9diZ7EE08= -github.com/sagernet/utls v0.0.0-20230225061716-536a007c8b01/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= +github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= +github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= From c0fc5d142f30dba9b4968e4a3ac989c34c6ff31f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 10 Mar 2023 00:25:22 +0800 Subject: [PATCH 073/530] fix: unmap 4in6 address in dialer and wireguard --- adapter/outbound/wireguard.go | 6 +++--- component/dialer/dialer.go | 9 +++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index e5d7cf3f..51c9ecb9 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -77,7 +77,7 @@ type wgNetDialer struct { var _ dialer.NetDialer = &wgNetDialer{} func (d wgNetDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { - return d.tunDevice.DialContext(ctx, network, M.ParseSocksaddr(address)) + return d.tunDevice.DialContext(ctx, network, M.ParseSocksaddr(address).Unwrap()) } func NewWireGuard(option WireGuardOption) (*WireGuard, error) { @@ -225,7 +225,7 @@ func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts 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))) + conn, err = w.tunDevice.DialContext(ctx, "tcp", M.SocksaddrFrom(metadata.DstIP, uint16(port)).Unwrap()) } if err != nil { return nil, err @@ -257,7 +257,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))) + pc, err = w.tunDevice.ListenPacket(ctx, M.SocksaddrFrom(metadata.DstIP, uint16(port)).Unwrap()) if err != nil { return nil, err } diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 025f7034..3014b812 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -302,13 +302,18 @@ func parseAddr(ctx context.Context, network, address string, preferResolver reso if err != nil { return nil, "-1", fmt.Errorf("dns resolve failed: %w", err) } + for i, ip := range ips { + if ip.Is4In6() { + ips[i] = ip.Unmap() + } + } return ips, port, nil } func sortationAddr(ips []netip.Addr) (ipv4s, ipv6s []netip.Addr) { for _, v := range ips { - if v.Is4() || v.Is4In6() { - ipv4s = append(ipv4s, v.Unmap()) + if v.Is4() { // 4in6 parse was in parseAddr + ipv4s = append(ipv4s, v) } else { ipv6s = append(ipv6s, v) } From dca98b7aa1b73b5b5c33b6db89266ce0dbd7b5ad Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 10 Mar 2023 10:01:05 +0800 Subject: [PATCH 074/530] fix: REALITY with gRPC transport --- adapter/outbound/trojan.go | 19 +++++++++-------- adapter/outbound/vless.go | 14 ++++++------- adapter/outbound/vmess.go | 4 ++-- transport/gun/gun.go | 42 +++++++++++++++++++++++++++----------- 4 files changed, 50 insertions(+), 29 deletions(-) diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index d36bd40c..030e74a9 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -26,6 +26,8 @@ type Trojan struct { gunTLSConfig *tls.Config gunConfig *gun.Config transport *gun.TransportWrap + + realityConfig *tlsC.RealityConfig } type TrojanOption struct { @@ -84,7 +86,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) } if t.transport != nil { - c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig) + c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig, t.realityConfig) } else { c, err = t.plainStream(c) } @@ -245,12 +247,6 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { tOption.ServerName = option.SNI } - var err error - tOption.Reality, err = option.RealityOpts.Parse() - if err != nil { - return nil, err - } - t := &Trojan{ Base: &Base{ name: option.Name, @@ -266,6 +262,13 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { option: &option, } + var err error + t.realityConfig, err = option.RealityOpts.Parse() + if err != nil { + return nil, err + } + tOption.Reality = t.realityConfig + if option.Network == "grpc" { dialFn := func(network, addr string) (net.Conn, error) { c, err := dialer.DialContext(context.Background(), "tcp", t.addr, t.Base.DialOptions()...) @@ -292,7 +295,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { } } - t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, tOption.ClientFingerprint) + t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, tOption.ClientFingerprint, t.realityConfig) t.gunTLSConfig = tlsConfig t.gunConfig = &gun.Config{ diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 435beee9..5dc52571 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -156,7 +156,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { c, err = vmess.StreamH2Conn(c, h2Opts) case "grpc": - c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) + c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig) default: // default tcp network // handle TLS And XTLS @@ -522,6 +522,11 @@ func NewVless(option VlessOption) (*Vless, error) { option: &option, } + v.realityConfig, err = v.option.RealityOpts.Parse() + if err != nil { + return nil, err + } + switch option.Network { case "h2": if len(option.HTTP2Opts.Host) == 0 { @@ -556,12 +561,7 @@ func NewVless(option VlessOption) (*Vless, error) { v.gunTLSConfig = tlsConfig v.gunConfig = gunConfig - v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint) - } - - v.realityConfig, err = v.option.RealityOpts.Parse() - if err != nil { - return nil, err + v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint, v.realityConfig) } return v, nil diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index f9e7205b..5bb46dad 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -193,7 +193,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { c, err = clashVMess.StreamH2Conn(c, h2Opts) case "grpc": - c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig) + c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig) default: // handle TLS if v.option.TLS { @@ -455,7 +455,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { v.gunTLSConfig = tlsConfig v.gunConfig = gunConfig - v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint) + v.transport = gun.NewHTTP2Client(dialFn, tlsConfig, v.option.ClientFingerprint, v.realityConfig) } v.realityConfig, err = v.option.RealityOpts.Parse() diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 920e7adc..8eafdc50 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -20,6 +20,7 @@ import ( "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/pool" tlsC "github.com/Dreamacro/clash/component/tls" + "go.uber.org/atomic" "golang.org/x/net/http2" ) @@ -189,7 +190,7 @@ func (g *Conn) SetDeadline(t time.Time) error { return nil } -func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *TransportWrap { +func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, realityConfig *tlsC.RealityConfig) *TransportWrap { wrap := TransportWrap{} dialFunc := func(ctx context.Context, network, addr string, cfg *tls.Config) (net.Conn, error) { @@ -201,20 +202,37 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string) *T wrap.remoteAddr = pconn.RemoteAddr() if len(Fingerprint) != 0 { - if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { - utlsConn := tlsC.UClient(pconn, cfg, fingerprint) - if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil { + if realityConfig == nil { + if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { + utlsConn := tlsC.UClient(pconn, cfg, fingerprint) + if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil { + pconn.Close() + return nil, err + } + state := utlsConn.(*tlsC.UConn).ConnectionState() + if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { + utlsConn.Close() + return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) + } + return utlsConn, nil + } + } else { + realityConn, err := tlsC.GetRealityConn(ctx, pconn, Fingerprint, tlsConfig, realityConfig) + if err != nil { pconn.Close() return nil, err } - state := utlsConn.(*tlsC.UConn).ConnectionState() - if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { - utlsConn.Close() - return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) - } - return utlsConn, nil + //state := realityConn.(*utls.UConn).ConnectionState() + //if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { + // realityConn.Close() + // return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) + //} + return realityConn, nil } } + if realityConfig != nil { + return nil, errors.New("REALITY is based on uTLS, please set a client-fingerprint") + } conn := tls.Client(pconn, cfg) if err := conn.HandshakeContext(ctx); err != nil { @@ -274,11 +292,11 @@ func StreamGunWithTransport(transport *TransportWrap, cfg *Config) (net.Conn, er return conn, nil } -func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config) (net.Conn, error) { +func StreamGunWithConn(conn net.Conn, tlsConfig *tls.Config, cfg *Config, realityConfig *tlsC.RealityConfig) (net.Conn, error) { dialFn := func(network, addr string) (net.Conn, error) { return conn, nil } - transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint) + transport := NewHTTP2Client(dialFn, tlsConfig, cfg.ClientFingerprint, realityConfig) return StreamGunWithTransport(transport, cfg) } From 9ae0bd9c2bdbc8c6b497dc4c4023502aa2e14799 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 10 Mar 2023 12:06:40 +0800 Subject: [PATCH 075/530] fix: don't return a non-nil interface containing nil pointer --- component/dialer/dialer.go | 4 ++-- go.mod | 4 ++-- go.sum | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 3014b812..84cc9c8d 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -170,7 +170,7 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, select { case results <- result: case <-returned: - if result.Conn != nil { + if result.Conn != nil && result.error == nil { _ = result.Conn.Close() } } @@ -218,7 +218,7 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, select { case results <- result: case <-returned: - if result.Conn != nil { + if result.Conn != nil && result.error == nil { _ = result.Conn.Close() } } diff --git a/go.mod b/go.mod index 26e47b8c..e5f99cf1 100644 --- a/go.mod +++ b/go.mod @@ -21,12 +21,12 @@ require ( github.com/metacubex/quic-go v0.32.0 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 - github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 + github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb github.com/miekg/dns v1.1.50 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.8-0.20230307054559-0560a4da412b + github.com/sagernet/sing v0.1.8 github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d diff --git a/go.sum b/go.sum index 49666074..cf1a9a50 100644 --- a/go.sum +++ b/go.sum @@ -95,8 +95,8 @@ github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:Nn github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 h1:oQLThm1a8E7hHmoM9XF2cO0FZPsHVynC4YXW4b3liUI= github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3/go.mod h1:b/19bRRhwampNPV+1gVDyDsQHmuGDaplxPQkwJh1kj4= -github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4 h1:d96mCF/LYyC9kULd2xwcXfP0Jd8klrOngmRxuUIZg/8= -github.com/metacubex/sing-wireguard v0.0.0-20230213124601-d04406a109b4/go.mod h1:p2VpJuxRefgVMxc8cmatMGSFNvYbjMYMsXJOe7qFstw= +github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb h1:uhvzbtOvyg2c1k1H2EeVPuPvTEjDHCq4+U0AljG40P8= +github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= @@ -127,8 +127,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.8-0.20230307054559-0560a4da412b h1:wxqf3O+cLHm1ZWEQG1DRwApwLlTV/NLKGqF1kNCk3Ms= -github.com/sagernet/sing v0.1.8-0.20230307054559-0560a4da412b/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.1.8 h1:6DKo2FkSHn0nUcjO7bAext/ai7y7pCusK/+fScBJ5Jk= +github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc h1:vqlYWupvVDRpvv2F+RtECJN+VbuKjLtmQculQvOecls= From 6fe7f4641ed69d117ccb352d41fecb0190dbd81a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 10 Mar 2023 12:26:17 +0800 Subject: [PATCH 076/530] fix: tuic server set authentication timeout after quic handshake complete --- transport/tuic/server.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/transport/tuic/server.go b/transport/tuic/server.go index fb8a30d3..19398fde 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -76,7 +76,7 @@ func (s *Server) Close() error { type serverHandler struct { *Server - quicConn quic.Connection + quicConn quic.EarlyConnection uuid uuid.UUID authCh chan struct{} @@ -87,13 +87,6 @@ type serverHandler struct { } func (s *serverHandler) handle() { - time.AfterFunc(s.AuthenticationTimeout, func() { - s.authOnce.Do(func() { - _ = s.quicConn.CloseWithError(AuthenticationTimeout, "AuthenticationTimeout") - s.authOk = false - close(s.authCh) - }) - }) go func() { _ = s.handleUniStream() }() @@ -103,6 +96,15 @@ func (s *serverHandler) handle() { go func() { _ = s.handleMessage() }() + + <-s.quicConn.HandshakeComplete().Done() + 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) { From fe298bd53fe391a1ddfcf2bf6080bbc00e7f996e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 10 Mar 2023 12:47:01 +0800 Subject: [PATCH 077/530] fix: strategyRoundRobin not begin with zero --- adapter/outboundgroup/loadbalance.go | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 703444da..1ed80496 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -131,21 +131,23 @@ func strategyRoundRobin() strategyFn { idx := 0 idxMutex := sync.Mutex{} return func(proxies []C.Proxy, metadata *C.Metadata, touch bool) C.Proxy { - id := idx // value could be wrong due to no lock, but don't care if we don't touch + idxMutex.Lock() + defer idxMutex.Unlock() + + i := 0 + length := len(proxies) + if touch { - idxMutex.Lock() - defer idxMutex.Unlock() - id = idx // get again by lock's protect, so it must be right defer func() { - idx = id + idx = (idx + i) % length }() } - length := len(proxies) - for i := 0; i < length; i++ { - id = (id + 1) % length + for ; i < length; i++ { + id := (idx + i) % length proxy := proxies[id] if proxy.Alive() { + i++ return proxy } } From e7f907291193d05d1218cdb1307980c6890a8565 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 10 Mar 2023 12:54:43 +0800 Subject: [PATCH 078/530] fix: add xtls-rprx-vision server version warning to user --- adapter/outbound/vless.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 5dc52571..757661cc 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -17,6 +17,7 @@ import ( "github.com/Dreamacro/clash/component/resolver" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/gun" "github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/vless" @@ -482,7 +483,10 @@ func NewVless(option VlessOption) (*Vless, error) { if option.Network != "ws" && len(option.Flow) >= 16 { option.Flow = option.Flow[:16] switch option.Flow { - case vless.XRO, vless.XRD, vless.XRS, vless.XRV: + 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, } From d309c6311dce876711be90677cf9c7ec259354a7 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 10 Mar 2023 13:42:09 +0800 Subject: [PATCH 079/530] chore: add reality-grpc --- docs/config.yaml | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 971ca124..b0d4541d 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -59,10 +59,9 @@ hosts: # '.dev': 127.0.0.1 # 'alpha.clash.dev': '::1' -profile: - # 存储 select 选择记录 +profile: # 存储 select 选择记录 store-selected: false - + # 持久化 fake-ip store-fake-ip: true @@ -273,7 +272,7 @@ proxies: # socks5 # obfs-opts: # mode: http # or tls # host: bing.com - + # Shadowsocks # cipher支持: # aes-128-gcm aes-192-gcm aes-256-gcm @@ -296,7 +295,7 @@ proxies: # socks5 # UDP 则为双栈解析,获取结果中的第一个 IPv4 # ipv6-prefer 同 ipv4-prefer # 现有协议都支持此参数,TCP 效果仅在开启 tcp-concurrent 生效 - + - name: "ss2" type: ss server: server @@ -435,12 +434,11 @@ proxies: # socks5 network: tcp tls: true udp: true - xudp: true - flow: xtls-rprx-vision + flow: xtls-rprx-vision client-fingerprint: chrome # fingerprint: xxxx # skip-cert-verify: true - + - name: "vless-reality-vision" type: vless server: server @@ -449,14 +447,31 @@ proxies: # socks5 network: tcp tls: true udp: true - xudp: true flow: xtls-rprx-vision servername: www.microsoft.com # REALITY servername reality-opts: public-key: xxx short-id: xxx # optional client-fingerprint: chrome # cannot be empty - + + - name: "vless-reality-grpc" + type: vless + server: server + port: 443 + uuid: uuid + network: grpc + tls: true + udp: true + flow: + # skip-cert-verify: true + client-fingerprint: chrome + servername: testingcf.jsdelivr.net + grpc-opts: + grpc-service-name: "grpc" + reality-opts: + public-key: CrrQSjAG_YkHLwvM2M-7XkKJilgL5upBKCp0od0tLhE + short-id: 10f897e26c4b9478 + - name: "vless-ws" type: vless server: server @@ -528,7 +543,7 @@ proxies: # socks5 # sni: example.com # aka server name # skip-cert-verify: true # fingerprint: xxxx - + #hysteria - name: "hysteria" type: hysteria @@ -588,7 +603,7 @@ proxies: # socks5 # 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: @@ -717,7 +732,7 @@ rules: - IP-CIDR,1.1.1.1/32,ss1 - IP-CIDR6,2409::/64,DIRECT # 当满足条件是 TCP 或 UDP 流量时,使用名为 sub-rule-name1 的规则集 - - SUB-RULE,(OR,((NETWORK,TCP),(NETWORK,UDP))),sub-rule-name1 + - SUB-RULE,(OR,((NETWORK,TCP),(NETWORK,UDP))),sub-rule-name1 - SUB-RULE,(AND,((NETWORK,UDP))),sub-rule-name2 # 定义多个子规则集,规则将以分叉匹配,使用 SUB-RULE 使用 # google.com(not match)--> baidu.com(match) From 7cc1c1b5617b30eaac9d1bcfa5af784047e7c621 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 10 Mar 2023 14:12:18 +0800 Subject: [PATCH 080/530] chore: adjust error log --- component/dialer/dialer.go | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 84cc9c8d..5ba00e31 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -180,14 +180,17 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, go racer(ipv4s, preferIPVersion != 6) go racer(ipv6s, preferIPVersion != 4) var fallback dialResult - var err error + var errs []error for { select { case <-ctx.Done(): if fallback.error == nil && fallback.Conn != nil { return fallback.Conn, nil } - return nil, fmt.Errorf("dual stack connect failed: %w", err) + if res, ok := <-results; ok && res.error == nil { + return res.Conn, nil + } + return nil, errorsJoin(errs...) case <-fallbackTicker.C: if fallback.error == nil && fallback.Conn != nil { return fallback.Conn, nil @@ -199,7 +202,11 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, } fallback = res } else { - err = res.error + if res.isPrimary { + errs = append([]error{fmt.Errorf("connect failed: %w", res.error)}, errs...) + } else { + errs = append(errs, fmt.Errorf("connect failed: %w", res.error)) + } } } } @@ -230,12 +237,12 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, for _, ip := range ips { go racer(ctx, ip) } - var err error + var errs []error for { select { case <-ctx.Done(): - if err != nil { - return nil, err + if len(errs) > 0 { + return nil, errorsJoin(errs...) } if ctx.Err() == context.DeadlineExceeded { return nil, os.ErrDeadlineExceeded @@ -245,7 +252,7 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, if res.error == nil { return res.Conn, nil } - err = res.error + errs = append(errs, res.error) } } } From 2c4783ff8b197e778b32558867897fa00ad0bbd8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 10 Mar 2023 16:17:43 +0800 Subject: [PATCH 081/530] fix: SA4001 for netDialer copy --- component/dialer/dialer.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 5ba00e31..b47b9e5b 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -116,7 +116,8 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po case nil: netDialer = &net.Dialer{} case *net.Dialer: - netDialer = &*netDialer.(*net.Dialer) // make a copy + _netDialer := *netDialer.(*net.Dialer) + netDialer = &_netDialer // make a copy default: return netDialer.DialContext(ctx, network, address) } From 2ccef31f754d1dab6734a3a3e358b01333ec01e9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 10 Mar 2023 17:00:39 +0800 Subject: [PATCH 082/530] fix: ensure wireguard inner use dialer with DefaultResolver --- adapter/outbound/wireguard.go | 1 + 1 file changed, 1 insertion(+) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 51c9ecb9..7eae30fc 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -221,6 +221,7 @@ func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts return nil, w.startErr } if !metadata.Resolved() { + options = append(options, dialer.WithResolver(resolver.DefaultResolver)) options = append(options, dialer.WithNetDialer(wgNetDialer{tunDevice: w.tunDevice})) conn, err = dialer.NewDialer(options...).DialContext(ctx, "tcp", metadata.RemoteAddress()) } else { From 5bcfe1a6c620a791ec25e23c22b2eb8ccd182eb7 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 10 Mar 2023 20:16:14 +0800 Subject: [PATCH 083/530] fix: dialer dual stack panic --- component/dialer/dialer.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index b47b9e5b..479def67 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -182,16 +182,8 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, go racer(ipv6s, preferIPVersion != 4) var fallback dialResult var errs []error - for { + for i := 0; i < 2; i++ { select { - case <-ctx.Done(): - if fallback.error == nil && fallback.Conn != nil { - return fallback.Conn, nil - } - if res, ok := <-results; ok && res.error == nil { - return res.Conn, nil - } - return nil, errorsJoin(errs...) case <-fallbackTicker.C: if fallback.error == nil && fallback.Conn != nil { return fallback.Conn, nil @@ -211,6 +203,10 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, } } } + if fallback.error == nil && fallback.Conn != nil { + return fallback.Conn, nil + } + return nil, errorsJoin(errs...) } func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { From 8c135e4a915bf48ce9265ca55072f04e04e9e4bd Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 10 Mar 2023 20:48:18 +0800 Subject: [PATCH 084/530] chore: adjust log --- config/config.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index efb5b4cf..85b1fafa 100644 --- a/config/config.go +++ b/config/config.go @@ -1255,8 +1255,10 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { } } } else { - // Deprecated: Use Sniff instead - log.Warnln("Deprecated: Use Sniff instead") + if sniffer.Enable { + // Deprecated: Use Sniff instead + log.Warnln("Deprecated: Use Sniff instead") + } globalPorts, err := parsePortRange(snifferRaw.Ports) if err != nil { return nil, err From 913ed62095428f99f93697274f7efd30a18e2d4f Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 10 Mar 2023 20:53:39 +0800 Subject: [PATCH 085/530] fix: ALPN not applied in uTLS/REALITY --- component/tls/reality.go | 1 + component/tls/utls.go | 1 + transport/gun/gun.go | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index 732613d8..dbd4bf41 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -41,6 +41,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string } uConfig := &utls.Config{ ServerName: tlsConfig.ServerName, + NextProtos: tlsConfig.NextProtos, InsecureSkipVerify: true, SessionTicketsDisabled: true, VerifyPeerCertificate: verifier.VerifyPeerCertificate, diff --git a/component/tls/utls.go b/component/tls/utls.go index a7189aa8..e08ca7ee 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -89,6 +89,7 @@ func copyConfig(c *tls.Config) *utls.Config { return &utls.Config{ RootCAs: c.RootCAs, ServerName: c.ServerName, + NextProtos: c.NextProtos, InsecureSkipVerify: c.InsecureSkipVerify, VerifyPeerCertificate: c.VerifyPeerCertificate, } diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 8eafdc50..ae2ea6a4 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -217,7 +217,7 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re return utlsConn, nil } } else { - realityConn, err := tlsC.GetRealityConn(ctx, pconn, Fingerprint, tlsConfig, realityConfig) + realityConn, err := tlsC.GetRealityConn(ctx, pconn, Fingerprint, cfg, realityConfig) if err != nil { pconn.Close() return nil, err From 035d878a9ff3eab2fabcb2de65afd6139bf7af96 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 10 Mar 2023 22:08:01 +0800 Subject: [PATCH 086/530] fix: dial panic --- component/dialer/dialer.go | 31 +++++++++++++------------------ 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 479def67..d70e9173 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -182,13 +182,14 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, go racer(ipv6s, preferIPVersion != 4) var fallback dialResult var errs []error - for i := 0; i < 2; i++ { + for i := 0; i < 2; { select { case <-fallbackTicker.C: if fallback.error == nil && fallback.Conn != nil { return fallback.Conn, nil } case res := <-results: + i++ if res.error == nil { if res.isPrimary { return res.Conn, nil @@ -217,7 +218,7 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, returned := make(chan struct{}) defer close(returned) racer := func(ctx context.Context, ip netip.Addr) { - result := dialResult{isPrimary: true} + result := dialResult{isPrimary: true, ip: ip} defer func() { select { case results <- result: @@ -227,7 +228,6 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, } } }() - result.ip = ip result.Conn, result.error = dialContext(ctx, network, ip, port, opt) } @@ -235,23 +235,18 @@ func parallelDialContext(ctx context.Context, network string, ips []netip.Addr, go racer(ctx, ip) } var errs []error - for { - select { - case <-ctx.Done(): - if len(errs) > 0 { - return nil, errorsJoin(errs...) - } - if ctx.Err() == context.DeadlineExceeded { - return nil, os.ErrDeadlineExceeded - } - return nil, ctx.Err() - case res := <-results: - if res.error == nil { - return res.Conn, nil - } - errs = append(errs, res.error) + for i := 0; i < len(ips); i++ { + res := <-results + if res.error == nil { + return res.Conn, nil } + errs = append(errs, res.error) } + + if len(errs) > 0 { + return nil, errorsJoin(errs...) + } + return nil, os.ErrDeadlineExceeded } func serialDialContext(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { From 07f3cd2ae5576043064757cf511a5c624e722a2d Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 10 Mar 2023 23:38:16 +0800 Subject: [PATCH 087/530] chore: exposure ipv6 wait time --- config/config.go | 4 ++++ dns/resolver.go | 37 ++++++++++++++++++++++++------------- docs/config.yaml | 2 +- hub/executor/executor.go | 1 + 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/config/config.go b/config/config.go index 85b1fafa..9316f920 100644 --- a/config/config.go +++ b/config/config.go @@ -92,6 +92,7 @@ type DNS struct { Enable bool `yaml:"enable"` PreferH3 bool `yaml:"prefer-h3"` IPv6 bool `yaml:"ipv6"` + IPv6Timeout uint `yaml:"ipv6-timeout"` NameServer []dns.NameServer `yaml:"nameserver"` Fallback []dns.NameServer `yaml:"fallback"` FallbackFilter FallbackFilter `yaml:"fallback-filter"` @@ -171,6 +172,7 @@ type RawDNS struct { Enable bool `yaml:"enable"` PreferH3 bool `yaml:"prefer-h3"` IPv6 bool `yaml:"ipv6"` + IPv6Timeout uint `yaml:"ipv6-timeout"` UseHosts bool `yaml:"use-hosts"` NameServer []string `yaml:"nameserver"` Fallback []string `yaml:"fallback"` @@ -377,6 +379,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { Enable: false, IPv6: false, UseHosts: true, + IPv6Timeout: 100, EnhancedMode: C.DNSMapping, FakeIPRange: "198.18.0.1/16", FallbackFilter: RawFallbackFilter{ @@ -1048,6 +1051,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[netip.Addr], rules []C.R Enable: cfg.Enable, Listen: cfg.Listen, PreferH3: cfg.PreferH3, + IPv6Timeout: cfg.IPv6Timeout, IPv6: cfg.IPv6, EnhancedMode: cfg.EnhancedMode, FallbackFilter: FallbackFilter{ diff --git a/dns/resolver.go b/dns/resolver.go index 59b1ee06..69725870 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -42,6 +42,7 @@ type geositePolicyRecord struct { type Resolver struct { ipv6 bool + ipv6Timeout time.Duration hosts *trie.DomainTrie[netip.Addr] main []dnsClient fallback []dnsClient @@ -91,14 +92,20 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ips []netip.Addr, }() ips, err = r.lookupIP(ctx, host, D.TypeA) - + var waitIPv6 *time.Timer + if r != nil { + waitIPv6 = time.NewTimer(r.ipv6Timeout) + } else { + waitIPv6 = time.NewTimer(100 * time.Millisecond) + } + defer waitIPv6.Stop() select { case ipv6s, open := <-ch: if !open && err != nil { return nil, resolver.ErrIPNotFound } ips = append(ips, ipv6s...) - case <-time.After(30 * time.Millisecond): + case <-waitIPv6.C: // wait ipv6 result } @@ -419,6 +426,7 @@ type Config struct { Default []NameServer ProxyServer []NameServer IPv6 bool + IPv6Timeout uint EnhancedMode C.DNSMode FallbackFilter FallbackFilter Pool *fakeip.Pool @@ -428,15 +436,17 @@ type Config struct { func NewResolver(config Config) *Resolver { defaultResolver := &Resolver{ - main: transform(config.Default, nil), - lruCache: cache.New(cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), + main: transform(config.Default, nil), + lruCache: cache.New(cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), + ipv6Timeout: time.Duration(config.IPv6Timeout) * time.Millisecond, } r := &Resolver{ - ipv6: config.IPv6, - main: transform(config.Main, defaultResolver), - lruCache: cache.New(cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), - hosts: config.Hosts, + ipv6: config.IPv6, + main: transform(config.Main, defaultResolver), + lruCache: cache.New(cache.WithSize[string, *D.Msg](4096), cache.WithStale[string, *D.Msg](true)), + hosts: config.Hosts, + ipv6Timeout: time.Duration(config.IPv6Timeout) * time.Millisecond, } if len(config.Fallback) != 0 { @@ -502,11 +512,12 @@ func NewResolver(config Config) *Resolver { func NewProxyServerHostResolver(old *Resolver) *Resolver { r := &Resolver{ - ipv6: old.ipv6, - main: old.proxyServer, - lruCache: old.lruCache, - hosts: old.hosts, - policy: old.policy, + ipv6: old.ipv6, + main: old.proxyServer, + lruCache: old.lruCache, + hosts: old.hosts, + policy: old.policy, + ipv6Timeout: old.ipv6Timeout, } return r } diff --git a/docs/config.yaml b/docs/config.yaml index b0d4541d..b5af798b 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -166,7 +166,7 @@ dns: prefer-h3: true # 开启 DoH 支持 HTTP/3,将并发尝试 listen: 0.0.0.0:53 # 开启 DNS 服务器监听 # ipv6: false # false 将返回 AAAA 的空结果 - + # ipv6-timeout: 300 # 单位:ms,内部双栈并发时,向上游查询 AAAA 时,等待 AAAA 的时间,默认 100ms # 用于解析 nameserver,fallback 以及其他DNS服务器配置的,DNS 服务域名 # 只能使用纯 IP 地址,可使用加密 DNS default-nameserver: diff --git a/hub/executor/executor.go b/hub/executor/executor.go index d6ff7851..1bd22385 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -190,6 +190,7 @@ func updateDNS(c *config.DNS, generalIPv6 bool) { Main: c.NameServer, Fallback: c.Fallback, IPv6: c.IPv6 && generalIPv6, + IPv6Timeout: c.IPv6Timeout, EnhancedMode: c.EnhancedMode, Pool: c.FakeIPRange, Hosts: c.Hosts, From ae4d114802c12d3685e819e6ec89471bb3234caa Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 11 Mar 2023 12:23:27 +0800 Subject: [PATCH 088/530] chore: Cleanup REALITY code --- adapter/outbound/reality.go | 4 ++-- common/utils/must.go | 8 ++++++++ component/tls/reality.go | 15 ++++++++++----- 3 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 common/utils/must.go diff --git a/adapter/outbound/reality.go b/adapter/outbound/reality.go index 9d892f96..23314e5f 100644 --- a/adapter/outbound/reality.go +++ b/adapter/outbound/reality.go @@ -24,8 +24,8 @@ func (o RealityOptions) Parse() (*tlsC.RealityConfig, error) { return nil, errors.New("invalid REALITY public key") } - config.ShortID, err = hex.DecodeString(o.ShortID) - if err != nil { + n, err = hex.Decode(config.ShortID[:], []byte(o.ShortID)) + if err != nil || n > tlsC.RealityMaxShortIDLen { return nil, errors.New("invalid REALITY short ID") } diff --git a/common/utils/must.go b/common/utils/must.go new file mode 100644 index 00000000..2dd5ff5e --- /dev/null +++ b/common/utils/must.go @@ -0,0 +1,8 @@ +package utils + +func MustOK[T any](result T, ok bool) T { + if ok { + return result + } + panic("operation failed") +} diff --git a/component/tls/reality.go b/component/tls/reality.go index dbd4bf41..a060de92 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -20,6 +20,7 @@ import ( "time" "unsafe" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/log" utls "github.com/sagernet/utls" @@ -29,9 +30,11 @@ import ( "golang.org/x/net/http2" ) +const RealityMaxShortIDLen = 8 + type RealityConfig struct { PublicKey [curve25519.ScalarSize]byte - ShortID []byte + ShortID [RealityMaxShortIDLen]byte } func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string, tlsConfig *tls.Config, realityConfig *RealityConfig) (net.Conn, error) { @@ -73,7 +76,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string hello.SessionId[0] = 1 hello.SessionId[1] = 7 hello.SessionId[2] = 5 - copy(hello.SessionId[8:], realityConfig.ShortID) + copy(hello.SessionId[8:], realityConfig.ShortID[:]) //log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16]) @@ -112,7 +115,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.ClientHelloID) { defer uConn.Close() - client := &http.Client{ + client := http.Client{ Transport: &http2.Transport{ DialTLSContext: func(ctx context.Context, network, addr string, config *tls.Config) (net.Conn, error) { return uConn, nil @@ -139,9 +142,11 @@ type realityVerifier struct { verified bool } +var pOffset = utils.MustOK(reflect.TypeOf((*utls.UConn)(nil)).Elem().FieldByName("peerCertificates")).Offset + func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { - p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates") - certs := *(*([]*x509.Certificate))(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + p.Offset)) + //p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates") + certs := *(*[]*x509.Certificate)(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + pOffset)) if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok { h := hmac.New(sha512.New, c.authKey) h.Write(pub) From 794452218808dc8ca7648166da9cb8a3603fd6ef Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 Mar 2023 09:38:58 +0800 Subject: [PATCH 089/530] chore: update quic-go --- go.mod | 7 +++---- go.sum | 14 ++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index e5f99cf1..bde63cc3 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 - github.com/metacubex/quic-go v0.32.0 + github.com/metacubex/quic-go v0.33.1 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb @@ -69,9 +69,8 @@ require ( github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-18 v0.2.0 // indirect - github.com/quic-go/qtls-go1-19 v0.2.0 // indirect - github.com/quic-go/qtls-go1-20 v0.1.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/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect diff --git a/go.sum b/go.sum index cf1a9a50..7b24bc35 100644 --- a/go.sum +++ b/go.sum @@ -89,8 +89,8 @@ github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005 h1:0TEvReK/D6YLszjGj/bdx4d7amQSjQ2X/98r4ZiUbxU= github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= -github.com/metacubex/quic-go v0.32.0 h1:dSD8LB4MSeBuD4otd8y1DUZcRdDcEB0Ax5esPOqn2Hw= -github.com/metacubex/quic-go v0.32.0/go.mod h1:yParIzDYUd/t/pzFlDtZKhnvSqbUu0bPChlKEGmJStA= +github.com/metacubex/quic-go v0.33.1 h1:ZIxZFGivpSLOEZuuNkLy+aPvo1RP4uRBjNg3SAkXwIg= +github.com/metacubex/quic-go v0.33.1/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 h1:oQLThm1a8E7hHmoM9XF2cO0FZPsHVynC4YXW4b3liUI= @@ -115,12 +115,10 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN 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-18 v0.2.0 h1:5ViXqBZ90wpUcZS0ge79rf029yx0dYB0McyPJwqqj7U= -github.com/quic-go/qtls-go1-18 v0.2.0/go.mod h1:moGulGHK7o6O8lSPSZNoOwcLvJKJ85vVNc7oJFD65bc= -github.com/quic-go/qtls-go1-19 v0.2.0 h1:Cvn2WdhyViFUHoOqK52i51k4nDX8EwIh5VJiVM4nttk= -github.com/quic-go/qtls-go1-19 v0.2.0/go.mod h1:ySOI96ew8lnoKPtSqx2BlI5wCpUVPT05RMAlajtnyOI= -github.com/quic-go/qtls-go1-20 v0.1.0 h1:d1PK3ErFy9t7zxKsG3NXBJXZjp/kMLoIb3y/kV54oAI= -github.com/quic-go/qtls-go1-20 v0.1.0/go.mod h1:JKtK6mjbAVcUTN/9jZpvLbGxvdWIKS8uT7EiStoU1SM= +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/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 09b4a7ff1584ccc57c9e2e342dfa19dc9cd682c2 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 12 Mar 2023 10:13:23 +0800 Subject: [PATCH 090/530] chore: Remove useless mutex in Vision --- transport/vless/vision.go | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/transport/vless/vision.go b/transport/vless/vision.go index 857d9150..8dc84e40 100644 --- a/transport/vless/vision.go +++ b/transport/vless/vision.go @@ -3,7 +3,6 @@ package vless import ( "bytes" "encoding/binary" - "sync" "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/log" @@ -20,12 +19,9 @@ const ( commandPaddingDirect byte = 0x02 ) -var mutex sync.RWMutex - func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid.UUID, paddingTLS bool) { contentLen := int32(len(p)) var paddingLen int32 - mutex.Lock() if contentLen < 900 { if paddingTLS { //log.Debugln("long padding") @@ -34,8 +30,7 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid paddingLen = fastrand.Int31n(256) } } - mutex.Unlock() - if userUUID != nil { // unnecessary, but keep the same with Xray + if userUUID != nil { buffer.Write(userUUID.Bytes()) } @@ -51,7 +46,6 @@ func WriteWithPadding(buffer *buf.Buffer, p []byte, command byte, userUUID *uuid func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, paddingTLS bool) { contentLen := int32(buffer.Len()) var paddingLen int32 - mutex.Lock() if contentLen < 900 { if paddingTLS { //log.Debugln("long padding") @@ -60,12 +54,11 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding paddingLen = fastrand.Int31n(256) } } - mutex.Unlock() binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(paddingLen)) binary.BigEndian.PutUint16(buffer.ExtendHeader(2), uint16(contentLen)) buffer.ExtendHeader(1)[0] = command - if userUUID != nil { // unnecessary, but keep the same with Xray + if userUUID != nil { copy(buffer.ExtendHeader(uuid.Size), userUUID.Bytes()) } From 4b72ae7aaba685afdf9538d04971d86b7a175172 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 12 Mar 2023 13:35:59 +0800 Subject: [PATCH 091/530] fix: global-client-fingerprint is now work --- config/config.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/config/config.go b/config/config.go index 9316f920..817d0d64 100644 --- a/config/config.go +++ b/config/config.go @@ -446,6 +446,11 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } config.General = general + if len(config.General.GlobalClientFingerprint) != 0 { + log.Debugln("GlobalClientFingerprint:%s", config.General.GlobalClientFingerprint) + tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint) + } + dialer.DefaultInterface.Store(config.General.Interface) proxies, providers, err := parseProxies(rawCfg) if err != nil { @@ -521,11 +526,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { elapsedTime := time.Since(startTime) / time.Millisecond // duration in ms log.Infoln("Initial configuration complete, total time: %dms", elapsedTime) //Segment finished in xxm - if len(config.General.GlobalClientFingerprint) != 0 { - log.Debugln("GlobalClientFingerprint:%s", config.General.GlobalClientFingerprint) - tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint) - } - return config, nil } From 7f588935eac0bcd2c7165d7d484c0a02a0c99df6 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 12 Mar 2023 15:00:59 +0800 Subject: [PATCH 092/530] feta: add hosts support domain and mulitple ip (#439) * feat: host support domain and multiple ips * chore: append local address via `clash` * chore: update hosts demo * chore: unified parse mixed string and array * fix: flatten cname * chore: adjust logic * chore: reuse code * chore: use cname in tunnel * chore: try use domain mapping when normal dns * chore: format code --- common/utils/slice.go | 34 ++++++++++ component/resolver/host.go | 112 +++++++++++++++++++++++++++++++++ component/resolver/resolver.go | 23 ++++--- config/config.go | 74 +++++++++++++--------- dns/middleware.go | 79 +++++++++++++++-------- dns/resolver.go | 4 +- dns/util.go | 2 +- docs/config.yaml | 3 + hub/executor/executor.go | 4 +- hub/hub.go | 2 +- tunnel/tunnel.go | 17 +++-- 11 files changed, 278 insertions(+), 76 deletions(-) create mode 100644 common/utils/slice.go create mode 100644 component/resolver/host.go diff --git a/common/utils/slice.go b/common/utils/slice.go new file mode 100644 index 00000000..1b0fa494 --- /dev/null +++ b/common/utils/slice.go @@ -0,0 +1,34 @@ +package utils + +import ( + "errors" + "fmt" + "reflect" +) + +func Filter[T comparable](tSlice []T, filter func(t T) bool) []T { + result := make([]T, 0) + for _, t := range tSlice { + if filter(t) { + result = append(result, t) + } + } + return result +} + +func ToStringSlice(value any) ([]string, error) { + strArr := make([]string, 0) + switch reflect.TypeOf(value).Kind() { + case reflect.Slice, reflect.Array: + origin := reflect.ValueOf(value) + for i := 0; i < origin.Len(); i++ { + item := fmt.Sprintf("%v", origin.Index(i)) + strArr = append(strArr, item) + } + case reflect.String: + strArr = append(strArr, fmt.Sprintf("%v", value)) + default: + return nil, errors.New("value format error, must be string or array") + } + return strArr, nil +} diff --git a/component/resolver/host.go b/component/resolver/host.go new file mode 100644 index 00000000..ca90cd27 --- /dev/null +++ b/component/resolver/host.go @@ -0,0 +1,112 @@ +package resolver + +import ( + "errors" + "math/rand" + "net/netip" + "strings" + + "github.com/Dreamacro/clash/common/utils" + "github.com/Dreamacro/clash/component/trie" +) + +type Hosts struct { + *trie.DomainTrie[HostValue] +} + +func NewHosts(hosts *trie.DomainTrie[HostValue]) Hosts { + return Hosts{ + hosts, + } +} + +func (h *Hosts) Search(domain string, isDomain bool) (*HostValue, bool) { + value := h.DomainTrie.Search(domain) + if value == nil { + return nil, false + } + hostValue := value.Data() + for { + if isDomain && hostValue.IsDomain { + return &hostValue, true + } else { + if node := h.DomainTrie.Search(hostValue.Domain); node != nil { + hostValue = node.Data() + } else { + break + } + } + } + if isDomain == hostValue.IsDomain { + return &hostValue, true + } + return &hostValue, false +} + +type HostValue struct { + IsDomain bool + IPs []netip.Addr + Domain string +} + +func NewHostValue(value any) (HostValue, error) { + isDomain := true + ips := make([]netip.Addr, 0) + domain := "" + if valueArr, err := utils.ToStringSlice(value); err != nil { + return HostValue{}, err + } else { + if len(valueArr) > 1 { + isDomain = false + for _, str := range valueArr { + if ip, err := netip.ParseAddr(str); err == nil { + ips = append(ips, ip) + } else { + return HostValue{}, err + } + } + } else if len(valueArr) == 1 { + host := valueArr[0] + if ip, err := netip.ParseAddr(host); err == nil { + ips = append(ips, ip) + isDomain = false + } else { + domain = host + } + } + } + if isDomain { + return NewHostValueByDomain(domain) + } else { + return NewHostValueByIPs(ips) + } +} + +func NewHostValueByIPs(ips []netip.Addr) (HostValue, error) { + if len(ips) == 0 { + return HostValue{}, errors.New("ip list is empty") + } + return HostValue{ + IsDomain: false, + IPs: ips, + }, nil +} + +func NewHostValueByDomain(domain string) (HostValue, error) { + domain = strings.Trim(domain, ".") + item := strings.Split(domain, ".") + if len(item) < 2 { + return HostValue{}, errors.New("invaild domain") + } + return HostValue{ + IsDomain: true, + Domain: domain, + }, nil +} + +func (hv HostValue) RandIP() (netip.Addr, error) { + if hv.IsDomain { + return netip.Addr{}, errors.New("value type is error") + } + return hv.IPs[rand.Intn(len(hv.IPs)-1)], nil +} diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index 6ae2d7c2..f5872ad7 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -9,6 +9,7 @@ import ( "strings" "time" + "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/trie" "github.com/miekg/dns" @@ -27,7 +28,7 @@ var ( DisableIPv6 = true // DefaultHosts aim to resolve hosts - DefaultHosts = trie.New[netip.Addr]() + DefaultHosts = NewHosts(trie.New[HostValue]()) // DefaultDNSTimeout defined the default dns request timeout DefaultDNSTimeout = time.Second * 5 @@ -51,9 +52,11 @@ type Resolver interface { // LookupIPv4WithResolver same as LookupIPv4, but with a resolver func LookupIPv4WithResolver(ctx context.Context, host string, r Resolver) ([]netip.Addr, error) { - if node := DefaultHosts.Search(host); node != nil { - if ip := node.Data(); ip.Is4() { - return []netip.Addr{node.Data()}, nil + if node, ok := DefaultHosts.Search(host, false); ok { + if addrs := utils.Filter(node.IPs, func(ip netip.Addr) bool { + return ip.Is4() + }); len(addrs) > 0 { + return addrs, nil } } @@ -106,9 +109,11 @@ func LookupIPv6WithResolver(ctx context.Context, host string, r Resolver) ([]net return nil, ErrIPv6Disabled } - if node := DefaultHosts.Search(host); node != nil { - if ip := node.Data(); ip.Is6() { - return []netip.Addr{ip}, nil + if node, ok := DefaultHosts.Search(host, false); ok { + if addrs := utils.Filter(node.IPs, func(ip netip.Addr) bool { + return ip.Is6() + }); len(addrs) > 0 { + return addrs, nil } } @@ -155,8 +160,8 @@ func ResolveIPv6(ctx context.Context, host string) (netip.Addr, error) { // LookupIPWithResolver same as LookupIP, but with a resolver func LookupIPWithResolver(ctx context.Context, host string, r Resolver) ([]netip.Addr, error) { - if node := DefaultHosts.Search(host); node != nil { - return []netip.Addr{node.Data()}, nil + if node, ok := DefaultHosts.Search(host, false); ok { + return node.IPs, nil } if r != nil { diff --git a/config/config.go b/config/config.go index 817d0d64..45dd31f5 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,6 @@ import ( "net/netip" "net/url" "os" - "reflect" "runtime" "strconv" "strings" @@ -26,6 +25,7 @@ import ( "github.com/Dreamacro/clash/component/geodata" "github.com/Dreamacro/clash/component/geodata/router" P "github.com/Dreamacro/clash/component/process" + "github.com/Dreamacro/clash/component/resolver" SNIFF "github.com/Dreamacro/clash/component/sniffer" tlsC "github.com/Dreamacro/clash/component/tls" "github.com/Dreamacro/clash/component/trie" @@ -100,7 +100,7 @@ type DNS struct { EnhancedMode C.DNSMode `yaml:"enhanced-mode"` DefaultNameserver []dns.NameServer `yaml:"default-nameserver"` FakeIPRange *fakeip.Pool - Hosts *trie.DomainTrie[netip.Addr] + Hosts *trie.DomainTrie[resolver.HostValue] NameServerPolicy map[string][]dns.NameServer ProxyServerNameserver []dns.NameServer } @@ -154,7 +154,7 @@ type Config struct { IPTables *IPTables DNS *DNS Experimental *Experimental - Hosts *trie.DomainTrie[netip.Addr] + Hosts *trie.DomainTrie[resolver.HostValue] Profile *Profile Rules []C.Rule SubRules map[string][]C.Rule @@ -265,7 +265,7 @@ type RawConfig struct { Sniffer RawSniffer `yaml:"sniffer"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` RuleProvider map[string]map[string]any `yaml:"rule-providers"` - Hosts map[string]string `yaml:"hosts"` + Hosts map[string]any `yaml:"hosts"` DNS RawDNS `yaml:"dns"` Tun RawTun `yaml:"tun"` TuicServer RawTuicServer `yaml:"tuic-server"` @@ -339,7 +339,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { UnifiedDelay: false, Authentication: []string{}, LogLevel: log.INFO, - Hosts: map[string]string{}, + Hosts: map[string]any{}, Rule: []string{}, Proxy: []map[string]any{}, ProxyGroup: []map[string]any{}, @@ -827,21 +827,47 @@ func parseRules(rulesConfig []string, proxies map[string]C.Proxy, subRules map[s return rules, nil } -func parseHosts(cfg *RawConfig) (*trie.DomainTrie[netip.Addr], error) { - tree := trie.New[netip.Addr]() +func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) { + tree := trie.New[resolver.HostValue]() // add default hosts - if err := tree.Insert("localhost", netip.AddrFrom4([4]byte{127, 0, 0, 1})); err != nil { + hostValue, _ := resolver.NewHostValueByIPs( + []netip.Addr{netip.AddrFrom4([4]byte{127, 0, 0, 1})}) + if err := tree.Insert("localhost", hostValue); err != nil { log.Errorln("insert localhost to host error: %s", err.Error()) } if len(cfg.Hosts) != 0 { - for domain, ipStr := range cfg.Hosts { - ip, err := netip.ParseAddr(ipStr) - if err != nil { - return nil, fmt.Errorf("%s is not a valid IP", ipStr) + for domain, anyValue := range cfg.Hosts { + if str, ok := anyValue.(string); ok && str == "clash" { + if addrs, err := net.InterfaceAddrs(); err != nil { + log.Errorln("insert clash to host error: %s", err) + } else { + ips := make([]netip.Addr, 0) + for _, addr := range addrs { + if ipnet, ok := addr.(*net.IPNet); ok { + if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil { + ips = append(ips, ip) + } + } + } + anyValue = ips + } } - _ = tree.Insert(domain, ip) + value, err := resolver.NewHostValue(anyValue) + if err != nil { + return nil, fmt.Errorf("%s is not a valid value", anyValue) + } + if value.IsDomain { + node := tree.Search(value.Domain) + for node != nil && node.Data().IsDomain { + if node.Data().Domain == domain { + return nil, fmt.Errorf("%s, there is a cycle in domain name mapping", domain) + } + node = tree.Search(node.Data().Domain) + } + } + _ = tree.Insert(domain, value) } } tree.Optimize() @@ -961,24 +987,12 @@ func parseNameServerPolicy(nsPolicy map[string]any, preferH3 bool) (map[string][ policy := map[string][]dns.NameServer{} for domain, server := range nsPolicy { - var ( - nameservers []dns.NameServer - err error - ) - switch reflect.TypeOf(server).Kind() { - case reflect.Slice, reflect.Array: - origin := reflect.ValueOf(server) - servers := make([]string, 0) - for i := 0; i < origin.Len(); i++ { - servers = append(servers, fmt.Sprintf("%v", origin.Index(i))) - } - nameservers, err = parseNameServer(servers, preferH3) - case reflect.String: - nameservers, err = parseNameServer([]string{fmt.Sprintf("%v", server)}, preferH3) - default: - return nil, errors.New("server format error, must be string or array") + servers, err := utils.ToStringSlice(server) + if err != nil { + return nil, err } + nameservers, err := parseNameServer(servers, preferH3) if err != nil { return nil, err } @@ -1041,7 +1055,7 @@ func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainM return sites, nil } -func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[netip.Addr], rules []C.Rule) (*DNS, error) { +func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule) (*DNS, error) { cfg := rawCfg.DNS if cfg.Enable && len(cfg.NameServer) == 0 { return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty") diff --git a/dns/middleware.go b/dns/middleware.go index 7dc9622d..f2dd9c96 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -8,7 +8,7 @@ import ( "github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/common/nnip" "github.com/Dreamacro/clash/component/fakeip" - "github.com/Dreamacro/clash/component/trie" + R "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/context" "github.com/Dreamacro/clash/log" @@ -21,7 +21,7 @@ type ( middleware func(next handler) handler ) -func withHosts(hosts *trie.DomainTrie[netip.Addr], mapping *cache.LruCache[netip.Addr, string]) middleware { +func withHosts(hosts R.Hosts, mapping *cache.LruCache[netip.Addr, string]) middleware { return func(next handler) handler { return func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error) { q := r.Question[0] @@ -31,40 +31,68 @@ func withHosts(hosts *trie.DomainTrie[netip.Addr], mapping *cache.LruCache[netip } host := strings.TrimRight(q.Name, ".") - - record := hosts.Search(host) - if record == nil { + handleCName := func(resp *D.Msg, domain string) { + rr := &D.CNAME{} + rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeCNAME, Class: D.ClassINET, Ttl: 10} + rr.Target = domain + "." + resp.Answer = append([]D.RR{rr}, resp.Answer...) + } + record, ok := hosts.Search(host, q.Qtype != D.TypeA && q.Qtype != D.TypeAAAA) + if !ok { + if record != nil && record.IsDomain { + // replace request domain + newR := r.Copy() + newR.Question[0].Name = record.Domain + "." + resp, err := next(ctx, newR) + if err == nil { + resp.Id = r.Id + resp.Question = r.Question + handleCName(resp, record.Domain) + } + return resp, err + } return next(ctx, r) } - ip := record.Data() msg := r.Copy() - - if ip.Is4() && q.Qtype == D.TypeA { - rr := &D.A{} - rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: 10} - rr.A = ip.AsSlice() - - msg.Answer = []D.RR{rr} - } else if q.Qtype == D.TypeAAAA { - rr := &D.AAAA{} - rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: 10} - ip := ip.As16() - rr.AAAA = ip[:] - msg.Answer = []D.RR{rr} - } else { - return next(ctx, r) + handleIPs := func() { + for _, ipAddr := range record.IPs { + if ipAddr.Is4() && q.Qtype == D.TypeA { + rr := &D.A{} + rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeA, Class: D.ClassINET, Ttl: 10} + rr.A = ipAddr.AsSlice() + msg.Answer = append(msg.Answer, rr) + if mapping != nil { + mapping.SetWithExpire(ipAddr, host, time.Now().Add(time.Second*10)) + } + } else if q.Qtype == D.TypeAAAA { + rr := &D.AAAA{} + rr.Hdr = D.RR_Header{Name: q.Name, Rrtype: D.TypeAAAA, Class: D.ClassINET, Ttl: 10} + ip := ipAddr.As16() + rr.AAAA = ip[:] + msg.Answer = append(msg.Answer, rr) + if mapping != nil { + mapping.SetWithExpire(ipAddr, host, time.Now().Add(time.Second*10)) + } + } + } } - if mapping != nil { - mapping.SetWithExpire(ip, host, time.Now().Add(time.Second*10)) + switch q.Qtype { + case D.TypeA: + handleIPs() + case D.TypeAAAA: + handleIPs() + case D.TypeCNAME: + handleCName(r, record.Domain) + default: + return next(ctx, r) } ctx.SetType(context.DNSTypeHost) msg.SetRcode(r, D.RcodeSuccess) msg.Authoritative = true msg.RecursionAvailable = true - return msg, nil } } @@ -149,6 +177,7 @@ func withFakeIP(fakePool *fakeip.Pool) middleware { func withResolver(resolver *Resolver) handler { return func(ctx *context.DNSContext, r *D.Msg) (*D.Msg, error) { ctx.SetType(context.DNSTypeRaw) + q := r.Question[0] // return a empty AAAA msg when ipv6 disabled @@ -183,7 +212,7 @@ func NewHandler(resolver *Resolver, mapper *ResolverEnhancer) handler { middlewares := []middleware{} if resolver.hosts != nil { - middlewares = append(middlewares, withHosts(resolver.hosts, mapper.mapping)) + middlewares = append(middlewares, withHosts(R.NewHosts(resolver.hosts), mapper.mapping)) } if mapper.mode == C.DNSFakeIP { diff --git a/dns/resolver.go b/dns/resolver.go index 69725870..57f581a5 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -43,7 +43,7 @@ type geositePolicyRecord struct { type Resolver struct { ipv6 bool ipv6Timeout time.Duration - hosts *trie.DomainTrie[netip.Addr] + hosts *trie.DomainTrie[resolver.HostValue] main []dnsClient fallback []dnsClient fallbackDomainFilters []fallbackDomainFilter @@ -430,7 +430,7 @@ type Config struct { EnhancedMode C.DNSMode FallbackFilter FallbackFilter Pool *fakeip.Pool - Hosts *trie.DomainTrie[netip.Addr] + Hosts *trie.DomainTrie[resolver.HostValue] Policy map[string][]NameServer } diff --git a/dns/util.go b/dns/util.go index 203ab615..4821195d 100644 --- a/dns/util.go +++ b/dns/util.go @@ -66,7 +66,7 @@ func setMsgTTL(msg *D.Msg, ttl uint32) { } func isIPRequest(q D.Question) bool { - return q.Qclass == D.ClassINET && (q.Qtype == D.TypeA || q.Qtype == D.TypeAAAA) + return q.Qclass == D.ClassINET && (q.Qtype == D.TypeA || q.Qtype == D.TypeAAAA || q.Qtype == D.TypeCNAME) } func transform(servers []NameServer, resolver *Resolver) []dnsClient { diff --git a/docs/config.yaml b/docs/config.yaml index b5af798b..b52cc63f 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -58,6 +58,9 @@ hosts: # '*.clash.dev': 127.0.0.1 # '.dev': 127.0.0.1 # 'alpha.clash.dev': '::1' +# test.com: [1.1.1.1, 2.2.2.2] +# clash.lan: clash # clash 为特别字段,将加入本地所有网卡的地址 +# baidu.com: google.com # 只允许配置一个别名 profile: # 存储 select 选择记录 store-selected: false diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 1bd22385..21a25ecd 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -226,8 +226,8 @@ func updateDNS(c *config.DNS, generalIPv6 bool) { dns.ReCreateServer(c.Listen, r, m) } -func updateHosts(tree *trie.DomainTrie[netip.Addr]) { - resolver.DefaultHosts = tree +func updateHosts(tree *trie.DomainTrie[resolver.HostValue]) { + resolver.DefaultHosts = resolver.NewHosts(tree) } func updateProxies(proxies map[string]C.Proxy, providers map[string]provider.ProxyProvider) { diff --git a/hub/hub.go b/hub/hub.go index e4c414fa..bd228fad 100644 --- a/hub/hub.go +++ b/hub/hub.go @@ -44,7 +44,7 @@ func Parse(options ...Option) error { if cfg.General.ExternalController != "" { go route.Start(cfg.General.ExternalController, cfg.General.ExternalControllerTLS, - cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey,cfg.General.LogLevel==log.DEBUG) + cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.General.LogLevel == log.DEBUG) } executor.ApplyConfig(cfg, true) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index d80893c9..b686eae6 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -201,13 +201,18 @@ func preHandleMetadata(metadata *C.Metadata) error { if resolver.FakeIPEnabled() { metadata.DstIP = netip.Addr{} metadata.DNSMode = C.DNSFakeIP - } else if node := resolver.DefaultHosts.Search(host); node != nil { + } else if node, ok := resolver.DefaultHosts.Search(host, false); ok { // redir-host should lookup the hosts - metadata.DstIP = node.Data() + metadata.DstIP, _ = node.RandIP() + } else if node != nil && node.IsDomain { + metadata.Host = node.Domain } } else if resolver.IsFakeIP(metadata.DstIP) { return fmt.Errorf("fake DNS record %s missing", metadata.DstIP) } + } else if node, ok := resolver.DefaultHosts.Search(metadata.Host, true); ok { + // try use domain mapping + metadata.Host = node.Domain } return nil @@ -392,8 +397,8 @@ func handleTCPConn(connCtx C.ConnContext) { dialMetadata := metadata if len(metadata.Host) > 0 { - if node := resolver.DefaultHosts.Search(metadata.Host); node != nil { - if dstIp := node.Data(); !FakeIPRange().Contains(dstIp) { + if node, ok := resolver.DefaultHosts.Search(metadata.Host, false); ok { + if dstIp, _ := node.RandIP(); !FakeIPRange().Contains(dstIp) { dialMetadata.DstIP = dstIp dialMetadata.DNSMode = C.DNSHosts dialMetadata = dialMetadata.Pure() @@ -498,8 +503,8 @@ func match(metadata *C.Metadata) (C.Proxy, C.Rule, error) { processFound bool ) - if node := resolver.DefaultHosts.Search(metadata.Host); node != nil { - metadata.DstIP = node.Data() + if node, ok := resolver.DefaultHosts.Search(metadata.Host, false); ok { + metadata.DstIP, _ = node.RandIP() resolved = true } From 074fee2b485e63cdeddde4e90a821db5c7ee6b08 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 12 Mar 2023 15:05:28 +0800 Subject: [PATCH 093/530] chore: add comment --- component/resolver/host.go | 1 + 1 file changed, 1 insertion(+) diff --git a/component/resolver/host.go b/component/resolver/host.go index ca90cd27..49168e2b 100644 --- a/component/resolver/host.go +++ b/component/resolver/host.go @@ -20,6 +20,7 @@ func NewHosts(hosts *trie.DomainTrie[HostValue]) Hosts { } } +// Return the search result and whether to match the parameter `isDomain` func (h *Hosts) Search(domain string, isDomain bool) (*HostValue, bool) { value := h.DomainTrie.Search(domain) if value == nil { From 0a6c848c9e89cc62a60a0dd210d621b06fa87aa6 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 12 Mar 2023 16:42:41 +0800 Subject: [PATCH 094/530] feat: nameserver-policy support multiple keys e.g., nameserver-policy: # 'www.baidu.com': '114.114.114.114' # '+.internal.crop.com': '10.0.0.1' "geosite:cn,private,apple": - https://doh.pub/dns-query - https://dns.alidns.com/dns-query "www.baidu.com,+.google.cn": - 223.5.5.5 - 1.1.1.1 --- config/config.go | 29 +++++++++++++++++++++++++++-- docs/config.yaml | 7 ++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/config/config.go b/config/config.go index 45dd31f5..c8c00664 100644 --- a/config/config.go +++ b/config/config.go @@ -4,11 +4,11 @@ import ( "container/list" "errors" "fmt" - "net" "net/netip" "net/url" "os" + "regexp" "runtime" "strconv" "strings" @@ -985,8 +985,33 @@ func parsePureDNSServer(server string) string { } func parseNameServerPolicy(nsPolicy map[string]any, preferH3 bool) (map[string][]dns.NameServer, error) { policy := map[string][]dns.NameServer{} + updatedPolicy := make(map[string]interface{}) + re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`) - for domain, server := range nsPolicy { + for k, v := range nsPolicy { + if strings.Contains(k, "geosite:") { + subkeys := strings.Split(k, ":") + subkeys = subkeys[1:] + subkeys = strings.Split(subkeys[0], ",") + //log.Infoln("subkeys:%+v", subkeys) + for _, subkey := range subkeys { + newKey := "geosite:" + subkey + //log.Infoln("newKey:%+v", newKey) + updatedPolicy[newKey] = v + } + } else if re.MatchString(k) { + subkeys := strings.Split(k, ",") + //log.Infoln("subkeys:%+v", subkeys) + for _, subkey := range subkeys { + updatedPolicy[subkey] = v + } + } else { + updatedPolicy[k] = v + } + } + //log.Infoln("updatedPolicy:%+v", updatedPolicy) + + for domain, server := range updatedPolicy { servers, err := utils.ToStringSlice(server) if err != nil { diff --git a/docs/config.yaml b/docs/config.yaml index b52cc63f..e08a6e33 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -231,12 +231,13 @@ dns: # - '+.youtube.com' # 配置查询域名使用的 DNS 服务器 - nameserver-policy: # 'www.baidu.com': '114.114.114.114' + nameserver-policy: + # 'www.baidu.com': '114.114.114.114' # '+.internal.crop.com': '10.0.0.1' - "geosite:cn": + "geosite:cn,private,apple": - https://doh.pub/dns-query - https://dns.alidns.com/dns-query - "www.baidu.com": [https://doh.pub/dns-query, https://dns.alidns.com/dns-query] + "www.baidu.com,+.google.cn": [223.5.5.5, https://dns.alidns.com/dns-query] proxies: # socks5 - name: "socks" From 7d230139a06dbf02d4846f6e27e16ddd1598b893 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sun, 12 Mar 2023 18:44:30 +0800 Subject: [PATCH 095/530] fix: rand ip error and `clash` remove loopback ip --- component/resolver/host.go | 4 ++-- config/config.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/component/resolver/host.go b/component/resolver/host.go index 49168e2b..3b7e9a37 100644 --- a/component/resolver/host.go +++ b/component/resolver/host.go @@ -2,12 +2,12 @@ package resolver import ( "errors" - "math/rand" "net/netip" "strings" "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/trie" + "github.com/zhangyunhao116/fastrand" ) type Hosts struct { @@ -109,5 +109,5 @@ func (hv HostValue) RandIP() (netip.Addr, error) { if hv.IsDomain { return netip.Addr{}, errors.New("value type is error") } - return hv.IPs[rand.Intn(len(hv.IPs)-1)], nil + return hv.IPs[fastrand.Intn(len(hv.IPs))], nil } diff --git a/config/config.go b/config/config.go index c8c00664..dfcb772e 100644 --- a/config/config.go +++ b/config/config.go @@ -845,7 +845,7 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) { } else { ips := make([]netip.Addr, 0) for _, addr := range addrs { - if ipnet, ok := addr.(*net.IPNet); ok { + if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil { ips = append(ips, ip) } From 5de043acc6006fb00b3b434aff58d76d2eb685fa Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 Mar 2023 19:03:03 +0800 Subject: [PATCH 096/530] fix: tuic relay tuic --- transport/tuic/conn.go | 30 ++++++++++++++++++++++++++---- transport/tuic/protocol.go | 20 +++++--------------- transport/tuic/server.go | 24 +----------------------- 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index 7ecc3f0d..ee687425 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -200,7 +200,7 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err } func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { - if len(p) > q.maxUdpRelayPacketSize { + if q.udpRelayMode != "quic" && len(p) > q.maxUdpRelayPacketSize { return 0, fmt.Errorf("udp packet too large(%d > %d)", len(p), q.maxUdpRelayPacketSize) } if q.closed { @@ -215,7 +215,6 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro q.deferQuicConnFn(q.quicConn, err) }() } - addr.String() buf := pool.GetBuffer() defer pool.PutBuffer(buf) addrPort, err := netip.ParseAddrPort(addr.String()) @@ -239,7 +238,8 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro return } default: // native - err = q.quicConn.SendMessage(buf.Bytes()) + data := buf.Bytes() + err = q.quicConn.SendMessage(data) if err != nil { return } @@ -250,7 +250,29 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro } func (q *quicStreamPacketConn) LocalAddr() net.Addr { - return q.quicConn.LocalAddr() + addr := q.quicConn.LocalAddr() + if q.inputConn != nil { // client + return &packetAddr{addrStr: q.quicConn.LocalAddr().String(), connId: q.connId, rawAddr: addr} + } + return addr // server } var _ net.PacketConn = &quicStreamPacketConn{} + +type packetAddr struct { + addrStr string + connId uint32 + rawAddr net.Addr +} + +func (a packetAddr) Network() string { + return "tuic" +} + +func (a packetAddr) String() string { + return fmt.Sprintf("%s-%d", a.addrStr, a.connId) +} + +func (a packetAddr) RawAddr() net.Addr { + return a.rawAddr +} diff --git a/transport/tuic/protocol.go b/transport/tuic/protocol.go index a54c8e54..b14074a7 100644 --- a/transport/tuic/protocol.go +++ b/transport/tuic/protocol.go @@ -114,9 +114,6 @@ func NewAuthenticate(TKN [32]byte) Authenticate { func ReadAuthenticateWithHead(head CommandHead, reader BufferedReader) (c Authenticate, err error) { c.CommandHead = head - if err != nil { - return - } if c.CommandHead.TYPE != AuthenticateType { err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) return @@ -170,9 +167,6 @@ func NewConnect(ADDR Address) Connect { func ReadConnectWithHead(head CommandHead, reader BufferedReader) (c Connect, err error) { c.CommandHead = head - if err != nil { - return - } if c.CommandHead.TYPE != ConnectType { err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) return @@ -228,9 +222,6 @@ func NewPacket(ASSOC_ID uint32, LEN uint16, ADDR Address, DATA []byte) Packet { func ReadPacketWithHead(head CommandHead, reader BufferedReader) (c Packet, err error) { c.CommandHead = head - if err != nil { - return - } if c.CommandHead.TYPE != PacketType { err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) return @@ -305,9 +296,6 @@ func NewDissociate(ASSOC_ID uint32) Dissociate { func ReadDissociateWithHead(head CommandHead, reader BufferedReader) (c Dissociate, err error) { c.CommandHead = head - if err != nil { - return - } if c.CommandHead.TYPE != DissociateType { err = fmt.Errorf("error command type: %s", c.CommandHead.TYPE) return @@ -476,15 +464,17 @@ func NewAddress(metadata *C.Metadata) Address { func NewAddressAddrPort(addrPort netip.AddrPort) Address { var addrType byte - if addrPort.Addr().Is4() { + port := addrPort.Port() + addr := addrPort.Addr().Unmap() + if addr.Is4() { addrType = AtypIPv4 } else { addrType = AtypIPv6 } return Address{ TYPE: addrType, - ADDR: addrPort.Addr().AsSlice(), - PORT: addrPort.Port(), + ADDR: addr.AsSlice(), + PORT: port, } } diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 19398fde..770e1869 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -5,7 +5,6 @@ import ( "bytes" "context" "crypto/tls" - "fmt" "net" "sync" "sync/atomic" @@ -154,14 +153,10 @@ func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err err return s.HandleUdpFn(packet.ADDR.SocksAddr(), &serverUDPPacket{ pc: pc, packet: &packet, - rAddr: s.genServerAssocIdAddr(assocId, s.quicConn.RemoteAddr()), + rAddr: &packetAddr{addrStr: "tuic-" + s.uuid.String(), connId: assocId, rawAddr: s.quicConn.RemoteAddr()}, }) } -func (s *serverHandler) genServerAssocIdAddr(assocId uint32, addr net.Addr) net.Addr { - return &ServerAssocIdAddr{assocId: fmt.Sprintf("tuic-%s-%d", s.uuid.String(), assocId), addr: addr} -} - func (s *serverHandler) handleStream() (err error) { for { var quicStream quic.Stream @@ -276,23 +271,6 @@ func (s *serverHandler) handleUniStream() (err error) { } } -type ServerAssocIdAddr struct { - assocId string - addr net.Addr -} - -func (a ServerAssocIdAddr) Network() string { - return "ServerAssocIdAddr" -} - -func (a ServerAssocIdAddr) String() string { - return a.assocId -} - -func (a ServerAssocIdAddr) RawAddr() net.Addr { - return a.addr -} - type serverUDPPacket struct { pc *quicStreamPacketConn packet *Packet From 13111081be154fa07708de7e59e406c763be5fc6 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 Mar 2023 23:37:45 +0800 Subject: [PATCH 097/530] fix: SA4001 for net.UDPAddr copy --- tunnel/connection.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tunnel/connection.go b/tunnel/connection.go index bd8d1b63..e21bbdbf 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -46,7 +46,8 @@ func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, } fromUDPAddr := from.(*net.UDPAddr) - fromUDPAddr = &(*fromUDPAddr) // make a copy + _fromUDPAddr := *fromUDPAddr + fromUDPAddr = &_fromUDPAddr // make a copy if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok { if fAddr.IsValid() && (oAddr.Unmap() == fromAddr.Unmap()) { fromUDPAddr.IP = fAddr.Unmap().AsSlice() From 2f992e986391378bfc31779a23780362aeb7eb69 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 13 Mar 2023 21:19:39 +0800 Subject: [PATCH 098/530] chore: fix issues #440 --- component/tls/utls.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/component/tls/utls.go b/component/tls/utls.go index e08ca7ee..857d598d 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -45,8 +45,13 @@ func GetFingerprint(ClientFingerprint string) (UClientHelloID, bool) { } fingerprint, ok := Fingerprints[ClientFingerprint] - log.Debugln("use specified fingerprint:%s", fingerprint.Client) - return fingerprint, ok + if ok { + log.Debugln("use specified fingerprint:%s", fingerprint.Client) + return fingerprint, ok + } else { + log.Warnln("wrong ClientFingerprint:%s", ClientFingerprint) + return UClientHelloID{}, false + } } func RollFingerprint() (UClientHelloID, bool) { @@ -128,10 +133,7 @@ func SetGlobalUtlsClient(Client string) { } func HaveGlobalFingerprint() bool { - if len(initUtlsClient) != 0 && initUtlsClient != "none" { - return true - } - return false + return len(initUtlsClient) != 0 && initUtlsClient != "none" } func GetGlobalFingerprint() string { From 2fef00d2a8f6bd7b54de52f1b2e3f6de2f84a85f Mon Sep 17 00:00:00 2001 From: 3andne <52860475+3andne@users.noreply.github.com> Date: Mon, 13 Mar 2023 22:33:24 -0700 Subject: [PATCH 099/530] Support Restls-V1 in Clash.Meta (#441) * feat: impl restls * fix: don't break shadowtls' working * chores: correct restls-client-go version * feat: bump restls-client-go version * fix: consistent naming `client-fingerprint` * docs: update example config * chore: adjust client-fingerprint's snippet --------- Co-authored-by: wwqgtxx Co-authored-by: Larvan2 <78135608+Larvan2@users.noreply.github.com> --- adapter/outbound/shadowsocks.go | 64 ++++++++++++++++++++++++--------- adapter/parser.go | 5 +++ docs/config.yaml | 40 ++++++++++++++++++++- go.mod | 1 + go.sum | 2 ++ transport/restls/restls.go | 57 +++++++++++++++++++++++++++++ 6 files changed, 152 insertions(+), 17 deletions(-) create mode 100644 transport/restls/restls.go diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index aab5cf42..49ff45ed 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -12,11 +12,13 @@ import ( "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/transport/restls" obfs "github.com/Dreamacro/clash/transport/simple-obfs" shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls" "github.com/Dreamacro/clash/transport/socks5" v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" + restlsC "github.com/3andne/restls-client-go" shadowsocks "github.com/metacubex/sing-shadowsocks" "github.com/metacubex/sing-shadowsocks/shadowimpl" "github.com/sagernet/sing/common/bufio" @@ -34,19 +36,21 @@ type ShadowSocks struct { obfsOption *simpleObfsOption v2rayOption *v2rayObfs.Option shadowTLSOption *shadowtls.ShadowTLSOption + restlsConfig *restlsC.Config } type ShadowSocksOption struct { BasicOption - Name string `proxy:"name"` - Server string `proxy:"server"` - Port int `proxy:"port"` - Password string `proxy:"password"` - Cipher string `proxy:"cipher"` - UDP bool `proxy:"udp,omitempty"` - Plugin string `proxy:"plugin,omitempty"` - PluginOpts map[string]any `proxy:"plugin-opts,omitempty"` - UDPOverTCP bool `proxy:"udp-over-tcp,omitempty"` + Name string `proxy:"name"` + Server string `proxy:"server"` + Port int `proxy:"port"` + Password string `proxy:"password"` + Cipher string `proxy:"cipher"` + UDP bool `proxy:"udp,omitempty"` + Plugin string `proxy:"plugin,omitempty"` + PluginOpts map[string]any `proxy:"plugin-opts,omitempty"` + UDPOverTCP bool `proxy:"udp-over-tcp,omitempty"` + ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } type simpleObfsOption struct { @@ -66,12 +70,18 @@ type v2rayObfsOption struct { } type shadowTLSOption struct { - Password string `obfs:"password"` - Host string `obfs:"host"` - Fingerprint string `obfs:"fingerprint,omitempty"` - ClientFingerprint string `obfs:"client-fingerprint,omitempty"` - SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` - Version int `obfs:"version,omitempty"` + Password string `obfs:"password"` + Host string `obfs:"host"` + Fingerprint string `obfs:"fingerprint,omitempty"` + SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` + Version int `obfs:"version,omitempty"` +} + +type restlsOption struct { + Password string `obfs:"password"` + Host string `obfs:"host"` + VersionHint string `obfs:"version-hint"` + RestlsScript string `obfs:"restls-script,omitempty"` } // StreamConn implements C.ProxyAdapter @@ -86,6 +96,7 @@ func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e if err != nil { return nil, err } + } return ss.streamConn(c, metadata) } @@ -103,6 +114,12 @@ func (ss *ShadowSocks) streamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } + case restls.Mode: + var err error + c, err = restls.NewRestls(c, ss.restlsConfig) + if err != nil { + return nil, fmt.Errorf("%s (restls) connect error: %w", ss.addr, err) + } } if metadata.NetWork == C.UDP && ss.option.UDPOverTCP { if N.NeedHandshake(c) { @@ -202,6 +219,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { var v2rayOption *v2rayObfs.Option var obfsOption *simpleObfsOption var shadowTLSOpt *shadowtls.ShadowTLSOption + var restlsConfig *restlsC.Config obfsMode := "" decoder := structure.NewDecoder(structure.Option{TagName: "obfs", WeaklyTypedInput: true}) @@ -250,10 +268,23 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { Password: opt.Password, Host: opt.Host, Fingerprint: opt.Fingerprint, - ClientFingerprint: opt.ClientFingerprint, + ClientFingerprint: option.ClientFingerprint, SkipCertVerify: opt.SkipCertVerify, Version: opt.Version, } + } else if option.Plugin == restls.Mode { + obfsMode = restls.Mode + restlsOpt := &restlsOption{} + if err := decoder.Decode(option.PluginOpts, restlsOpt); err != nil { + return nil, fmt.Errorf("ss %s initialize restls-plugin error: %w", addr, err) + } + + restlsConfig, err = restlsC.NewRestlsConfig(restlsOpt.Host, restlsOpt.Password, restlsOpt.VersionHint, restlsOpt.RestlsScript, option.ClientFingerprint) + restlsConfig.SessionTicketsDisabled = true + if err != nil { + return nil, fmt.Errorf("ss %s initialize restls-plugin error: %w", addr, err) + } + } return &ShadowSocks{ @@ -274,6 +305,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { v2rayOption: v2rayOption, obfsOption: obfsOption, shadowTLSOption: shadowTLSOpt, + restlsConfig: restlsConfig, }, nil } diff --git a/adapter/parser.go b/adapter/parser.go index d9c18694..65db74c4 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -24,6 +24,11 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { switch proxyType { case "ss": ssOption := &outbound.ShadowSocksOption{} + + if GlobalUtlsClient := tlsC.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { + ssOption.ClientFingerprint = GlobalUtlsClient + } + err = decoder.Decode(mapping, ssOption) if err != nil { break diff --git a/docs/config.yaml b/docs/config.yaml index e08a6e33..3ef09342 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -331,17 +331,55 @@ proxies: # socks5 # headers: # custom: value - - name: "ss4" + - name: "ss4-shadow-tls" type: ss server: server port: 443 cipher: chacha20-ietf-poly1305 password: "password" plugin: shadow-tls + client-fingerprint: chrome plugin-opts: host: "cloud.tencent.com" password: "shadow_tls_password" version: 2 # support 1/2/3 + + - name: "ss-restls-tls13" + type: ss + server: [YOUR_SERVER_IP] + port: 443 + cipher: chacha20-ietf-poly1305 + password: [YOUR_SS_PASSWORD] + 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" + + - name: "ss-restls-tls12" + type: ss + server: [YOUR_SERVER_IP] + port: 443 + cipher: chacha20-ietf-poly1305 + password: [YOUR_SS_PASSWORD] + 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" # vmess # cipher支持 auto/aes-128-gcm/chacha20-poly1305/none diff --git a/go.mod b/go.mod index bde63cc3..28760b44 100644 --- a/go.mod +++ b/go.mod @@ -51,6 +51,7 @@ require ( ) require ( + github.com/3andne/restls-client-go v0.1.4 github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect diff --git a/go.sum b/go.sum index 7b24bc35..f9e584a2 100644 --- a/go.sum +++ b/go.sum @@ -1,3 +1,5 @@ +github.com/3andne/restls-client-go v0.1.4 h1:kLNC2aSRHPlEVYmTj6EOqJoorCpobEe2toMRSfBF7FU= +github.com/3andne/restls-client-go v0.1.4/go.mod h1:04CGbRk1BwBiEDles8b5mlKgTqIwE5MqF7JDloJV47I= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= diff --git a/transport/restls/restls.go b/transport/restls/restls.go new file mode 100644 index 00000000..4b03b825 --- /dev/null +++ b/transport/restls/restls.go @@ -0,0 +1,57 @@ +package restls + +import ( + "net" + + tls "github.com/3andne/restls-client-go" +) + +const ( + Mode string = "restls" +) + +// Restls +type Restls struct { + net.Conn + firstPacketCache []byte + firstPacket bool +} + +func (r *Restls) Read(b []byte) (int, error) { + if err := r.Conn.(*tls.UConn).Handshake(); err != nil { + return 0, err + } + n, err := r.Conn.(*tls.UConn).Read(b) + return n, err +} + +func (r *Restls) Write(b []byte) (int, error) { + if r.firstPacket { + r.firstPacketCache = append([]byte(nil), b...) + r.firstPacket = false + return len(b), nil + } + if len(r.firstPacketCache) != 0 { + b = append(r.firstPacketCache, b...) + r.firstPacketCache = nil + } + n, err := r.Conn.(*tls.UConn).Write(b) + return n, err +} + +// NewRestls return a Restls Connection +func NewRestls(conn net.Conn, config *tls.Config) (net.Conn, error) { + if config != nil { + clientIDPtr := config.ClientID.Load() + if clientIDPtr != nil { + return &Restls{ + Conn: tls.UClient(conn, config, *clientIDPtr), + firstPacket: true, + }, nil + } + } + return &Restls{ + Conn: tls.UClient(conn, config, tls.HelloChrome_Auto), + firstPacket: true, + }, nil +} From f4251e58a5e933d1da1f0f9896085bd838388537 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 14 Mar 2023 14:23:10 +0800 Subject: [PATCH 100/530] chore: clean up code --- config/config.go | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/config/config.go b/config/config.go index dfcb772e..61222af7 100644 --- a/config/config.go +++ b/config/config.go @@ -989,30 +989,27 @@ func parseNameServerPolicy(nsPolicy map[string]any, preferH3 bool) (map[string][ re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`) for k, v := range nsPolicy { - if strings.Contains(k, "geosite:") { - subkeys := strings.Split(k, ":") - subkeys = subkeys[1:] - subkeys = strings.Split(subkeys[0], ",") - //log.Infoln("subkeys:%+v", subkeys) - for _, subkey := range subkeys { - newKey := "geosite:" + subkey - //log.Infoln("newKey:%+v", newKey) - updatedPolicy[newKey] = v - } - } else if re.MatchString(k) { - subkeys := strings.Split(k, ",") - //log.Infoln("subkeys:%+v", subkeys) - for _, subkey := range subkeys { - updatedPolicy[subkey] = v + if strings.Contains(k, ",") { + if strings.Contains(k, "geosite:") { + subkeys := strings.Split(k, ":") + subkeys = subkeys[1:] + subkeys = strings.Split(subkeys[0], ",") + for _, subkey := range subkeys { + newKey := "geosite:" + subkey + updatedPolicy[newKey] = v + } + } else if re.MatchString(k) { + subkeys := strings.Split(k, ",") + for _, subkey := range subkeys { + updatedPolicy[subkey] = v + } } } else { updatedPolicy[k] = v } } - //log.Infoln("updatedPolicy:%+v", updatedPolicy) for domain, server := range updatedPolicy { - servers, err := utils.ToStringSlice(server) if err != nil { return nil, err From 5816dc295517528dae6b7902114efd552509dd5a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 14 Mar 2023 16:50:27 +0800 Subject: [PATCH 101/530] chore: better restls --- adapter/outbound/shadowsocks.go | 45 +++++++++++++------------------ transport/restls/restls.go | 48 +++++++++++---------------------- 2 files changed, 34 insertions(+), 59 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 49ff45ed..af034472 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -86,22 +86,14 @@ type restlsOption struct { // StreamConn implements C.ProxyAdapter func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { - switch ss.obfsMode { - case shadowtls.Mode: - // fix tls handshake not timeout - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - var err error - c, err = shadowtls.NewShadowTLS(ctx, c, ss.shadowTLSOption) - if err != nil { - return nil, err - } - - } - return ss.streamConn(c, metadata) + // fix tls handshake not timeout + ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) + defer cancel() + return ss.StreamConnContext(ctx, c, metadata) } -func (ss *ShadowSocks) streamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { + useEarly := false switch ss.obfsMode { case "tls": c = obfs.NewTLSObfs(c, ss.obfsOption.Host) @@ -114,21 +106,30 @@ func (ss *ShadowSocks) streamConn(c net.Conn, metadata *C.Metadata) (net.Conn, e if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } + case shadowtls.Mode: + var err error + c, err = shadowtls.NewShadowTLS(ctx, c, ss.shadowTLSOption) + if err != nil { + return nil, err + } + useEarly = true case restls.Mode: var err error - c, err = restls.NewRestls(c, ss.restlsConfig) + c, err = restls.NewRestls(ctx, c, ss.restlsConfig) if err != nil { return nil, fmt.Errorf("%s (restls) connect error: %w", ss.addr, err) } + useEarly = true } + useEarly = useEarly || N.NeedHandshake(c) if metadata.NetWork == C.UDP && ss.option.UDPOverTCP { - if N.NeedHandshake(c) { + if useEarly { return ss.method.DialEarlyConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")), nil } else { return ss.method.DialConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")) } } - if N.NeedHandshake(c) { + if useEarly { return ss.method.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil } else { return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) @@ -152,15 +153,7 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale safeConnClose(c, err) }(c) - switch ss.obfsMode { - case shadowtls.Mode: - c, err = shadowtls.NewShadowTLS(ctx, c, ss.shadowTLSOption) - if err != nil { - return nil, err - } - } - - c, err = ss.streamConn(c, metadata) + c, err = ss.StreamConnContext(ctx, c, metadata) return NewConn(c, ss), err } diff --git a/transport/restls/restls.go b/transport/restls/restls.go index 4b03b825..0f3ba8ac 100644 --- a/transport/restls/restls.go +++ b/transport/restls/restls.go @@ -1,6 +1,7 @@ package restls import ( + "context" "net" tls "github.com/3andne/restls-client-go" @@ -10,48 +11,29 @@ const ( Mode string = "restls" ) -// Restls type Restls struct { - net.Conn - firstPacketCache []byte - firstPacket bool + *tls.UConn } -func (r *Restls) Read(b []byte) (int, error) { - if err := r.Conn.(*tls.UConn).Handshake(); err != nil { - return 0, err - } - n, err := r.Conn.(*tls.UConn).Read(b) - return n, err -} - -func (r *Restls) Write(b []byte) (int, error) { - if r.firstPacket { - r.firstPacketCache = append([]byte(nil), b...) - r.firstPacket = false - return len(b), nil - } - if len(r.firstPacketCache) != 0 { - b = append(r.firstPacketCache, b...) - r.firstPacketCache = nil - } - n, err := r.Conn.(*tls.UConn).Write(b) - return n, err +func (r *Restls) Upstream() any { + return r.UConn.NetConn() } // NewRestls return a Restls Connection -func NewRestls(conn net.Conn, config *tls.Config) (net.Conn, error) { +func NewRestls(ctx context.Context, conn net.Conn, config *tls.Config) (net.Conn, error) { + clientHellowID := tls.HelloChrome_Auto if config != nil { clientIDPtr := config.ClientID.Load() if clientIDPtr != nil { - return &Restls{ - Conn: tls.UClient(conn, config, *clientIDPtr), - firstPacket: true, - }, nil + clientHellowID = *clientIDPtr } } - return &Restls{ - Conn: tls.UClient(conn, config, tls.HelloChrome_Auto), - firstPacket: true, - }, nil + restls := &Restls{ + UConn: tls.UClient(conn, config, clientHellowID), + } + if err := restls.HandshakeContext(ctx); err != nil { + return nil, err + } + + return restls, nil } From 6ba82c6d850909b053f2367a64c27e541a53bc16 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 14 Mar 2023 17:45:37 +0800 Subject: [PATCH 102/530] chore: cleanup code --- adapter/parser.go | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/adapter/parser.go b/adapter/parser.go index 65db74c4..1f626f33 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -23,12 +23,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { ) switch proxyType { case "ss": - ssOption := &outbound.ShadowSocksOption{} - - if GlobalUtlsClient := tlsC.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { - ssOption.ClientFingerprint = GlobalUtlsClient - } - + ssOption := &outbound.ShadowSocksOption{ClientFingerprint: tlsC.GetGlobalFingerprint()} err = decoder.Decode(mapping, ssOption) if err != nil { break @@ -61,10 +56,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { Method: "GET", Path: []string{"/"}, }, - } - - if GlobalUtlsClient := tlsC.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { - vmessOption.ClientFingerprint = GlobalUtlsClient + ClientFingerprint: tlsC.GetGlobalFingerprint(), } err = decoder.Decode(mapping, vmessOption) @@ -73,12 +65,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { } proxy, err = outbound.NewVmess(*vmessOption) case "vless": - vlessOption := &outbound.VlessOption{} - - if GlobalUtlsClient := tlsC.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { - vlessOption.ClientFingerprint = GlobalUtlsClient - } - + vlessOption := &outbound.VlessOption{ClientFingerprint: tlsC.GetGlobalFingerprint()} err = decoder.Decode(mapping, vlessOption) if err != nil { break @@ -92,12 +79,7 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { } proxy, err = outbound.NewSnell(*snellOption) case "trojan": - trojanOption := &outbound.TrojanOption{} - - if GlobalUtlsClient := tlsC.GetGlobalFingerprint(); len(GlobalUtlsClient) != 0 { - trojanOption.ClientFingerprint = GlobalUtlsClient - } - + trojanOption := &outbound.TrojanOption{ClientFingerprint: tlsC.GetGlobalFingerprint()} err = decoder.Decode(mapping, trojanOption) if err != nil { break From 88116d90324b86f49b990daeabad3cc96bd6b690 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 14 Mar 2023 20:10:52 +0800 Subject: [PATCH 103/530] fix: optimize health check --- adapter/provider/healthcheck.go | 24 ++++++------------------ adapter/provider/provider.go | 2 +- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 6f79cd05..d1624cad 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -34,16 +34,15 @@ type HealthCheck struct { func (hc *HealthCheck) process() { ticker := time.NewTicker(time.Duration(hc.interval) * time.Second) - - go func() { - time.Sleep(30 * time.Second) - hc.lazyCheck() - }() - for { select { case <-ticker.C: - hc.lazyCheck() + now := time.Now().Unix() + if !hc.lazy || now-hc.lastTouch.Load() < int64(hc.interval) { + hc.check() + } else { + log.Debugln("Skip once health check because we are lazy") + } case <-hc.done: ticker.Stop() return @@ -51,17 +50,6 @@ func (hc *HealthCheck) process() { } } -func (hc *HealthCheck) lazyCheck() bool { - now := time.Now().Unix() - if !hc.lazy || now-hc.lastTouch.Load() < int64(hc.interval) { - hc.check() - return true - } else { - log.Debugln("Skip once health check because we are lazy") - return false - } -} - func (hc *HealthCheck) setProxy(proxies []C.Proxy) { hc.proxies = proxies } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index e8bd7ed1..1ea346bf 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -99,7 +99,7 @@ func (pp *proxySetProvider) setProxies(proxies []C.Proxy) { pp.proxies = proxies pp.healthCheck.setProxy(proxies) if pp.healthCheck.auto() { - defer func() { go pp.healthCheck.lazyCheck() }() + go pp.healthCheck.check() } } From 0f24c2f849a9ff87da61a4f39db3cec422bc8c80 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 14 Mar 2023 22:18:55 +0800 Subject: [PATCH 104/530] chore: add /restart to restful api --- hub/route/restart.go | 53 ++++++++++++++++++++++++++++++++++++++++++++ hub/route/server.go | 1 + 2 files changed, 54 insertions(+) create mode 100644 hub/route/restart.go diff --git a/hub/route/restart.go b/hub/route/restart.go new file mode 100644 index 00000000..196896a3 --- /dev/null +++ b/hub/route/restart.go @@ -0,0 +1,53 @@ +package route + +import ( + "fmt" + "net/http" + "os" + "os/exec" + "runtime" + "syscall" + + "github.com/Dreamacro/clash/log" + + "github.com/go-chi/chi/v5" + "github.com/go-chi/render" +) + +func restartRouter() http.Handler { + r := chi.NewRouter() + r.Post("/", restart) + return r +} + +func restart(w http.ResponseWriter, r *http.Request) { + // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L180 + execPath, err := os.Executable() + if err != nil { + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, newError(fmt.Sprintf("getting path: %s", err))) + return + } + + if runtime.GOOS == "windows" { + cmd := exec.Command(execPath, os.Args[1:]...) + log.Infoln("restarting: %q %q", execPath, os.Args[1:]) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Start() + if err != nil { + log.Fatalln("restarting:: %s", err) + } + + os.Exit(0) + } + + log.Infoln("restarting: %q %q", execPath, os.Args[1:]) + err = syscall.Exec(execPath, os.Args, os.Environ()) + if err != nil { + log.Fatalln("restarting: %s", err) + } + + render.JSON(w, r, render.M{"status": "ok"}) +} diff --git a/hub/route/server.go b/hub/route/server.go index 2ce4ba8c..054b1ad1 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -86,6 +86,7 @@ func Start(addr string, tlsAddr string, secret string, r.Mount("/providers/rules", ruleProviderRouter()) r.Mount("/cache", cacheRouter()) r.Mount("/dns", dnsRouter()) + r.Mount("/restart", restartRouter()) }) if uiPath != "" { From 09c53e7cb7def6e627918f98e8d954d1e10afe14 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 14 Mar 2023 22:37:07 +0800 Subject: [PATCH 105/530] chore: Chore: adjust the loading order, and then load the resource at last --- constant/status.go | 9 ++++++++ hub/executor/executor.go | 48 +++++++++++++++++----------------------- tunnel/tunnel.go | 25 +++++++++++++++++++++ 3 files changed, 54 insertions(+), 28 deletions(-) create mode 100644 constant/status.go diff --git a/constant/status.go b/constant/status.go new file mode 100644 index 00000000..4a784bfa --- /dev/null +++ b/constant/status.go @@ -0,0 +1,9 @@ +package constant + +type TunnelStatus uint8 + +const ( + TunnelSuspend TunnelStatus = iota + TunnelInner + TunnelRunning +) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 21a25ecd..1b2ec572 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -75,24 +75,38 @@ func ParseWithBytes(buf []byte) (*config.Config, error) { func ApplyConfig(cfg *config.Config, force bool) { mux.Lock() defer mux.Unlock() - preUpdateExperimental(cfg) + + tunnel.OnSuspend() + + CTLS.ResetCertificate() + for _, c := range cfg.TLS.CustomTrustCert { + if err := CTLS.AddCertificate(c); err != nil { + log.Warnln("%s\nadd error: %s", c, err.Error()) + } + } + updateUsers(cfg.Users) updateProxies(cfg.Proxies, cfg.Providers) updateRules(cfg.Rules, cfg.SubRules, cfg.RuleProviders) updateSniffer(cfg.Sniffer) updateHosts(cfg.Hosts) updateGeneral(cfg.General) - initInnerTcp() updateDNS(cfg.DNS, cfg.General.IPv6) - loadProxyProvider(cfg.Providers) - updateProfile(cfg) - loadRuleProvider(cfg.RuleProviders) updateListeners(cfg.General, cfg.Listeners, force) updateIPTables(cfg) updateTun(cfg.General) updateExperimental(cfg) updateTunnels(cfg.Tunnels) + tunnel.OnInnerLoading() + + initInnerTcp() + loadProxyProvider(cfg.Providers) + updateProfile(cfg) + loadRuleProvider(cfg.RuleProviders) + + tunnel.OnRunning() + log.SetLevel(cfg.General.LogLevel) } @@ -144,10 +158,6 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList return } - if general.Interface == "" && (!general.Tun.Enable || !general.Tun.AutoDetectInterface) { - dialer.DefaultInterface.Store(general.Interface) - } - allowLan := general.AllowLan listener.SetAllowLan(allowLan) @@ -168,15 +178,6 @@ func updateExperimental(c *config.Config) { runtime.GC() } -func preUpdateExperimental(c *config.Config) { - CTLS.ResetCertificate() - for _, c := range c.TLS.CustomTrustCert { - if err := CTLS.AddCertificate(c); err != nil { - log.Warnln("%s\nadd error: %s", c, err.Error()) - } - } -} - func updateDNS(c *config.DNS, generalIPv6 bool) { if !c.Enable { resolver.DefaultResolver = nil @@ -342,17 +343,8 @@ func updateGeneral(general *config.General) { inbound.SetTfo(general.InboundTfo) adapter.UnifiedDelay.Store(general.UnifiedDelay) - // Avoid reload configuration clean the value, causing traffic loops - if listener.GetTunConf().Enable && listener.GetTunConf().AutoDetectInterface { - // changed only when the name is specified - // if name is empty, setting delay until after tun loaded - if general.Interface != "" && (!general.Tun.Enable || !general.Tun.AutoDetectInterface) { - dialer.DefaultInterface.Store(general.Interface) - } - } else { - dialer.DefaultInterface.Store(general.Interface) - } + dialer.DefaultInterface.Store(general.Interface) dialer.DefaultRoutingMark.Store(int32(general.RoutingMark)) if general.RoutingMark > 0 { log.Infoln("Use routing mark: %#x", general.RoutingMark) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index b686eae6..aad1dda7 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -26,6 +26,7 @@ import ( ) var ( + status C.TunnelStatus tcpQueue = make(chan C.ConnContext, 200) udpQueue = make(chan C.PacketAdapter, 200) natTable = nat.New() @@ -49,6 +50,18 @@ var ( fakeIPRange netip.Prefix ) +func OnSuspend() { + status = C.TunnelSuspend +} + +func OnInnerLoading() { + status = C.TunnelInner +} + +func OnRunning() { + status = C.TunnelRunning +} + func SetFakeIPRange(p netip.Prefix) { fakeIPRange = p } @@ -158,10 +171,18 @@ func SetFindProcessMode(mode P.FindProcessMode) { findProcessMode = mode } +func isHandle(t C.Type) bool { + return status == C.TunnelRunning || (status == C.TunnelInner && t == C.INNER) +} + // processUDP starts a loop to handle udp packet func processUDP() { queue := udpQueue for conn := range queue { + if !isHandle(conn.Metadata().Type) { + conn.Drop() + continue + } handleUDPConn(conn) } } @@ -177,6 +198,10 @@ func process() { queue := tcpQueue for conn := range queue { + if !isHandle(conn.Metadata().Type) { + _ = conn.Conn().Close() + continue + } go handleTCPConn(conn) } } From 68d7a6da7f795045d9090016cb74ed16dd4fd43f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 14 Mar 2023 22:38:42 +0800 Subject: [PATCH 106/530] fix: ensure restart api return ok --- hub/route/restart.go | 49 ++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/hub/route/restart.go b/hub/route/restart.go index 196896a3..bbf83f5e 100644 --- a/hub/route/restart.go +++ b/hub/route/restart.go @@ -21,7 +21,7 @@ func restartRouter() http.Handler { } func restart(w http.ResponseWriter, r *http.Request) { - // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L180 + // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L108 execPath, err := os.Executable() if err != nil { render.Status(r, http.StatusInternalServerError) @@ -29,25 +29,34 @@ func restart(w http.ResponseWriter, r *http.Request) { return } - if runtime.GOOS == "windows" { - cmd := exec.Command(execPath, os.Args[1:]...) - log.Infoln("restarting: %q %q", execPath, os.Args[1:]) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err = cmd.Start() - if err != nil { - log.Fatalln("restarting:: %s", err) + render.JSON(w, r, render.M{"status": "ok"}) + if f, ok := w.(http.Flusher); ok { + f.Flush() + } + + // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L180 + // The background context is used because the underlying functions wrap it + // with timeout and shut down the server, which handles current request. It + // also should be done in a separate goroutine for the same reason. + go func() { + if runtime.GOOS == "windows" { + cmd := exec.Command(execPath, os.Args[1:]...) + log.Infoln("restarting: %q %q", execPath, os.Args[1:]) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Start() + if err != nil { + log.Fatalln("restarting:: %s", err) + } + + os.Exit(0) } - os.Exit(0) - } - - log.Infoln("restarting: %q %q", execPath, os.Args[1:]) - err = syscall.Exec(execPath, os.Args, os.Environ()) - if err != nil { - log.Fatalln("restarting: %s", err) - } - - render.JSON(w, r, render.M{"status": "ok"}) + log.Infoln("restarting: %q %q", execPath, os.Args[1:]) + err = syscall.Exec(execPath, os.Args, os.Environ()) + if err != nil { + log.Fatalln("restarting: %s", err) + } + }() } From cf7520ec22d0c6bcbbfb365dfec96f3dbea7fb6f Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 14 Mar 2023 22:57:43 +0800 Subject: [PATCH 107/530] chore: disconnect when suspended --- tunnel/tunnel.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index aad1dda7..342cdd65 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -12,6 +12,7 @@ import ( "time" "github.com/jpillora/backoff" + "go.uber.org/atomic" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/nat" @@ -26,7 +27,7 @@ import ( ) var ( - status C.TunnelStatus + status = atomic.NewInt32(int32(C.TunnelSuspend)) tcpQueue = make(chan C.ConnContext, 200) udpQueue = make(chan C.PacketAdapter, 200) natTable = nat.New() @@ -51,15 +52,18 @@ var ( ) func OnSuspend() { - status = C.TunnelSuspend + status.Store(int32(C.TunnelSuspend)) + for _, c := range statistic.DefaultManager.Snapshot().Connections { + _ = c.Close() + } } func OnInnerLoading() { - status = C.TunnelInner + status.Store(int32(C.TunnelInner)) } func OnRunning() { - status = C.TunnelRunning + status.Store(int32(C.TunnelRunning)) } func SetFakeIPRange(p netip.Prefix) { @@ -172,6 +176,7 @@ func SetFindProcessMode(mode P.FindProcessMode) { } func isHandle(t C.Type) bool { + status := C.TunnelStatus(status.Load()) return status == C.TunnelRunning || (status == C.TunnelInner && t == C.INNER) } From 8dda9fdb70beff793f41f5aa5a6f6629c726c1fa Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 14 Mar 2023 23:52:27 +0800 Subject: [PATCH 108/530] fix: The default interface is actually configured incorrectly --- config/config.go | 1 - 1 file changed, 1 deletion(-) diff --git a/config/config.go b/config/config.go index 61222af7..457ce72f 100644 --- a/config/config.go +++ b/config/config.go @@ -451,7 +451,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint) } - dialer.DefaultInterface.Store(config.General.Interface) proxies, providers, err := parseProxies(rawCfg) if err != nil { return nil, err From 53928eb895f3437ed4338731f8e6909ba4f7b23e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 15 Mar 2023 00:10:54 +0800 Subject: [PATCH 109/530] chore: better TunnelStatus define --- constant/status.go | 9 ----- tunnel/status.go | 92 ++++++++++++++++++++++++++++++++++++++++++++++ tunnel/tunnel.go | 17 +++++---- 3 files changed, 102 insertions(+), 16 deletions(-) delete mode 100644 constant/status.go create mode 100644 tunnel/status.go diff --git a/constant/status.go b/constant/status.go deleted file mode 100644 index 4a784bfa..00000000 --- a/constant/status.go +++ /dev/null @@ -1,9 +0,0 @@ -package constant - -type TunnelStatus uint8 - -const ( - TunnelSuspend TunnelStatus = iota - TunnelInner - TunnelRunning -) diff --git a/tunnel/status.go b/tunnel/status.go new file mode 100644 index 00000000..d81dd45e --- /dev/null +++ b/tunnel/status.go @@ -0,0 +1,92 @@ +package tunnel + +import ( + "encoding/json" + "errors" + "strings" + "sync/atomic" +) + +type TunnelStatus int + +// StatusMapping is a mapping for Status enum +var StatusMapping = map[string]TunnelStatus{ + Suspend.String(): Suspend, + Inner.String(): Inner, + Running.String(): Running, +} + +const ( + Suspend TunnelStatus = iota + Inner + Running +) + +// UnmarshalJSON unserialize Status +func (s *TunnelStatus) UnmarshalJSON(data []byte) error { + var tp string + json.Unmarshal(data, &tp) + status, exist := StatusMapping[strings.ToLower(tp)] + if !exist { + return errors.New("invalid mode") + } + *s = status + return nil +} + +// UnmarshalYAML unserialize Status with yaml +func (s *TunnelStatus) UnmarshalYAML(unmarshal func(any) error) error { + var tp string + unmarshal(&tp) + status, exist := StatusMapping[strings.ToLower(tp)] + if !exist { + return errors.New("invalid status") + } + *s = status + return nil +} + +// MarshalJSON serialize Status +func (s TunnelStatus) MarshalJSON() ([]byte, error) { + return json.Marshal(s.String()) +} + +// MarshalYAML serialize TunnelMode with yaml +func (s TunnelStatus) MarshalYAML() (any, error) { + return s.String(), nil +} + +func (s TunnelStatus) String() string { + switch s { + case Suspend: + return "suspend" + case Inner: + return "inner" + case Running: + return "running" + default: + return "Unknown" + } +} + +type AtomicStatus struct { + value atomic.Int32 +} + +func (a *AtomicStatus) Store(s TunnelStatus) { + a.value.Store(int32(s)) +} + +func (a *AtomicStatus) Load() TunnelStatus { + return TunnelStatus(a.value.Load()) +} + +func (a *AtomicStatus) String() string { + return a.Load().String() +} + +func newAtomicStatus(s TunnelStatus) *AtomicStatus { + a := &AtomicStatus{} + a.Store(s) + return a +} diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 342cdd65..532c9e0e 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -12,7 +12,6 @@ import ( "time" "github.com/jpillora/backoff" - "go.uber.org/atomic" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/nat" @@ -27,7 +26,7 @@ import ( ) var ( - status = atomic.NewInt32(int32(C.TunnelSuspend)) + status = newAtomicStatus(Suspend) tcpQueue = make(chan C.ConnContext, 200) udpQueue = make(chan C.PacketAdapter, 200) natTable = nat.New() @@ -52,18 +51,22 @@ var ( ) func OnSuspend() { - status.Store(int32(C.TunnelSuspend)) + status.Store(Suspend) for _, c := range statistic.DefaultManager.Snapshot().Connections { _ = c.Close() } } func OnInnerLoading() { - status.Store(int32(C.TunnelInner)) + status.Store(Inner) } func OnRunning() { - status.Store(int32(C.TunnelRunning)) + status.Store(Running) +} + +func Status() TunnelStatus { + return status.Load() } func SetFakeIPRange(p netip.Prefix) { @@ -176,8 +179,8 @@ func SetFindProcessMode(mode P.FindProcessMode) { } func isHandle(t C.Type) bool { - status := C.TunnelStatus(status.Load()) - return status == C.TunnelRunning || (status == C.TunnelInner && t == C.INNER) + status := status.Load() + return status == Running || (status == Inner && t == C.INNER) } // processUDP starts a loop to handle udp packet From 9d9bd245f3abed0c98c64ee25297277a598bd6b9 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 15 Mar 2023 09:05:16 +0800 Subject: [PATCH 110/530] fix: Adjust the timing of subscription information acquisition --- adapter/provider/provider.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 1ea346bf..4a2cf7b8 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -80,6 +80,7 @@ func (pp *proxySetProvider) Initial() error { return err } pp.OnUpdate(elm) + pp.getSubscriptionInfo() return nil } @@ -172,8 +173,6 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, exc fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg), proxiesOnUpdate(pd)) pd.Fetcher = fetcher - - pd.getSubscriptionInfo() wrapper := &ProxySetProvider{pd} runtime.SetFinalizer(wrapper, stopProxyProvider) return wrapper, nil From 5d0efb5472455e35d8a0c9b1e066333f98fb4712 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 15 Mar 2023 09:18:03 +0800 Subject: [PATCH 111/530] chore: keep existing connections --- tunnel/tunnel.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 532c9e0e..c4f55fbd 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -52,9 +52,6 @@ var ( func OnSuspend() { status.Store(Suspend) - for _, c := range statistic.DefaultManager.Snapshot().Connections { - _ = c.Close() - } } func OnInnerLoading() { From 516c219580f6abdec7fa9584fd8597d5f4d55ee6 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 15 Mar 2023 09:55:48 +0800 Subject: [PATCH 112/530] fix: let quic-go works on outbound's packetConn --- adapter/outbound/base.go | 10 +++++++++- common/net/addr.go | 36 ++++++++++++++++++++++++++++++++++++ transport/tuic/conn.go | 24 +----------------------- transport/tuic/server.go | 3 ++- 4 files changed, 48 insertions(+), 25 deletions(-) create mode 100644 common/net/addr.go diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index b69311f6..a9615be0 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -210,6 +210,8 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { type packetConn struct { net.PacketConn chain C.Chain + adapterName string + connID string actualRemoteDestination string } @@ -227,8 +229,14 @@ func (c *packetConn) AppendToChains(a C.ProxyAdapter) { c.chain = append(c.chain, a.Name()) } +func (c *packetConn) LocalAddr() net.Addr { + lAddr := c.PacketConn.LocalAddr() + return N.NewCustomAddr(c.adapterName, c.connID, lAddr) // make quic-go's connMultiplexer happy +} + func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn { - return &packetConn{pc, []string{a.Name()}, parseRemoteDestination(a.Addr())} + id, _ := utils.UnsafeUUIDGenerator.NewV4() + return &packetConn{pc, []string{a.Name()}, a.Name(), id.String(), parseRemoteDestination(a.Addr())} } func parseRemoteDestination(addr string) string { diff --git a/common/net/addr.go b/common/net/addr.go new file mode 100644 index 00000000..4efaefcd --- /dev/null +++ b/common/net/addr.go @@ -0,0 +1,36 @@ +package net + +import ( + "net" +) + +type CustomAddr interface { + net.Addr + RawAddr() net.Addr +} + +type customAddr struct { + networkStr string + addrStr string + rawAddr net.Addr +} + +func (a customAddr) Network() string { + return a.networkStr +} + +func (a customAddr) String() string { + return a.addrStr +} + +func (a customAddr) RawAddr() net.Addr { + return a.rawAddr +} + +func NewCustomAddr(networkStr string, addrStr string, rawAddr net.Addr) CustomAddr { + return customAddr{ + networkStr: networkStr, + addrStr: addrStr, + rawAddr: rawAddr, + } +} diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index ee687425..dfa43e1f 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -250,29 +250,7 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro } func (q *quicStreamPacketConn) LocalAddr() net.Addr { - addr := q.quicConn.LocalAddr() - if q.inputConn != nil { // client - return &packetAddr{addrStr: q.quicConn.LocalAddr().String(), connId: q.connId, rawAddr: addr} - } - return addr // server + return q.quicConn.LocalAddr() } var _ net.PacketConn = &quicStreamPacketConn{} - -type packetAddr struct { - addrStr string - connId uint32 - rawAddr net.Addr -} - -func (a packetAddr) Network() string { - return "tuic" -} - -func (a packetAddr) String() string { - return fmt.Sprintf("%s-%d", a.addrStr, a.connId) -} - -func (a packetAddr) RawAddr() net.Addr { - return a.rawAddr -} diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 770e1869..b23f3ae9 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -5,6 +5,7 @@ import ( "bytes" "context" "crypto/tls" + "fmt" "net" "sync" "sync/atomic" @@ -153,7 +154,7 @@ func (s *serverHandler) parsePacket(packet Packet, udpRelayMode string) (err err return s.HandleUdpFn(packet.ADDR.SocksAddr(), &serverUDPPacket{ pc: pc, packet: &packet, - rAddr: &packetAddr{addrStr: "tuic-" + s.uuid.String(), connId: assocId, rawAddr: s.quicConn.RemoteAddr()}, + rAddr: N.NewCustomAddr("tuic", fmt.Sprintf("tuic-%s-%d", s.uuid, assocId), s.quicConn.RemoteAddr()), // for tunnel's handleUDPConn }) } From f7610ce2ad7525be367bc43e584e609d8da3d121 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 15 Mar 2023 10:10:03 +0800 Subject: [PATCH 113/530] chore: better uuid using --- adapter/outbound/base.go | 10 ++-------- adapter/provider/healthcheck.go | 5 +---- common/convert/util.go | 3 +-- common/utils/uuid.go | 30 +++++++++++++++++++++++++++++- context/conn.go | 4 +--- context/dns.go | 3 +-- context/packetconn.go | 3 +-- transport/tuic/server.go | 6 +----- tunnel/statistic/tracker.go | 6 ++---- 9 files changed, 39 insertions(+), 31 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index a9615be0..156bc114 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -34,12 +34,7 @@ func (b *Base) Name() string { // Id implements C.ProxyAdapter func (b *Base) Id() string { if b.id == "" { - id, err := utils.UnsafeUUIDGenerator.NewV6() - if err != nil { - b.id = b.name - } else { - b.id = id.String() - } + b.id = utils.NewUUIDV6().String() } return b.id @@ -235,8 +230,7 @@ func (c *packetConn) LocalAddr() net.Addr { } func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn { - id, _ := utils.UnsafeUUIDGenerator.NewV4() - return &packetConn{pc, []string{a.Name()}, a.Name(), id.String(), parseRemoteDestination(a.Addr())} + return &packetConn{pc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} } func parseRemoteDestination(addr string) string { diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index d1624cad..9deb7b82 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -64,10 +64,7 @@ func (hc *HealthCheck) touch() { func (hc *HealthCheck) check() { _, _, _ = hc.singleDo.Do(func() (struct{}, error) { - id := "" - if uid, err := utils.UnsafeUUIDGenerator.NewV4(); err == nil { - id = uid.String() - } + 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 { diff --git a/common/convert/util.go b/common/convert/util.go index 4f86e616..0ec35acd 100644 --- a/common/convert/util.go +++ b/common/convert/util.go @@ -294,8 +294,7 @@ var ( ) func RandHost() string { - id, _ := utils.UnsafeUUIDGenerator.NewV4() - base := strings.ToLower(base64.RawURLEncoding.EncodeToString(id.Bytes())) + base := strings.ToLower(base64.RawURLEncoding.EncodeToString(utils.NewUUIDV4().Bytes())) base = strings.ReplaceAll(base, "-", "") base = strings.ReplaceAll(base, "_", "") buf := []byte(base) diff --git a/common/utils/uuid.go b/common/utils/uuid.go index d043ae37..930fda7d 100644 --- a/common/utils/uuid.go +++ b/common/utils/uuid.go @@ -13,11 +13,39 @@ func (r fastRandReader) Read(p []byte) (int, error) { var UnsafeUUIDGenerator = uuid.NewGenWithOptions(uuid.WithRandomReader(fastRandReader{})) +func NewUUIDV1() uuid.UUID { + u, _ := UnsafeUUIDGenerator.NewV1() // fastrand.Read wouldn't cause error, so ignore err is safe + return u +} + +func NewUUIDV3(ns uuid.UUID, name string) uuid.UUID { + return UnsafeUUIDGenerator.NewV3(ns, name) +} + +func NewUUIDV4() uuid.UUID { + u, _ := UnsafeUUIDGenerator.NewV4() // fastrand.Read wouldn't cause error, so ignore err is safe + return u +} + +func NewUUIDV5(ns uuid.UUID, name string) uuid.UUID { + return UnsafeUUIDGenerator.NewV5(ns, name) +} + +func NewUUIDV6() uuid.UUID { + u, _ := UnsafeUUIDGenerator.NewV6() // fastrand.Read wouldn't cause error, so ignore err is safe + return u +} + +func NewUUIDV7() uuid.UUID { + u, _ := UnsafeUUIDGenerator.NewV7() // fastrand.Read wouldn't cause error, so ignore err is safe + return u +} + // UUIDMap https://github.com/XTLS/Xray-core/issues/158#issue-783294090 func UUIDMap(str string) (uuid.UUID, error) { u, err := uuid.FromString(str) if err != nil { - return UnsafeUUIDGenerator.NewV5(uuid.Nil, str), nil + return NewUUIDV5(uuid.Nil, str), nil } return u, nil } diff --git a/context/conn.go b/context/conn.go index 35ea788d..c5477780 100644 --- a/context/conn.go +++ b/context/conn.go @@ -17,10 +17,8 @@ type ConnContext struct { } func NewConnContext(conn net.Conn, metadata *C.Metadata) *ConnContext { - id, _ := utils.UnsafeUUIDGenerator.NewV4() - return &ConnContext{ - id: id, + id: utils.NewUUIDV4(), metadata: metadata, conn: N.NewBufferedConn(conn), } diff --git a/context/dns.go b/context/dns.go index 80a4c988..c41de724 100644 --- a/context/dns.go +++ b/context/dns.go @@ -23,11 +23,10 @@ type DNSContext struct { } func NewDNSContext(ctx context.Context, msg *dns.Msg) *DNSContext { - id, _ := utils.UnsafeUUIDGenerator.NewV4() return &DNSContext{ Context: ctx, - id: id, + id: utils.NewUUIDV4(), msg: msg, } } diff --git a/context/packetconn.go b/context/packetconn.go index 87a9290a..b9afef41 100644 --- a/context/packetconn.go +++ b/context/packetconn.go @@ -16,9 +16,8 @@ type PacketConnContext struct { } func NewPacketConnContext(metadata *C.Metadata) *PacketConnContext { - id, _ := utils.UnsafeUUIDGenerator.NewV4() return &PacketConnContext{ - id: id, + id: utils.NewUUIDV4(), metadata: metadata, } } diff --git a/transport/tuic/server.go b/transport/tuic/server.go index b23f3ae9..5eb6e611 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -56,14 +56,10 @@ func (s *Server) Serve() error { return err } SetCongestionController(conn, s.CongestionController) - uuid, err := utils.UnsafeUUIDGenerator.NewV4() - if err != nil { - return err - } h := &serverHandler{ Server: s, quicConn: conn, - uuid: uuid, + uuid: utils.NewUUIDV4(), authCh: make(chan struct{}), } go h.handle() diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index bb5678b8..f7e9d971 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -83,7 +83,6 @@ func (tt *tcpTracker) Upstream() any { } func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64) *tcpTracker { - uuid, _ := utils.UnsafeUUIDGenerator.NewV4() if conn != nil { if tcpAddr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { metadata.RemoteDst = tcpAddr.IP.String() @@ -96,7 +95,7 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R Conn: conn, manager: manager, trackerInfo: &trackerInfo{ - UUID: uuid, + UUID: utils.NewUUIDV4(), Start: time.Now(), Metadata: metadata, Chain: conn.Chains(), @@ -149,14 +148,13 @@ func (ut *udpTracker) Close() error { } func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64) *udpTracker { - uuid, _ := utils.UnsafeUUIDGenerator.NewV4() metadata.RemoteDst = conn.RemoteDestination() ut := &udpTracker{ PacketConn: conn, manager: manager, trackerInfo: &trackerInfo{ - UUID: uuid, + UUID: utils.NewUUIDV4(), Start: time.Now(), Metadata: metadata, Chain: conn.Chains(), From e8d4f8ae7b59473fe4db2c951baa2cd4627ec06b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Wed, 15 Mar 2023 14:08:52 +0800 Subject: [PATCH 114/530] Update UoT protocol --- adapter/outbound/shadowsocks.go | 34 ++++++++++++++++++++++++++++----- go.mod | 4 ++-- go.sum | 10 ++++++---- listener/sing/sing.go | 14 +++++++++++--- 4 files changed, 48 insertions(+), 14 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index af034472..c3097d09 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -50,6 +50,7 @@ type ShadowSocksOption struct { Plugin string `proxy:"plugin,omitempty"` PluginOpts map[string]any `proxy:"plugin-opts,omitempty"` UDPOverTCP bool `proxy:"udp-over-tcp,omitempty"` + UDPOverTCPVersion int `proxy:"udp-over-tcp-version,omitempty"` ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } @@ -123,10 +124,16 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada } useEarly = useEarly || N.NeedHandshake(c) if metadata.NetWork == C.UDP && ss.option.UDPOverTCP { - if useEarly { - return ss.method.DialEarlyConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")), nil + var uotDestination M.Socksaddr + if ss.option.UDPOverTCPVersion == 1 { + uotDestination.Fqdn = uot.LegacyMagicAddress } else { - return ss.method.DialConn(c, M.ParseSocksaddr(uot.UOTMagicAddress+":443")) + uotDestination.Fqdn = uot.MagicAddress + } + if useEarly { + return ss.method.DialEarlyConn(c, uotDestination), nil + } else { + return ss.method.DialConn(c, uotDestination) } } if useEarly { @@ -169,7 +176,12 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - return newPacketConn(uot.NewClientConn(tcpConn), ss), nil + destination := M.ParseSocksaddr(metadata.RemoteAddress()) + if ss.option.UDPOverTCPVersion == 1 { + return newPacketConn(uot.NewConn(tcpConn, false, destination), ss), nil + } else { + return newPacketConn(uot.NewLazyConn(tcpConn, uot.Request{Destination: destination}), ss), nil + } } addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer) if err != nil { @@ -192,7 +204,12 @@ func (ss *ShadowSocks) SupportWithDialer() bool { // ListenPacketOnStreamConn implements C.ProxyAdapter func (ss *ShadowSocks) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { if ss.option.UDPOverTCP { - return newPacketConn(uot.NewClientConn(c), ss), nil + destination := M.ParseSocksaddr(metadata.RemoteAddress()) + if ss.option.UDPOverTCPVersion == 1 { + return newPacketConn(uot.NewConn(c, false, destination), ss), nil + } else { + return newPacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination}), ss), nil + } } return nil, errors.New("no support") } @@ -279,6 +296,13 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } } + switch option.UDPOverTCPVersion { + case uot.Version, uot.LegacyVersion: + case 0: + option.UDPOverTCPVersion = uot.Version + default: + return nil, fmt.Errorf("ss %s unknown udp over tcp protocol version: %d", addr, option.UDPOverTCPVersion) + } return &ShadowSocks{ Base: &Base{ diff --git a/go.mod b/go.mod index 28760b44..c9080f7d 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.8 + github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d @@ -44,7 +44,7 @@ require ( golang.org/x/exp v0.0.0-20221205204356-47842c84f3db golang.org/x/net v0.7.0 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.5.0 + golang.org/x/sys v0.6.0 google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.1.7 diff --git a/go.sum b/go.sum index f9e584a2..5fc1b7e0 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,10 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.8 h1:6DKo2FkSHn0nUcjO7bAext/ai7y7pCusK/+fScBJ5Jk= -github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.1.9-0.20230315055814-2f422b53b06f h1:bCx4+svKuZyw8CxxFXmrmhAERFf5BAAiNb1aYXj4hwk= +github.com/sagernet/sing v0.1.9-0.20230315055814-2f422b53b06f/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= +github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b h1:1iKGftQ59+shDSx2RaLaxXJcMK/B+IU9WqUPwyBW+E0= +github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc h1:vqlYWupvVDRpvv2F+RtECJN+VbuKjLtmQculQvOecls= @@ -222,8 +224,8 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= -golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index a3e15154..fa9e02f1 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -5,6 +5,7 @@ import ( "errors" "golang.org/x/exp/slices" "net" + "net/netip" "sync" "time" @@ -61,9 +62,16 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta switch metadata.Destination.Fqdn { case vmess.MuxDestination.Fqdn: return vmess.HandleMuxConnection(ctx, conn, h) - case uot.UOTMagicAddress: - metadata.Destination = M.Socksaddr{} - return h.NewPacketConnection(ctx, uot.NewClientConn(conn), metadata) + case uot.MagicAddress: + request, err := uot.ReadRequest(conn) + if err != nil { + return E.Cause(err, "read UoT request") + } + metadata.Destination = request.Destination + return h.NewPacketConnection(ctx, uot.NewConn(conn, request.IsConnect, metadata.Destination), metadata) + case uot.LegacyMagicAddress: + metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()} + return h.NewPacketConnection(ctx, uot.NewConn(conn, false, metadata.Destination), metadata) } target := socks5.ParseAddr(metadata.Destination.String()) wg := &sync.WaitGroup{} From 7404bfdc445eeec6be8427f11d6239cb336e7909 Mon Sep 17 00:00:00 2001 From: H1JK Date: Wed, 15 Mar 2023 15:55:18 +0800 Subject: [PATCH 115/530] chore: Improve REALITY handshake --- component/tls/reality.go | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index a060de92..85309fb5 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -62,16 +62,12 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string } hello := uConn.HandshakeState.Hello - hello.SessionId = make([]byte, 32) + for i := range hello.SessionId { // https://github.com/golang/go/issues/5373 + hello.SessionId[i] = 0 + } copy(hello.Raw[39:], hello.SessionId) - var nowTime time.Time - if uConfig.Time != nil { - nowTime = uConfig.Time() - } else { - nowTime = time.Now() - } - binary.BigEndian.PutUint64(hello.SessionId, uint64(nowTime.Unix())) + binary.BigEndian.PutUint64(hello.SessionId, uint64(time.Now().Unix())) hello.SessionId[0] = 1 hello.SessionId[1] = 7 @@ -130,7 +126,7 @@ func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.C return } //_, _ = io.Copy(io.Discard, response.Body) - time.Sleep(time.Duration(5 + fastrand.Int63n(10))) + time.Sleep(time.Duration(5+fastrand.Int63n(10)) * time.Second) response.Body.Close() client.CloseIdleConnections() } From 520cc807d6283ac751af45b96e401c3a0ad975fd Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 15 Mar 2023 18:58:59 +0800 Subject: [PATCH 116/530] chore: Update dependencies --- go.mod | 22 +++++++++++----------- go.sum | 47 ++++++++++++++++++++--------------------------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index c9080f7d..2404ff99 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/Dreamacro/clash go 1.19 require ( + github.com/3andne/restls-client-go v0.1.4 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da github.com/cilium/ebpf v0.9.3 github.com/coreos/go-iptables v0.6.0 @@ -20,16 +21,16 @@ require ( github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.1 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 - github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 + github.com/metacubex/sing-tun v0.1.2 github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb - github.com/miekg/dns v1.1.50 + github.com/miekg/dns v1.1.52 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b github.com/sagernet/sing-shadowtls v0.1.0 - github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc - github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d + github.com/sagernet/sing-vmess v0.1.3 + 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-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 @@ -40,9 +41,9 @@ require ( go.etcd.io/bbolt v1.3.6 go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 - golang.org/x/crypto v0.6.0 + golang.org/x/crypto v0.7.0 golang.org/x/exp v0.0.0-20221205204356-47842c84f3db - golang.org/x/net v0.7.0 + golang.org/x/net v0.8.0 golang.org/x/sync v0.1.0 golang.org/x/sys v0.6.0 google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d @@ -51,7 +52,6 @@ require ( ) require ( - github.com/3andne/restls-client-go v0.1.4 github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect @@ -65,7 +65,7 @@ require ( github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/mdlayher/socket v0.4.0 // indirect - github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005 // indirect + github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect @@ -75,10 +75,10 @@ require ( github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect - golang.org/x/mod v0.7.0 // indirect - golang.org/x/text v0.7.0 // indirect + golang.org/x/mod v0.8.0 // indirect + golang.org/x/text v0.8.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect - golang.org/x/tools v0.5.0 // indirect + golang.org/x/tools v0.6.0 // indirect ) replace go.uber.org/atomic v1.10.0 => github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 diff --git a/go.sum b/go.sum index 5fc1b7e0..64264a0f 100644 --- a/go.sum +++ b/go.sum @@ -89,20 +89,20 @@ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= -github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005 h1:0TEvReK/D6YLszjGj/bdx4d7amQSjQ2X/98r4ZiUbxU= -github.com/metacubex/gvisor v0.0.0-20230304153416-e2bb9c726005/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= +github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be h1:zg8lXHo8t+dCSPHQ/wCJui1V+eO9TSh9NoIjKNvUykA= +github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= github.com/metacubex/quic-go v0.33.1 h1:ZIxZFGivpSLOEZuuNkLy+aPvo1RP4uRBjNg3SAkXwIg= github.com/metacubex/quic-go v0.33.1/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= -github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3 h1:oQLThm1a8E7hHmoM9XF2cO0FZPsHVynC4YXW4b3liUI= -github.com/metacubex/sing-tun v0.1.1-0.20230304153753-5058534177f3/go.mod h1:b/19bRRhwampNPV+1gVDyDsQHmuGDaplxPQkwJh1kj4= +github.com/metacubex/sing-tun v0.1.2 h1:rQzy+11rt2ZCpCNIsFab5lWoYDTqkdaurofHo8f97yU= +github.com/metacubex/sing-tun v0.1.2/go.mod h1:+2JxFqCjgSmeeTygZjZSsQbTQUUVXwC3mxnASTs/EhU= github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb h1:uhvzbtOvyg2c1k1H2EeVPuPvTEjDHCq4+U0AljG40P8= github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c= +github.com/miekg/dns v1.1.52/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= 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/onsi/ginkgo/v2 v2.2.0 h1:3ZNA3L1c5FYDFTTxbFeVGGD8jYvjYauHD30YgLxVsNI= @@ -127,16 +127,14 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.9-0.20230315055814-2f422b53b06f h1:bCx4+svKuZyw8CxxFXmrmhAERFf5BAAiNb1aYXj4hwk= -github.com/sagernet/sing v0.1.9-0.20230315055814-2f422b53b06f/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b h1:1iKGftQ59+shDSx2RaLaxXJcMK/B+IU9WqUPwyBW+E0= github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= -github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc h1:vqlYWupvVDRpvv2F+RtECJN+VbuKjLtmQculQvOecls= -github.com/sagernet/sing-vmess v0.1.3-0.20230307060529-d110e81a50bc/go.mod h1:V14iffGwhZPU2S7wgIiPlLWXygSjAXazYzD1w0ejBl4= -github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d h1:trP/l6ZPWvQ/5Gv99Z7/t/v8iYy06akDMejxW1sznUk= -github.com/sagernet/tfo-go v0.0.0-20230207095944-549363a7327d/go.mod h1:jk6Ii8Y3En+j2KQDLgdgQGwb3M6y7EL567jFnGYhN9g= +github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM= +github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE= +github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= +github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= @@ -173,15 +171,15 @@ go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= 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.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= -golang.org/x/mod v0.7.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +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/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -193,9 +191,8 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= -golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= 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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= @@ -217,9 +214,7 @@ golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -229,9 +224,8 @@ golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -239,9 +233,8 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3 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.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.5.0 h1:+bSpV5HIeWkuvgaMfI3UmKRThoTA5ODJTUd8T17NO+4= -golang.org/x/tools v0.5.0/go.mod h1:N+Kgy78s5I24c24dU8OfWNEotWjutIs8SnJvn5IDq+k= +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/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= From 998d407d445c842ed78521c16c047ded28e3fa44 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 15 Mar 2023 23:43:58 +0800 Subject: [PATCH 117/530] Feat: support set tun file-descriptor in config file Co-authored-by: DuFoxit --- config/config.go | 2 ++ hub/route/configs.go | 4 ++++ listener/config/tun.go | 1 + listener/inbound/tun.go | 2 ++ listener/listener.go | 3 ++- listener/sing_tun/server.go | 1 + 6 files changed, 12 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 457ce72f..c407aad5 100644 --- a/config/config.go +++ b/config/config.go @@ -218,6 +218,7 @@ type RawTun struct { ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` } type RawTuicServer struct { @@ -1239,6 +1240,7 @@ func parseTun(rawTun RawTun, general *General) error { ExcludePackage: rawTun.ExcludePackage, EndpointIndependentNat: rawTun.EndpointIndependentNat, UDPTimeout: rawTun.UDPTimeout, + FileDescriptor: rawTun.FileDescriptor, } return nil diff --git a/hub/route/configs.go b/hub/route/configs.go index 50e3cd13..afafe80e 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -80,6 +80,7 @@ type tunSchema struct { ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` } type tuicServerSchema struct { @@ -169,6 +170,9 @@ func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun { if p.UDPTimeout != nil { def.UDPTimeout = *p.UDPTimeout } + if p.FileDescriptor != nil { + def.FileDescriptor = *p.FileDescriptor + } } return def } diff --git a/listener/config/tun.go b/listener/config/tun.go index 2e1d1a71..50f5cf7d 100644 --- a/listener/config/tun.go +++ b/listener/config/tun.go @@ -95,4 +95,5 @@ type Tun struct { ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` } diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index ad215989..eb16d2dd 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -33,6 +33,7 @@ type TunOption struct { ExcludePackage []string `inbound:"exclude_package,omitempty"` EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"` UDPTimeout int64 `inbound:"udp_timeout,omitempty"` + FileDescriptor int `inbound:"file-descriptor,omitempty"` } func (o TunOption) Equal(config C.InboundConfig) bool { @@ -96,6 +97,7 @@ func NewTun(options *TunOption) (*Tun, error) { ExcludePackage: options.ExcludePackage, EndpointIndependentNat: options.EndpointIndependentNat, UDPTimeout: options.UDPTimeout, + FileDescriptor: options.FileDescriptor, }, }, nil } diff --git a/listener/listener.go b/listener/listener.go index d8eb5c0c..21dee51e 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -821,7 +821,8 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { LastTunConf.MTU != tunConf.MTU || LastTunConf.StrictRoute != tunConf.StrictRoute || LastTunConf.EndpointIndependentNat != tunConf.EndpointIndependentNat || - LastTunConf.UDPTimeout != tunConf.UDPTimeout { + LastTunConf.UDPTimeout != tunConf.UDPTimeout || + LastTunConf.FileDescriptor != tunConf.FileDescriptor { return true } diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 06215c73..d7f42c98 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -212,6 +212,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte IncludeAndroidUser: options.IncludeAndroidUser, IncludePackage: options.IncludePackage, ExcludePackage: options.ExcludePackage, + FileDescriptor: options.FileDescriptor, InterfaceMonitor: defaultInterfaceMonitor, TableIndex: 2022, } From 3ae428570208b789030fce58b5872fe9738aaf74 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 16 Mar 2023 21:09:44 +0800 Subject: [PATCH 118/530] fix: tuic udp native mode can't relay packetSize>1200 --- adapter/outbound/tuic.go | 31 +++++++++++++++++++++---------- go.mod | 2 +- go.sum | 4 ++-- listener/config/tuic.go | 1 + listener/tuic/server.go | 10 ++++++++++ transport/tuic/conn.go | 3 +-- transport/tuic/protocol.go | 2 ++ 7 files changed, 38 insertions(+), 15 deletions(-) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index b6335fa8..d2f2b5e9 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -42,16 +42,17 @@ type TuicOption struct { DisableSni bool `proxy:"disable-sni,omitempty"` MaxUdpRelayPacketSize int `proxy:"max-udp-relay-packet-size,omitempty"` - FastOpen bool `proxy:"fast-open,omitempty"` - MaxOpenStreams int `proxy:"max-open-streams,omitempty"` - SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` - Fingerprint string `proxy:"fingerprint,omitempty"` - CustomCA string `proxy:"ca,omitempty"` - CustomCAString string `proxy:"ca-str,omitempty"` - ReceiveWindowConn int `proxy:"recv-window-conn,omitempty"` - ReceiveWindow int `proxy:"recv-window,omitempty"` - DisableMTUDiscovery bool `proxy:"disable-mtu-discovery,omitempty"` - SNI string `proxy:"sni,omitempty"` + FastOpen bool `proxy:"fast-open,omitempty"` + MaxOpenStreams int `proxy:"max-open-streams,omitempty"` + SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` + Fingerprint string `proxy:"fingerprint,omitempty"` + CustomCA string `proxy:"ca,omitempty"` + CustomCAString string `proxy:"ca-str,omitempty"` + ReceiveWindowConn int `proxy:"recv-window-conn,omitempty"` + ReceiveWindow int `proxy:"recv-window,omitempty"` + DisableMTUDiscovery bool `proxy:"disable-mtu-discovery,omitempty"` + MaxDatagramFrameSize int `proxy:"max-datagram-frame-size,omitempty"` + SNI string `proxy:"sni,omitempty"` } // DialContext implements C.ProxyAdapter @@ -175,6 +176,15 @@ func NewTuic(option TuicOption) (*Tuic, error) { option.MaxOpenStreams = 100 } + if option.MaxDatagramFrameSize == 0 { + option.MaxDatagramFrameSize = option.MaxUdpRelayPacketSize + tuic.PacketOverHead + } + + if option.MaxDatagramFrameSize > 1400 { + option.MaxDatagramFrameSize = 1400 + } + option.MaxUdpRelayPacketSize = option.MaxDatagramFrameSize - tuic.PacketOverHead + // ensure server's incoming stream can handle correctly, increase to 1.1x quicMaxOpenStreams := int64(option.MaxOpenStreams) quicMaxOpenStreams = quicMaxOpenStreams + int64(math.Ceil(float64(quicMaxOpenStreams)/10.0)) @@ -187,6 +197,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { MaxIncomingUniStreams: quicMaxOpenStreams, KeepAlivePeriod: time.Duration(option.HeartbeatInterval) * time.Millisecond, DisablePathMTUDiscovery: option.DisableMTUDiscovery, + MaxDatagramFrameSize: int64(option.MaxDatagramFrameSize), EnableDatagrams: true, } if option.ReceiveWindowConn == 0 { diff --git a/go.mod b/go.mod index 2404ff99..0f44f260 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 - github.com/metacubex/quic-go v0.33.1 + github.com/metacubex/quic-go v0.33.2 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 github.com/metacubex/sing-tun v0.1.2 github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb diff --git a/go.sum b/go.sum index 64264a0f..881d2b70 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be h1:zg8lXHo8t+dCSPHQ/wCJui1V+eO9TSh9NoIjKNvUykA= github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= -github.com/metacubex/quic-go v0.33.1 h1:ZIxZFGivpSLOEZuuNkLy+aPvo1RP4uRBjNg3SAkXwIg= -github.com/metacubex/quic-go v0.33.1/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= +github.com/metacubex/quic-go v0.33.2 h1:DsDdTaLvGI0eVV0C/jzPrw5MBwK5VR20r5Mt9uU5Djw= +github.com/metacubex/quic-go v0.33.2/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= github.com/metacubex/sing-tun v0.1.2 h1:rQzy+11rt2ZCpCNIsFab5lWoYDTqkdaurofHo8f97yU= diff --git a/listener/config/tuic.go b/listener/config/tuic.go index c584bbf5..991a04c9 100644 --- a/listener/config/tuic.go +++ b/listener/config/tuic.go @@ -15,6 +15,7 @@ type TuicServer 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"` + MaxDatagramFrameSize int `yaml:"max-datagram-frame-size" json:"max-datagram-frame-size,omitempty"` } func (t TuicServer) String() string { diff --git a/listener/tuic/server.go b/listener/tuic/server.go index a7ad69f6..92cc0b37 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -61,6 +61,16 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet quicConfig.InitialConnectionReceiveWindow = tuic.DefaultConnectionReceiveWindow / 10 quicConfig.MaxConnectionReceiveWindow = tuic.DefaultConnectionReceiveWindow + if config.MaxUdpRelayPacketSize == 0 { + config.MaxUdpRelayPacketSize = 1500 + } + maxDatagramFrameSize := config.MaxUdpRelayPacketSize + tuic.PacketOverHead + if maxDatagramFrameSize > 1400 { + maxDatagramFrameSize = 1400 + } + config.MaxUdpRelayPacketSize = maxDatagramFrameSize - tuic.PacketOverHead + quicConfig.MaxDatagramFrameSize = int64(maxDatagramFrameSize) + tokens := make([][32]byte, len(config.Token)) for i, token := range config.Token { tokens[i] = tuic.GenTKN(token) diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index dfa43e1f..d5955e13 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -1,7 +1,6 @@ package tuic import ( - "fmt" "net" "net/netip" "sync" @@ -201,7 +200,7 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { if q.udpRelayMode != "quic" && len(p) > q.maxUdpRelayPacketSize { - return 0, fmt.Errorf("udp packet too large(%d > %d)", len(p), q.maxUdpRelayPacketSize) + return 0, quic.ErrMessageTooLarge(q.maxUdpRelayPacketSize) } if q.closed { return 0, net.ErrClosed diff --git a/transport/tuic/protocol.go b/transport/tuic/protocol.go index b14074a7..570b6e54 100644 --- a/transport/tuic/protocol.go +++ b/transport/tuic/protocol.go @@ -282,6 +282,8 @@ func (c Packet) BytesLen() int { return c.CommandHead.BytesLen() + 4 + 2 + c.ADDR.BytesLen() + len(c.DATA) } +var PacketOverHead = NewPacket(0, 0, NewAddressAddrPort(netip.AddrPortFrom(netip.IPv6Unspecified(), 0)), nil).BytesLen() + type Dissociate struct { CommandHead ASSOC_ID uint32 From 8cb67b6480649edfa45dcc9ac89ce0789651e8b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Fri, 17 Mar 2023 13:23:37 +0800 Subject: [PATCH 119/530] Update UoT protocol --- adapter/outbound/shadowsocks.go | 13 ++++--------- go.mod | 2 +- go.sum | 2 ++ listener/sing/sing.go | 4 ++-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index c3097d09..1c64b3ca 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -124,12 +124,7 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada } useEarly = useEarly || N.NeedHandshake(c) if metadata.NetWork == C.UDP && ss.option.UDPOverTCP { - var uotDestination M.Socksaddr - if ss.option.UDPOverTCPVersion == 1 { - uotDestination.Fqdn = uot.LegacyMagicAddress - } else { - uotDestination.Fqdn = uot.MagicAddress - } + uotDestination := uot.RequestDestination(uint8(ss.option.UDPOverTCPVersion)) if useEarly { return ss.method.DialEarlyConn(c, uotDestination), nil } else { @@ -178,7 +173,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial } destination := M.ParseSocksaddr(metadata.RemoteAddress()) if ss.option.UDPOverTCPVersion == 1 { - return newPacketConn(uot.NewConn(tcpConn, false, destination), ss), nil + return newPacketConn(uot.NewConn(tcpConn, uot.Request{Destination: destination}), ss), nil } else { return newPacketConn(uot.NewLazyConn(tcpConn, uot.Request{Destination: destination}), ss), nil } @@ -205,8 +200,8 @@ func (ss *ShadowSocks) SupportWithDialer() bool { func (ss *ShadowSocks) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { if ss.option.UDPOverTCP { destination := M.ParseSocksaddr(metadata.RemoteAddress()) - if ss.option.UDPOverTCPVersion == 1 { - return newPacketConn(uot.NewConn(c, false, destination), ss), nil + if ss.option.UDPOverTCPVersion == uot.LegacyVersion { + return newPacketConn(uot.NewConn(c, uot.Request{Destination: destination}), ss), nil } else { return newPacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination}), ss), nil } diff --git a/go.mod b/go.mod index 0f44f260..a9967400 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b + github.com/sagernet/sing v0.2.0 github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index 881d2b70..eeb4e912 100644 --- a/go.sum +++ b/go.sum @@ -129,6 +129,8 @@ github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b h1:1iKGftQ59+shDSx2RaLaxXJcMK/B+IU9WqUPwyBW+E0= github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= +github.com/sagernet/sing v0.2.0 h1:iyc4TaeXG5XYXixl48zSDDTw46C9NOEAVFq6ZE0dA2k= +github.com/sagernet/sing v0.2.0/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index fa9e02f1..9436fcfb 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -68,10 +68,10 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta return E.Cause(err, "read UoT request") } metadata.Destination = request.Destination - return h.NewPacketConnection(ctx, uot.NewConn(conn, request.IsConnect, metadata.Destination), metadata) + return h.NewPacketConnection(ctx, uot.NewConn(conn, *request), metadata) case uot.LegacyMagicAddress: metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()} - return h.NewPacketConnection(ctx, uot.NewConn(conn, false, metadata.Destination), metadata) + return h.NewPacketConnection(ctx, uot.NewConn(conn, uot.Request{}), metadata) } target := socks5.ParseAddr(metadata.Destination.String()) wg := &sync.WaitGroup{} From c7362fce9c6e147f2e011a40a044476e621fe4f1 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 17 Mar 2023 14:49:42 +0800 Subject: [PATCH 120/530] chore: do not modify ALPN in utls --- component/tls/reality.go | 1 - component/tls/utls.go | 1 - 2 files changed, 2 deletions(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index 85309fb5..3dadb7fd 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -44,7 +44,6 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string } uConfig := &utls.Config{ ServerName: tlsConfig.ServerName, - NextProtos: tlsConfig.NextProtos, InsecureSkipVerify: true, SessionTicketsDisabled: true, VerifyPeerCertificate: verifier.VerifyPeerCertificate, diff --git a/component/tls/utls.go b/component/tls/utls.go index 857d598d..7ea2ad06 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -94,7 +94,6 @@ func copyConfig(c *tls.Config) *utls.Config { return &utls.Config{ RootCAs: c.RootCAs, ServerName: c.ServerName, - NextProtos: c.NextProtos, InsecureSkipVerify: c.InsecureSkipVerify, VerifyPeerCertificate: c.VerifyPeerCertificate, } From 84967ace53acca0fa9fc59e28dbe67e566603ce9 Mon Sep 17 00:00:00 2001 From: Phie Ash <56054933+yaoshiu@users.noreply.github.com> Date: Sat, 18 Mar 2023 19:55:29 +0800 Subject: [PATCH 121/530] Update flake.nix (#452) --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index 88a6eacb..ffd18629 100644 --- a/flake.nix +++ b/flake.nix @@ -28,7 +28,7 @@ inherit version; src = ./.; - vendorSha256 = "sha256-8cbcE9gKJjU14DNTLPc6nneEPZg7Akt+FlSDlPRvG5k="; + vendorSha256 = "sha256-W5oiPtTRin0731QQWr98xZ2Vpk97HYcBtKoi1OKZz+w="; # Do not build testing suit excludedPackages = [ "./test" ]; From f6f02bb5ebb950b9b0a07fd367af14ac5e7b5c4a Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 18 Mar 2023 22:20:31 +0800 Subject: [PATCH 122/530] fix: ToLower first --- constant/path.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/constant/path.go b/constant/path.go index 29ac9872..707c53f6 100644 --- a/constant/path.go +++ b/constant/path.go @@ -66,7 +66,7 @@ func (p *path) MMDB() string { // 目录则直接跳过 continue } else { - if strings.EqualFold(fi.Name(), "Country.mmdb") { + if strings.EqualFold(strings.ToLower(fi.Name()), "country.mmdb") { GeoipName = fi.Name() return P.Join(p.homeDir, fi.Name()) } @@ -93,7 +93,7 @@ func (p *path) GeoIP() string { // 目录则直接跳过 continue } else { - if strings.EqualFold(fi.Name(), "GeoIP.dat") { + if strings.EqualFold(strings.ToLower(fi.Name()), "geoip.dat") { GeoipName = fi.Name() return P.Join(p.homeDir, fi.Name()) } @@ -112,7 +112,7 @@ func (p *path) GeoSite() string { // 目录则直接跳过 continue } else { - if strings.EqualFold(fi.Name(), "GeoSite.dat") { + if strings.EqualFold(strings.ToLower(fi.Name()), "geosite.dat") { GeositeName = fi.Name() return P.Join(p.homeDir, fi.Name()) } From 9316c1293e01ad82492e50a80f3f4c58b2da8cfd Mon Sep 17 00:00:00 2001 From: metacubex Date: Sat, 18 Mar 2023 22:33:39 +0800 Subject: [PATCH 123/530] fix: geosite of nameserver-policy cannot be loaded correctly --- dns/filters.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dns/filters.go b/dns/filters.go index b51e6402..11c85c2c 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -92,6 +92,10 @@ type geoSiteFilter struct { } func NewGeoSite(group string) (fallbackDomainFilter, error) { + if err := geodata.InitGeoSite(); err != nil { + log.Errorln("can't initial GeoSite: %s", err) + return nil, err + } matcher, _, err := geodata.LoadGeoSiteMatcher(group) if err != nil { return nil, err From 3e47bfacf067a5a1b9ef3b3f90e7f305a7b62b91 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 19 Mar 2023 17:31:52 +0800 Subject: [PATCH 124/530] feat: Converter support REALITY share standard --- common/convert/v.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/common/convert/v.go b/common/convert/v.go index 606d8aff..7e365170 100644 --- a/common/convert/v.go +++ b/common/convert/v.go @@ -38,6 +38,12 @@ func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy m if sni := query.Get("sni"); sni != "" { proxy["servername"] = sni } + if realityPublicKey := query.Get("pbk"); realityPublicKey != "" { + proxy["reality-opts"] = map[string]any{ + "public-key": realityPublicKey, + "short-id": query.Get("sid"), + } + } switch query.Get("packetEncoding") { case "none": From 154fbb34eace2f1568f034d004f27973f6fa5d0a Mon Sep 17 00:00:00 2001 From: metacubex Date: Tue, 21 Mar 2023 00:45:25 +0800 Subject: [PATCH 125/530] fix: log typo --- component/geodata/memconservative/cache.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/component/geodata/memconservative/cache.go b/component/geodata/memconservative/cache.go index 28c2c238..ca78d19d 100644 --- a/component/geodata/memconservative/cache.go +++ b/component/geodata/memconservative/cache.go @@ -118,7 +118,7 @@ func (g GeoSiteCache) Unmarshal(filename, code string) (*router.GeoSite, error) case errFailedToReadBytes, errFailedToReadExpectedLenBytes, errInvalidGeodataFile, errInvalidGeodataVarintLength: - log.Warnln("failed to decode geoip file: %s%s", filename, ", fallback to the original ReadFile method") + log.Warnln("failed to decode geosite file: %s%s", filename, ", fallback to the original ReadFile method") geositeBytes, err = os.ReadFile(asset) if err != nil { return nil, err From 0336435ebc4346597a2d571999f780dd98418145 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 21 Mar 2023 12:40:36 +0800 Subject: [PATCH 126/530] chore: shadowsocks listener support the "udp" setting --- listener/config/shadowsocks.go | 1 + listener/inbound/shadowsocks.go | 2 + listener/listener.go | 1 + listener/parse.go | 2 +- listener/shadowsocks/tcp.go | 12 +++--- listener/sing_shadowsocks/server.go | 62 +++++++++++++++-------------- 6 files changed, 44 insertions(+), 36 deletions(-) diff --git a/listener/config/shadowsocks.go b/listener/config/shadowsocks.go index cfe31f62..60540bbd 100644 --- a/listener/config/shadowsocks.go +++ b/listener/config/shadowsocks.go @@ -9,6 +9,7 @@ type ShadowsocksServer struct { Listen string Password string Cipher string + Udp bool } func (t ShadowsocksServer) String() string { diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go index 40907485..4659f4d7 100644 --- a/listener/inbound/shadowsocks.go +++ b/listener/inbound/shadowsocks.go @@ -11,6 +11,7 @@ type ShadowSocksOption struct { BaseOption Password string `inbound:"password"` Cipher string `inbound:"cipher"` + UDP bool `inbound:"udp,omitempty"` } func (o ShadowSocksOption) Equal(config C.InboundConfig) bool { @@ -37,6 +38,7 @@ func NewShadowSocks(options *ShadowSocksOption) (*ShadowSocks, error) { Listen: base.RawAddress(), Password: options.Password, Cipher: options.Cipher, + Udp: options.UDP, }, }, nil } diff --git a/listener/listener.go b/listener/listener.go index 21dee51e..8f0088db 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -271,6 +271,7 @@ func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, u Listen: addr, Password: password, Cipher: cipher, + Udp: true, } } diff --git a/listener/parse.go b/listener/parse.go index aa9e39ac..c8e1ddf7 100644 --- a/listener/parse.go +++ b/listener/parse.go @@ -73,7 +73,7 @@ func ParseListener(mapping map[string]any) (C.InboundListener, error) { } listener, err = IN.NewTun(tunOption) case "shadowsocks": - shadowsocksOption := &IN.ShadowSocksOption{} + shadowsocksOption := &IN.ShadowSocksOption{UDP: true} err = decoder.Decode(mapping, shadowsocksOption) if err != nil { return nil, err diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index 21db5b63..c0fd490f 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -33,12 +33,14 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C for _, addr := range strings.Split(config.Listen, ",") { addr := addr - //UDP - ul, err := NewUDP(addr, pickCipher, udpIn) - if err != nil { - return nil, err + if config.Udp { + //UDP + ul, err := NewUDP(addr, pickCipher, udpIn) + if err != nil { + return nil, err + } + sl.udpListeners = append(sl.udpListeners, ul) } - sl.udpListeners = append(sl.udpListeners, ul) //TCP l, err := inbound.Listen("tcp", addr) diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 5602a3ed..c7e05bb5 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -76,37 +76,39 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C for _, addr := range strings.Split(config.Listen, ",") { addr := addr - //UDP - ul, err := net.ListenPacket("udp", addr) - if err != nil { - return nil, err - } - - err = sockopt.UDPReuseaddr(ul.(*net.UDPConn)) - if err != nil { - log.Warnln("Failed to Reuse UDP Address: %s", err) - } - - sl.udpListeners = append(sl.udpListeners, ul) - - go func() { - conn := bufio.NewPacketConn(ul) - for { - buff := buf.NewPacket() - remoteAddr, err := conn.ReadPacket(buff) - if err != nil { - buff.Release() - if sl.closed { - break - } - continue - } - _ = sl.service.NewPacket(context.TODO(), conn, buff, metadata.Metadata{ - Protocol: "shadowsocks", - Source: remoteAddr, - }) + if config.Udp { + //UDP + ul, err := net.ListenPacket("udp", addr) + if err != nil { + return nil, err } - }() + + err = sockopt.UDPReuseaddr(ul.(*net.UDPConn)) + if err != nil { + log.Warnln("Failed to Reuse UDP Address: %s", err) + } + + sl.udpListeners = append(sl.udpListeners, ul) + + go func() { + conn := bufio.NewPacketConn(ul) + for { + buff := buf.NewPacket() + remoteAddr, err := conn.ReadPacket(buff) + if err != nil { + buff.Release() + if sl.closed { + break + } + continue + } + _ = sl.service.NewPacket(context.TODO(), conn, buff, metadata.Metadata{ + Protocol: "shadowsocks", + Source: remoteAddr, + }) + } + }() + } //TCP l, err := inbound.Listen("tcp", addr) From a22000c41b9c0f0acc2adb3bdfed752095be7ea1 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 21 Mar 2023 23:56:40 +0800 Subject: [PATCH 127/530] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index cdfa3505..2e485db2 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ ## Wiki -Documentation and configuring examples are available on [wiki](https://github.com/MetaCubeX/Clash.Meta/wiki) and [Clash.Meta Wiki](https://docs.metacubex.one/). +Documentation and configuring examples are available on [Clash.Meta Wiki](https://clash-meta.wiki). ## Build From e7bb1f42b1bff18493d0aa4509cb4f8b3e5c847d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 22 Mar 2023 13:01:45 +0800 Subject: [PATCH 128/530] chore: update quic-go to release unused buffer when error --- go.mod | 2 +- go.sum | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index a9967400..661adc9a 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 - github.com/metacubex/quic-go v0.33.2 + github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 github.com/metacubex/sing-tun v0.1.2 github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb diff --git a/go.sum b/go.sum index eeb4e912..6f3236f2 100644 --- a/go.sum +++ b/go.sum @@ -91,8 +91,8 @@ github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be h1:zg8lXHo8t+dCSPHQ/wCJui1V+eO9TSh9NoIjKNvUykA= github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= -github.com/metacubex/quic-go v0.33.2 h1:DsDdTaLvGI0eVV0C/jzPrw5MBwK5VR20r5Mt9uU5Djw= -github.com/metacubex/quic-go v0.33.2/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= +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.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= github.com/metacubex/sing-tun v0.1.2 h1:rQzy+11rt2ZCpCNIsFab5lWoYDTqkdaurofHo8f97yU= @@ -127,8 +127,6 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b h1:1iKGftQ59+shDSx2RaLaxXJcMK/B+IU9WqUPwyBW+E0= -github.com/sagernet/sing v0.1.9-0.20230315063014-2731df16725b/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing v0.2.0 h1:iyc4TaeXG5XYXixl48zSDDTw46C9NOEAVFq6ZE0dA2k= github.com/sagernet/sing v0.2.0/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= From e026ac6a2a43459e964588f14a5f7d564e568297 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 22 Mar 2023 23:45:26 +0800 Subject: [PATCH 129/530] chore: update xray-core version --- component/tls/reality.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index 3dadb7fd..dd4f3af8 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -69,8 +69,8 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string binary.BigEndian.PutUint64(hello.SessionId, uint64(time.Now().Unix())) hello.SessionId[0] = 1 - hello.SessionId[1] = 7 - hello.SessionId[2] = 5 + hello.SessionId[1] = 8 + hello.SessionId[2] = 0 copy(hello.SessionId[8:], realityConfig.ShortID[:]) //log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16]) From 5737fbc23cad0ac84f86d0e00002a6031c55ee6b Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 23 Mar 2023 12:58:59 +0800 Subject: [PATCH 130/530] chore: `proxy-server-nameserver` does not follow the `nameserver-policy` --- dns/resolver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dns/resolver.go b/dns/resolver.go index 57f581a5..c16aad40 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -516,7 +516,7 @@ func NewProxyServerHostResolver(old *Resolver) *Resolver { main: old.proxyServer, lruCache: old.lruCache, hosts: old.hosts, - policy: old.policy, + policy: trie.New[*Policy](), ipv6Timeout: old.ipv6Timeout, } return r From fd0580bfddeb840597379034ab8bae509e7562ae Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 23 Mar 2023 14:05:16 +0800 Subject: [PATCH 131/530] fix: sing_tun apply udpTimeout when using gvisor stack --- go.mod | 4 +-- go.sum | 8 +++--- listener/sing/sing.go | 49 ++++++++++++++++++++++++++----------- listener/sing_tun/server.go | 10 +++++--- 4 files changed, 47 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 661adc9a..2ae77925 100644 --- a/go.mod +++ b/go.mod @@ -27,7 +27,7 @@ require ( github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.0 + github.com/sagernet/sing v0.2.1-0.20230323055925-1c4c60c739ef github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 @@ -42,7 +42,7 @@ require ( go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.1 golang.org/x/crypto v0.7.0 - golang.org/x/exp v0.0.0-20221205204356-47842c84f3db + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 golang.org/x/net v0.8.0 golang.org/x/sync v0.1.0 golang.org/x/sys v0.6.0 diff --git a/go.sum b/go.sum index 6f3236f2..db54998b 100644 --- a/go.sum +++ b/go.sum @@ -127,8 +127,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.0 h1:iyc4TaeXG5XYXixl48zSDDTw46C9NOEAVFq6ZE0dA2k= -github.com/sagernet/sing v0.2.0/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= +github.com/sagernet/sing v0.2.1-0.20230323055925-1c4c60c739ef h1:gCIUmEaAbTZnQU6DPcnJkqnD9D0W2f3mp/mx0HKiWI8= +github.com/sagernet/sing v0.2.1-0.20230323055925-1c4c60c739ef/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM= @@ -173,8 +173,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/exp v0.0.0-20221205204356-47842c84f3db h1:D/cFflL63o2KSLJIwjlcIt8PR064j/xsmdEJL/YvY/o= -golang.org/x/exp v0.0.0-20221205204356-47842c84f3db/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc= +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/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= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 9436fcfb..d6ff81c3 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -3,6 +3,7 @@ package sing import ( "context" "errors" + "go.uber.org/atomic" "golang.org/x/exp/slices" "net" "net/netip" @@ -14,6 +15,7 @@ import ( "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" + tun "github.com/metacubex/sing-tun" vmess "github.com/sagernet/sing-vmess" "github.com/sagernet/sing/common/buf" E "github.com/sagernet/sing/common/exceptions" @@ -25,10 +27,11 @@ import ( const UDPTimeout = 5 * time.Minute type ListenerHandler struct { - TcpIn chan<- C.ConnContext - UdpIn chan<- C.PacketAdapter - Type C.Type - Additions []inbound.Addition + TcpIn chan<- C.ConnContext + UdpIn chan<- C.PacketAdapter + Type C.Type + Additions []inbound.Addition + UDPTimeout time.Duration } type waitCloseConn struct { @@ -96,11 +99,23 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() + lastWrite := atomic.NewTime(time.Now()) + needTimeout := tun.NeedTimeoutFromContext(ctx) // gvisor stack call NewPacketConnection() with ContextWithNeedTimeout() + udpTimeout := h.UDPTimeout + if udpTimeout == 0 { + udpTimeout = UDPTimeout + } for { buff := buf.NewPacket() // do not use stack buffer + if needTimeout { + _ = conn.SetReadDeadline(time.Now().Add(udpTimeout)) + } dest, err := conn.ReadPacket(buff) if err != nil { buff.Release() + if needTimeout && E.IsTimeout(err) && time.Now().Sub(lastWrite.Load()) < udpTimeout { + continue // someone write successful in time, so we continue read instead of return error + } if E.IsClosed(err) { break } @@ -108,11 +123,12 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } target := socks5.ParseAddr(dest.String()) packet := &packet{ - conn: &conn2, - mutex: &mutex, - rAddr: metadata.Source.UDPAddr(), - lAddr: conn.LocalAddr(), - buff: buff, + conn: &conn2, + mutex: &mutex, + rAddr: metadata.Source.UDPAddr(), + lAddr: conn.LocalAddr(), + buff: buff, + lastWrite: lastWrite, } select { case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, additions...): @@ -127,11 +143,12 @@ func (h *ListenerHandler) NewError(ctx context.Context, err error) { } type packet struct { - conn *network.PacketConn - mutex *sync.Mutex - rAddr net.Addr - lAddr net.Addr - buff *buf.Buffer + conn *network.PacketConn + mutex *sync.Mutex + rAddr net.Addr + lAddr net.Addr + buff *buf.Buffer + lastWrite *atomic.Time } func (c *packet) Data() []byte { @@ -159,6 +176,10 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { return } err = conn.WritePacket(buff, M.SocksaddrFromNet(addr)) + if err != nil { + return + } + c.lastWrite.Store(time.Now()) return } diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index d7f42c98..ada9d1c2 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -8,6 +8,7 @@ import ( "runtime" "strconv" "strings" + "time" "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/component/dialer" @@ -151,10 +152,11 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte handler := &ListenerHandler{ ListenerHandler: sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, - Type: C.TUN, - Additions: additions, + TcpIn: tcpIn, + UdpIn: udpIn, + Type: C.TUN, + Additions: additions, + UDPTimeout: time.Second * time.Duration(udpTimeout), }, DnsAdds: dnsAdds, } From 7e10d78d53e9a23f0bec4cd24afa84af767a5fab Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 23 Mar 2023 18:35:37 +0800 Subject: [PATCH 132/530] chore: share the same geodata in different rule --- component/geodata/utils.go | 42 +++++++++++++++++++++++++++----------- config/updateGeo.go | 2 ++ dns/filters.go | 25 +++-------------------- 3 files changed, 35 insertions(+), 34 deletions(-) diff --git a/component/geodata/utils.go b/component/geodata/utils.go index 9e7e50b1..f1ea7151 100644 --- a/component/geodata/utils.go +++ b/component/geodata/utils.go @@ -2,6 +2,9 @@ package geodata import ( "fmt" + "golang.org/x/sync/singleflight" + "strings" + "github.com/Dreamacro/clash/component/geodata/router" C "github.com/Dreamacro/clash/constant" ) @@ -34,6 +37,8 @@ func Verify(name string) error { } } +var loadGeoSiteMatcherSF = singleflight.Group{} + func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) { if len(countryCode) == 0 { return nil, 0, fmt.Errorf("country code could not be empty") @@ -44,16 +49,19 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) not = true countryCode = countryCode[1:] } + countryCode = strings.ToLower(countryCode) - geoLoader, err := GetGeoDataLoader(geoLoaderName) - if err != nil { - return nil, 0, err - } - - domains, err := geoLoader.LoadGeoSite(countryCode) + v, err, _ := loadGeoSiteMatcherSF.Do(countryCode, func() (interface{}, error) { + geoLoader, err := GetGeoDataLoader(geoLoaderName) + if err != nil { + return nil, err + } + return geoLoader.LoadGeoSite(countryCode) + }) if err != nil { return nil, 0, err } + domains := v.([]*router.Domain) /** linear: linear algorithm @@ -68,25 +76,31 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) return matcher, len(domains), nil } +var loadGeoIPMatcherSF = singleflight.Group{} + func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) { if len(country) == 0 { return nil, 0, fmt.Errorf("country code could not be empty") } - geoLoader, err := GetGeoDataLoader(geoLoaderName) - if err != nil { - return nil, 0, err - } not := false if country[0] == '!' { not = true country = country[1:] } + country = strings.ToLower(country) - records, err := geoLoader.LoadGeoIP(country) + v, err, _ := loadGeoIPMatcherSF.Do(country, func() (interface{}, error) { + geoLoader, err := GetGeoDataLoader(geoLoaderName) + if err != nil { + return nil, err + } + return geoLoader.LoadGeoIP(country) + }) if err != nil { return nil, 0, err } + records := v.([]*router.CIDR) geoIP := &router.GeoIP{ CountryCode: country, @@ -98,6 +112,10 @@ func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) { if err != nil { return nil, 0, err } - return matcher, len(records), nil } + +func ClearCache() { + loadGeoSiteMatcherSF = singleflight.Group{} + loadGeoIPMatcherSF = singleflight.Group{} +} diff --git a/config/updateGeo.go b/config/updateGeo.go index a5f7b17b..698bd52d 100644 --- a/config/updateGeo.go +++ b/config/updateGeo.go @@ -63,6 +63,8 @@ func UpdateGeoDatabases() error { return fmt.Errorf("can't save GeoSite database file: %w", err) } + geodata.ClearCache() + return nil } diff --git a/dns/filters.go b/dns/filters.go index 11c85c2c..58b261ac 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -29,29 +29,10 @@ func (gf *geoipFilter) Match(ip netip.Addr) bool { } if geoIPMatcher == nil { - countryCode := "cn" - geoLoader, err := geodata.GetGeoDataLoader(geodata.LoaderName()) + var err error + geoIPMatcher, _, err = geodata.LoadGeoIPMatcher("CN") if err != nil { - log.Errorln("[GeoIPFilter] GetGeoDataLoader error: %s", err.Error()) - return false - } - - records, err := geoLoader.LoadGeoIP(countryCode) - if err != nil { - log.Errorln("[GeoIPFilter] LoadGeoIP error: %s", err.Error()) - return false - } - - geoIP := &router.GeoIP{ - CountryCode: countryCode, - Cidr: records, - ReverseMatch: false, - } - - geoIPMatcher, err = router.NewGeoIPMatcher(geoIP) - - if err != nil { - log.Errorln("[GeoIPFilter] NewGeoIPMatcher error: %s", err.Error()) + log.Errorln("[GeoIPFilter] LoadGeoIPMatcher error: %s", err.Error()) return false } } From a7944f1369b8ca9a7f23d0fa605c72c16f38cc65 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 23 Mar 2023 18:58:24 +0800 Subject: [PATCH 133/530] chore: better geodata shared --- component/geodata/geodata.go | 47 ++----------------------------- component/geodata/geodataproto.go | 1 - component/geodata/utils.go | 45 +++++++++++++++++++++++++++-- 3 files changed, 44 insertions(+), 49 deletions(-) diff --git a/component/geodata/geodata.go b/component/geodata/geodata.go index ac0f820e..9d0b0df0 100644 --- a/component/geodata/geodata.go +++ b/component/geodata/geodata.go @@ -1,13 +1,10 @@ package geodata import ( - "errors" "fmt" - C "github.com/Dreamacro/clash/constant" - "strings" "github.com/Dreamacro/clash/component/geodata/router" - "github.com/Dreamacro/clash/log" + C "github.com/Dreamacro/clash/constant" ) type loader struct { @@ -15,47 +12,7 @@ type loader struct { } func (l *loader) LoadGeoSite(list string) ([]*router.Domain, error) { - return l.LoadGeoSiteWithAttr(C.GeositeName, list) -} - -func (l *loader) LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) { - parts := strings.Split(siteWithAttr, "@") - if len(parts) == 0 { - return nil, errors.New("empty rule") - } - list := strings.TrimSpace(parts[0]) - attrVal := parts[1:] - - if len(list) == 0 { - return nil, fmt.Errorf("empty listname in rule: %s", siteWithAttr) - } - - domains, err := l.LoadSiteByPath(file, list) - if err != nil { - return nil, err - } - - attrs := parseAttrs(attrVal) - if attrs.IsEmpty() { - if strings.Contains(siteWithAttr, "@") { - log.Warnln("empty attribute list: %s", siteWithAttr) - } - return domains, nil - } - - filteredDomains := make([]*router.Domain, 0, len(domains)) - hasAttrMatched := false - for _, domain := range domains { - if attrs.Match(domain) { - hasAttrMatched = true - filteredDomains = append(filteredDomains, domain) - } - } - if !hasAttrMatched { - log.Warnln("attribute match no rule: geosite: %s", siteWithAttr) - } - - return filteredDomains, nil + return l.LoadSiteByPath(C.GeositeName, list) } func (l *loader) LoadGeoIP(country string) ([]*router.CIDR, error) { diff --git a/component/geodata/geodataproto.go b/component/geodata/geodataproto.go index ffefc484..34bdad70 100644 --- a/component/geodata/geodataproto.go +++ b/component/geodata/geodataproto.go @@ -14,6 +14,5 @@ type LoaderImplementation interface { type Loader interface { LoaderImplementation LoadGeoSite(list string) ([]*router.Domain, error) - LoadGeoSiteWithAttr(file string, siteWithAttr string) ([]*router.Domain, error) LoadGeoIP(country string) ([]*router.CIDR, error) } diff --git a/component/geodata/utils.go b/component/geodata/utils.go index f1ea7151..04ccfa51 100644 --- a/component/geodata/utils.go +++ b/component/geodata/utils.go @@ -1,12 +1,14 @@ package geodata import ( + "errors" "fmt" "golang.org/x/sync/singleflight" "strings" "github.com/Dreamacro/clash/component/geodata/router" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" ) var geoLoaderName = "memconservative" @@ -51,18 +53,52 @@ func LoadGeoSiteMatcher(countryCode string) (*router.DomainMatcher, int, error) } countryCode = strings.ToLower(countryCode) - v, err, _ := loadGeoSiteMatcherSF.Do(countryCode, func() (interface{}, error) { + parts := strings.Split(countryCode, "@") + if len(parts) == 0 { + return nil, 0, errors.New("empty rule") + } + listName := strings.TrimSpace(parts[0]) + attrVal := parts[1:] + + if len(listName) == 0 { + return nil, 0, fmt.Errorf("empty listname in rule: %s", countryCode) + } + + v, err, shared := loadGeoSiteMatcherSF.Do(listName, func() (interface{}, error) { geoLoader, err := GetGeoDataLoader(geoLoaderName) if err != nil { return nil, err } - return geoLoader.LoadGeoSite(countryCode) + return geoLoader.LoadGeoSite(listName) }) if err != nil { + if !shared { + loadGeoSiteMatcherSF.Forget(listName) // don't store the error result + } return nil, 0, err } domains := v.([]*router.Domain) + attrs := parseAttrs(attrVal) + if attrs.IsEmpty() { + if strings.Contains(countryCode, "@") { + log.Warnln("empty attribute list: %s", countryCode) + } + } else { + filteredDomains := make([]*router.Domain, 0, len(domains)) + hasAttrMatched := false + for _, domain := range domains { + if attrs.Match(domain) { + hasAttrMatched = true + filteredDomains = append(filteredDomains, domain) + } + } + if !hasAttrMatched { + log.Warnln("attribute match no rule: geosite: %s", countryCode) + } + domains = filteredDomains + } + /** linear: linear algorithm matcher, err := router.NewDomainMatcher(domains) @@ -90,7 +126,7 @@ func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) { } country = strings.ToLower(country) - v, err, _ := loadGeoIPMatcherSF.Do(country, func() (interface{}, error) { + v, err, shared := loadGeoIPMatcherSF.Do(country, func() (interface{}, error) { geoLoader, err := GetGeoDataLoader(geoLoaderName) if err != nil { return nil, err @@ -98,6 +134,9 @@ func LoadGeoIPMatcher(country string) (*router.GeoIPMatcher, int, error) { return geoLoader.LoadGeoIP(country) }) if err != nil { + if !shared { + loadGeoIPMatcherSF.Forget(country) // don't store the error result + } return nil, 0, err } records := v.([]*router.CIDR) From 291b5be986bbd73d9c7c3fc1b7910bba571cf69e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 23 Mar 2023 19:53:28 +0800 Subject: [PATCH 134/530] chore: move sing-tun's udpTimeout fix to there lib --- go.mod | 6 +++--- go.sum | 12 ++++++------ listener/sing/sing.go | 37 ++++++++++--------------------------- 3 files changed, 19 insertions(+), 36 deletions(-) diff --git a/go.mod b/go.mod index 2ae77925..1101def1 100644 --- a/go.mod +++ b/go.mod @@ -21,13 +21,13 @@ require ( github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 - github.com/metacubex/sing-tun v0.1.2 + github.com/metacubex/sing-tun v0.1.3-0.20230323115055-7935ba0ac8b3 github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb github.com/miekg/dns v1.1.52 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.1-0.20230323055925-1c4c60c739ef + github.com/sagernet/sing v0.2.1-0.20230323071235-f8038854d286 github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 @@ -65,7 +65,7 @@ require ( github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/mdlayher/socket v0.4.0 // indirect - github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be // indirect + github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index db54998b..22cc7c26 100644 --- a/go.sum +++ b/go.sum @@ -89,14 +89,14 @@ github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZ github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= -github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be h1:zg8lXHo8t+dCSPHQ/wCJui1V+eO9TSh9NoIjKNvUykA= -github.com/metacubex/gvisor v0.0.0-20230315105319-c03631d706be/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= +github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 h1:gREIdurac9fpyBMBRPPMF/Sk3gKfPfdNCa4GQyR9FoA= +github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03/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.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE= github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= -github.com/metacubex/sing-tun v0.1.2 h1:rQzy+11rt2ZCpCNIsFab5lWoYDTqkdaurofHo8f97yU= -github.com/metacubex/sing-tun v0.1.2/go.mod h1:+2JxFqCjgSmeeTygZjZSsQbTQUUVXwC3mxnASTs/EhU= +github.com/metacubex/sing-tun v0.1.3-0.20230323115055-7935ba0ac8b3 h1:LnKcLs0HI0HX4xH/2XerX+1BLXS1Uj6Xvzn20xFuCOk= +github.com/metacubex/sing-tun v0.1.3-0.20230323115055-7935ba0ac8b3/go.mod h1:0i22nk0tgkQz/N96hrhPib1O/C5AjxSnco7Mwi2YSF0= github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb h1:uhvzbtOvyg2c1k1H2EeVPuPvTEjDHCq4+U0AljG40P8= github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= @@ -127,8 +127,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.1-0.20230323055925-1c4c60c739ef h1:gCIUmEaAbTZnQU6DPcnJkqnD9D0W2f3mp/mx0HKiWI8= -github.com/sagernet/sing v0.2.1-0.20230323055925-1c4c60c739ef/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= +github.com/sagernet/sing v0.2.1-0.20230323071235-f8038854d286 h1:0Td2b5l1KgrdlOnbRWgFFWsyb0TLoq/tP6j9Lut4JN0= +github.com/sagernet/sing v0.2.1-0.20230323071235-f8038854d286/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index d6ff81c3..70462728 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -3,7 +3,6 @@ package sing import ( "context" "errors" - "go.uber.org/atomic" "golang.org/x/exp/slices" "net" "net/netip" @@ -15,7 +14,6 @@ import ( "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" - tun "github.com/metacubex/sing-tun" vmess "github.com/sagernet/sing-vmess" "github.com/sagernet/sing/common/buf" E "github.com/sagernet/sing/common/exceptions" @@ -99,23 +97,11 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() - lastWrite := atomic.NewTime(time.Now()) - needTimeout := tun.NeedTimeoutFromContext(ctx) // gvisor stack call NewPacketConnection() with ContextWithNeedTimeout() - udpTimeout := h.UDPTimeout - if udpTimeout == 0 { - udpTimeout = UDPTimeout - } for { buff := buf.NewPacket() // do not use stack buffer - if needTimeout { - _ = conn.SetReadDeadline(time.Now().Add(udpTimeout)) - } dest, err := conn.ReadPacket(buff) if err != nil { buff.Release() - if needTimeout && E.IsTimeout(err) && time.Now().Sub(lastWrite.Load()) < udpTimeout { - continue // someone write successful in time, so we continue read instead of return error - } if E.IsClosed(err) { break } @@ -123,12 +109,11 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } target := socks5.ParseAddr(dest.String()) packet := &packet{ - conn: &conn2, - mutex: &mutex, - rAddr: metadata.Source.UDPAddr(), - lAddr: conn.LocalAddr(), - buff: buff, - lastWrite: lastWrite, + conn: &conn2, + mutex: &mutex, + rAddr: metadata.Source.UDPAddr(), + lAddr: conn.LocalAddr(), + buff: buff, } select { case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, additions...): @@ -143,12 +128,11 @@ func (h *ListenerHandler) NewError(ctx context.Context, err error) { } type packet struct { - conn *network.PacketConn - mutex *sync.Mutex - rAddr net.Addr - lAddr net.Addr - buff *buf.Buffer - lastWrite *atomic.Time + conn *network.PacketConn + mutex *sync.Mutex + rAddr net.Addr + lAddr net.Addr + buff *buf.Buffer } func (c *packet) Data() []byte { @@ -179,7 +163,6 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { if err != nil { return } - c.lastWrite.Store(time.Now()) return } From 99ede63a9abb85c97d1b39962d12d74349e9320d Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 23 Mar 2023 20:42:01 +0800 Subject: [PATCH 135/530] feat: add upgrade api example: curl -X POST -H "Authorization: Bearer 123456" http://ip:port/upgrade --- go.mod | 2 +- go.sum | 4 +- hub/route/server.go | 2 + hub/route/upgrade.go | 69 ++++++ hub/updater/limitedreader.go | 67 +++++ hub/updater/updater.go | 460 +++++++++++++++++++++++++++++++++++ 6 files changed, 601 insertions(+), 3 deletions(-) create mode 100644 hub/route/upgrade.go create mode 100644 hub/updater/limitedreader.go create mode 100644 hub/updater/updater.go diff --git a/go.mod b/go.mod index 1101def1..c8eb6e10 100644 --- a/go.mod +++ b/go.mod @@ -35,7 +35,7 @@ require ( github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 github.com/sirupsen/logrus v1.9.0 - github.com/stretchr/testify v1.8.1 + github.com/stretchr/testify v1.8.2 github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.6 diff --git a/go.sum b/go.sum index 22cc7c26..f56aed7a 100644 --- a/go.sum +++ b/go.sum @@ -153,8 +153,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.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/u-root/uio v0.0.0-20221213070652-c3537552635f h1:dpx1PHxYqAnXzbryJrWP1NQLzEjwcVgFLhkknuFQ7ww= github.com/u-root/uio v0.0.0-20221213070652-c3537552635f/go.mod h1:IogEAUBXDEwX7oR/BMmCctShYs80ql4hF0ySdzGxf7E= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= diff --git a/hub/route/server.go b/hub/route/server.go index 054b1ad1..848face9 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -87,6 +87,8 @@ func Start(addr string, tlsAddr string, secret string, r.Mount("/cache", cacheRouter()) r.Mount("/dns", dnsRouter()) r.Mount("/restart", restartRouter()) + r.Mount("/upgrade", upgradeRouter()) + }) if uiPath != "" { diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go new file mode 100644 index 00000000..0d772c85 --- /dev/null +++ b/hub/route/upgrade.go @@ -0,0 +1,69 @@ +package route + +import ( + "fmt" + "net/http" + "os" + "os/exec" + "runtime" + "syscall" + + "github.com/Dreamacro/clash/hub/updater" + "github.com/Dreamacro/clash/log" + "github.com/go-chi/render" + + "github.com/go-chi/chi/v5" +) + +func upgradeRouter() http.Handler { + r := chi.NewRouter() + r.Post("/", upgrade) + return r +} + +func upgrade(w http.ResponseWriter, r *http.Request) { + // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L108 + log.Infoln("start update") + err := updater.Update() + if err != nil { + log.Errorln("err:%s", err) + } + + execPath, err := os.Executable() + if err != nil { + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, newError(fmt.Sprintf("getting path: %s", err))) + return + } + + render.JSON(w, r, render.M{"status": "ok"}) + if f, ok := w.(http.Flusher); ok { + f.Flush() + } + + // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L180 + // The background context is used because the underlying functions wrap it + // with timeout and shut down the server, which handles current request. It + // also should be done in a separate goroutine for the same reason. + go func() { + if runtime.GOOS == "windows" { + cmd := exec.Command(execPath, os.Args[1:]...) + log.Infoln("restarting: %q %q", execPath, os.Args[1:]) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Start() + if err != nil { + log.Fatalln("restarting: %s", err) + } + + os.Exit(0) + } + + log.Infoln("restarting: %q %q", execPath, os.Args[1:]) + err = syscall.Exec(execPath, os.Args, os.Environ()) + if err != nil { + log.Fatalln("restarting: %s", err) + } + }() +} diff --git a/hub/updater/limitedreader.go b/hub/updater/limitedreader.go new file mode 100644 index 00000000..c31db601 --- /dev/null +++ b/hub/updater/limitedreader.go @@ -0,0 +1,67 @@ +package updater + +import ( + "fmt" + "io" + + "golang.org/x/exp/constraints" +) + +// LimitReachedError records the limit and the operation that caused it. +type LimitReachedError struct { + Limit int64 +} + +// Error implements the [error] interface for *LimitReachedError. +// +// TODO(a.garipov): Think about error string format. +func (lre *LimitReachedError) Error() string { + return fmt.Sprintf("attempted to read more than %d bytes", lre.Limit) +} + +// limitedReader is a wrapper for [io.Reader] limiting the input and dealing +// with errors package. +type limitedReader struct { + r io.Reader + limit int64 + n int64 +} + +// Read implements the [io.Reader] interface. +func (lr *limitedReader) Read(p []byte) (n int, err error) { + if lr.n == 0 { + return 0, &LimitReachedError{ + Limit: lr.limit, + } + } + + p = p[:Min(lr.n, int64(len(p)))] + + n, err = lr.r.Read(p) + lr.n -= int64(n) + + return n, err +} + +// LimitReader wraps Reader to make it's Reader stop with ErrLimitReached after +// n bytes read. +func LimitReader(r io.Reader, n int64) (limited io.Reader, err error) { + if n < 0 { + return nil, &updateError{Message: "limit must be non-negative"} + } + + return &limitedReader{ + r: r, + limit: n, + n: n, + }, nil +} + +// Min returns the smaller of x or y. +func Min[T constraints.Integer | ~string](x, y T) (res T) { + if x < y { + return x + } + + return y +} diff --git a/hub/updater/updater.go b/hub/updater/updater.go new file mode 100644 index 00000000..e4b55421 --- /dev/null +++ b/hub/updater/updater.go @@ -0,0 +1,460 @@ +package updater + +import ( + "archive/zip" + "compress/gzip" + "fmt" + "io" + "net/http" + "os" + "path/filepath" + "runtime" + "strings" + "sync" + + "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" +) + +// Updater is the AdGuard Home updater. +var ( + client http.Client + + goarch string + goos string + goarm string + gomips string + + workDir string + versionCheckURL string + + // mu protects all fields below. + mu sync.RWMutex + + // TODO(a.garipov): See if all of these fields actually have to be in + // this struct. + currentExeName string // 当前可执行文件 + updateDir string // 更新目录 + packageName string // 更新压缩文件 + backupDir string // 备份目录 + backupExeName string // 备份文件名 + updateExeName string // 更新后的可执行文件 + unpackedFile string + + baseURL = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/clash.meta" + versionURL = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/version.txt" + packageURL string + latestVersion string +) + +type updateError struct { + Message string +} + +func (e *updateError) Error() string { + return fmt.Sprintf("error: %s", e.Message) +} + +// Update performs the auto-updater. It returns an error if the updater failed. +// If firstRun is true, it assumes the configuration file doesn't exist. +func Update() (err error) { + goos = runtime.GOOS + goarch = runtime.GOARCH + latestVersion = getLatestVersion() + + if latestVersion == constant.Version { + err := &updateError{Message: "Already using latest version"} + return err + } + + updateDownloadURL() + mu.Lock() + defer mu.Unlock() + + log.Infoln("current version alpha-%s", constant.Version) + + defer func() { + if err != nil { + log.Errorln("updater: failed: %v", err) + } else { + log.Infoln("updater: finished") + } + }() + + execPath, err := os.Executable() + if err != nil { + return fmt.Errorf("getting executable path: %w", err) + } + + workDir = filepath.Dir(execPath) + //log.Infoln("workDir %s", execPath) + + err = prepare(execPath) + if err != nil { + return fmt.Errorf("preparing: %w", err) + } + + defer clean() + + err = downloadPackageFile() + if err != nil { + return fmt.Errorf("downloading package file: %w", err) + } + + err = unpack() + if err != nil { + return fmt.Errorf("unpacking: %w", err) + } + + err = replace() + if err != nil { + return fmt.Errorf("replacing: %w", err) + } + + return nil +} + +// VersionCheckURL returns the version check URL. +func VersionCheckURL() (vcu string) { + mu.RLock() + defer mu.RUnlock() + + return versionCheckURL +} + +// prepare fills all necessary fields in Updater object. +func prepare(exePath string) (err error) { + updateDir = filepath.Join(workDir, "meta-update") + currentExeName = exePath + _, pkgNameOnly := filepath.Split(packageURL) + if pkgNameOnly == "" { + return fmt.Errorf("invalid PackageURL: %q", packageURL) + } + + packageName = filepath.Join(updateDir, pkgNameOnly) + //log.Infoln(packageName) + backupDir = filepath.Join(workDir, "meta-backup") + + if goos == "windows" { + updateExeName = "clash.meta" + "-" + goos + "-" + goarch + ".exe" + } else { + updateExeName = "clash.meta" + "-" + goos + "-" + goarch + } + + log.Infoln("updateExeName: %s ,currentExeName: %s", updateExeName, currentExeName) + + backupExeName = filepath.Join(backupDir, filepath.Base(exePath)) + updateExeName = filepath.Join(updateDir, updateExeName) + + log.Infoln( + "updater: updating using url: %s", + packageURL, + ) + + currentExeName = exePath + _, err = os.Stat(currentExeName) + if err != nil { + return fmt.Errorf("checking %q: %w", currentExeName, err) + } + + return nil +} + +// unpack extracts the files from the downloaded archive. +func unpack() error { + var err error + _, pkgNameOnly := filepath.Split(packageURL) + + log.Debugln("updater: unpacking package") + if strings.HasSuffix(pkgNameOnly, ".zip") { + unpackedFile, err = zipFileUnpack(packageName, updateDir) + if err != nil { + return fmt.Errorf(".zip unpack failed: %w", err) + } + + } else if strings.HasSuffix(pkgNameOnly, ".gz") { + unpackedFile, err = gzFileUnpack(packageName, updateDir) + if err != nil { + return fmt.Errorf(".gz unpack failed: %w", err) + } + + } else { + return fmt.Errorf("unknown package extension") + } + + return nil +} + +// replace moves the current executable with the updated one and also copies the +// supporting files. +func replace() error { + //err := copySupportingFiles(unpackedFiles, updateDir, workDir) + //if err != nil { + // return fmt.Errorf("copySupportingFiles(%s, %s) failed: %w", updateDir, workDir, err) + //} + + log.Infoln("updater: renaming: %s to %s", currentExeName, backupExeName) + err := os.Rename(currentExeName, backupExeName) + if err != nil { + return err + } + + if goos == "windows" { + // rename fails with "File in use" error + log.Infoln("copying:%s to %s", updateExeName, currentExeName) + err = copyFile(updateExeName, currentExeName) + } else { + err = os.Rename(updateExeName, currentExeName) + } + if err != nil { + return err + } + + return nil +} + +// clean removes the temporary directory itself and all it's contents. +func clean() { + _ = os.RemoveAll(updateDir) +} + +// MaxPackageFileSize is a maximum package file length in bytes. The largest +// package whose size is limited by this constant currently has the size of +// approximately 9 MiB. +const MaxPackageFileSize = 32 * 1024 * 1024 + +// Download package file and save it to disk +func downloadPackageFile() (err error) { + var resp *http.Response + resp, err = client.Get(packageURL) + if err != nil { + return fmt.Errorf("http request failed: %w", err) + } + + defer func() { + closeErr := resp.Body.Close() + if closeErr != nil && err == nil { + err = closeErr + } + }() + + var r io.Reader + r, err = LimitReader(resp.Body, MaxPackageFileSize) + if err != nil { + return fmt.Errorf("http request failed: %w", err) + } + + log.Debugln("updater: reading http body") + // This use of ReadAll is now safe, because we limited body's Reader. + body, err := io.ReadAll(r) + if err != nil { + return fmt.Errorf("io.ReadAll() failed: %w", err) + } + + log.Debugln("updateDir %s", updateDir) + err = os.Mkdir(updateDir, 0o755) + if err != nil { + fmt.Errorf("mkdir error: %w", err) + } + + log.Debugln("updater: saving package to file %s", packageName) + err = os.WriteFile(packageName, body, 0o755) + if err != nil { + return fmt.Errorf("os.WriteFile() failed: %w", err) + } + return nil +} + +// Unpack a single .gz file to the specified directory +// Existing files are overwritten +// All files are created inside outDir, subdirectories are not created +// Return the output file name +func gzFileUnpack(gzfile, outDir string) (string, error) { + f, err := os.Open(gzfile) + if err != nil { + return "", fmt.Errorf("os.Open(): %w", err) + } + + defer func() { + closeErr := f.Close() + if closeErr != nil && err == nil { + err = closeErr + } + }() + + gzReader, err := gzip.NewReader(f) + if err != nil { + return "", fmt.Errorf("gzip.NewReader(): %w", err) + } + + defer func() { + closeErr := gzReader.Close() + if closeErr != nil && err == nil { + err = closeErr + } + }() + // Get the original file name from the .gz file header + originalName := gzReader.Header.Name + if originalName == "" { + // Fallback: remove the .gz extension from the input file name if the header doesn't provide the original name + originalName = filepath.Base(gzfile) + originalName = strings.TrimSuffix(originalName, ".gz") + } + + outputName := filepath.Join(outDir, originalName) + + // Create the output file + wc, err := os.OpenFile( + outputName, + os.O_WRONLY|os.O_CREATE|os.O_TRUNC, + 0o755, + ) + if err != nil { + return "", fmt.Errorf("os.OpenFile(%s): %w", outputName, err) + } + + defer func() { + closeErr := wc.Close() + if closeErr != nil && err == nil { + err = closeErr + } + }() + + // Copy the contents of the gzReader to the output file + _, err = io.Copy(wc, gzReader) + if err != nil { + return "", fmt.Errorf("io.Copy(): %w", err) + } + + return outputName, nil +} + +// Unpack a single file from .zip file to the specified directory +// Existing files are overwritten +// All files are created inside 'outDir', subdirectories are not created +// Return the output file name +func zipFileUnpack(zipfile, outDir string) (string, error) { + zrc, err := zip.OpenReader(zipfile) + if err != nil { + return "", fmt.Errorf("zip.OpenReader(): %w", err) + } + + defer func() { + closeErr := zrc.Close() + if closeErr != nil && err == nil { + err = closeErr + } + }() + if len(zrc.File) == 0 { + return "", fmt.Errorf("no files in the zip archive") + } + + // Assuming the first file in the zip archive is the target file + zf := zrc.File[0] + var rc io.ReadCloser + rc, err = zf.Open() + if err != nil { + return "", fmt.Errorf("zip file Open(): %w", err) + } + + defer func() { + closeErr := rc.Close() + if closeErr != nil && err == nil { + err = closeErr + } + }() + fi := zf.FileInfo() + name := fi.Name() + outputName := filepath.Join(outDir, name) + + if fi.IsDir() { + return "", fmt.Errorf("the target file is a directory") + } + + var wc io.WriteCloser + wc, err = os.OpenFile(outputName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fi.Mode()) + if err != nil { + return "", fmt.Errorf("os.OpenFile(): %w", err) + } + + defer func() { + closeErr := wc.Close() + if closeErr != nil && err == nil { + err = closeErr + } + }() + _, err = io.Copy(wc, rc) + if err != nil { + return "", fmt.Errorf("io.Copy(): %w", err) + } + + return outputName, nil +} + +// Copy file on disk +func copyFile(src, dst string) error { + d, e := os.ReadFile(src) + if e != nil { + return e + } + e = os.WriteFile(dst, d, 0o644) + if e != nil { + return e + } + return nil +} + +func getLatestVersion() string { + resp, err := http.Get(versionURL) + if err != nil { + return "" + } + defer func() { + closeErr := resp.Body.Close() + if closeErr != nil && err == nil { + err = closeErr + } + }() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "" + } + content := strings.TrimRight(string(body), "\n") + log.Infoln("latest:%s", content) + return content +} + +func updateDownloadURL() { + var middle string + + if goarch == "arm" && goarm != "" { + middle = fmt.Sprintf("-%s-%sv%s-%s", goos, goarch, goarm, latestVersion) + } else if isMIPS(goarch) && gomips != "" { + middle = fmt.Sprintf("-%s-%s-%s-%s", goos, goarch, gomips, latestVersion) + } else { + middle = fmt.Sprintf("-%s-%s-%s", goos, goarch, latestVersion) + } + + if goos == "windows" { + middle += ".zip" + } else { + middle += ".gz" + } + packageURL = baseURL + middle + //log.Infoln(packageURL) +} + +// isMIPS returns true if arch is any MIPS architecture. +func isMIPS(arch string) (ok bool) { + switch arch { + case + "mips", + "mips64", + "mips64le", + "mipsle": + return true + default: + return false + } +} From e4364cc985edd4c7da10280cd75f0220062213c9 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 23 Mar 2023 21:04:04 +0800 Subject: [PATCH 136/530] chore: update for testing the updater --- hub/updater/updater.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hub/updater/updater.go b/hub/updater/updater.go index e4b55421..8b9b7409 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -16,7 +16,8 @@ import ( "github.com/Dreamacro/clash/log" ) -// Updater is the AdGuard Home updater. +// modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/updater/updater.go +// Updater is the Clash.Meta updater. var ( client http.Client From 4d307887384cbf88c1c12ee88bc33dfe2629dc11 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 25 Mar 2023 22:56:24 +0800 Subject: [PATCH 137/530] chore: clean up code --- component/http/http.go | 5 +++-- hub/route/upgrade.go | 2 +- hub/updater/updater.go | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/component/http/http.go b/component/http/http.go index 54a3daa9..eb8478cd 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -2,14 +2,15 @@ package http import ( "context" - "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/listener/inner" "io" "net" "net/http" URL "net/url" "strings" "time" + + "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/listener/inner" ) const ( diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index 0d772c85..a4a8e683 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -10,9 +10,9 @@ import ( "github.com/Dreamacro/clash/hub/updater" "github.com/Dreamacro/clash/log" - "github.com/go-chi/render" "github.com/go-chi/chi/v5" + "github.com/go-chi/render" ) func upgradeRouter() http.Handler { diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 8b9b7409..272b5017 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -42,8 +42,8 @@ var ( updateExeName string // 更新后的可执行文件 unpackedFile string - baseURL = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/clash.meta" - versionURL = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/version.txt" + baseURL string = "https://ghproxy.com/https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/clash.meta" + versionURL string = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/version.txt" packageURL string latestVersion string ) From 431dcfa914071eb103ffe526db162ad367e0ae4d Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 26 Mar 2023 11:03:32 +0800 Subject: [PATCH 138/530] fix: Converter REALITY security type --- common/convert/v.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/convert/v.go b/common/convert/v.go index 7e365170..23949aab 100644 --- a/common/convert/v.go +++ b/common/convert/v.go @@ -27,7 +27,7 @@ func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy m proxy["skip-cert-verify"] = false proxy["tls"] = false tls := strings.ToLower(query.Get("security")) - if strings.HasSuffix(tls, "tls") { + if strings.HasSuffix(tls, "tls") || tls == "reality" { proxy["tls"] = true if fingerprint := query.Get("fp"); fingerprint == "" { proxy["client-fingerprint"] = "chrome" From 545cbeeec067cb4f3d201293570b9f8cf7285878 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 27 Mar 2023 00:49:32 +0800 Subject: [PATCH 139/530] chore: skip restart when update error --- hub/route/upgrade.go | 1 + 1 file changed, 1 insertion(+) diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index a4a8e683..b60d60d4 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -27,6 +27,7 @@ func upgrade(w http.ResponseWriter, r *http.Request) { err := updater.Update() if err != nil { log.Errorln("err:%s", err) + return } execPath, err := os.Executable() From 6ca14c814efb3c38ad8f15179511854bc7ffbf6e Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 27 Mar 2023 22:18:54 +0800 Subject: [PATCH 140/530] fix: tproxy listener cannot listen udp --- listener/inbound/tproxy.go | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/listener/inbound/tproxy.go b/listener/inbound/tproxy.go index fa458d2c..00cd0849 100644 --- a/listener/inbound/tproxy.go +++ b/listener/inbound/tproxy.go @@ -56,13 +56,10 @@ func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter return err } if t.udp { - if t.lUDP != nil { - t.lUDP, err = tproxy.NewUDP(t.RawAddress(), udpIn, natTable, t.Additions()...) - if err != nil { - return err - } + t.lUDP, err = tproxy.NewUDP(t.RawAddress(), udpIn, natTable, t.Additions()...) + if err != nil { + return err } - } log.Infoln("TProxy[%s] proxy listening at: %s", t.Name(), t.Address()) return nil From 6d40de2179a644a722ee314554ecac5df9f7fdda Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 27 Mar 2023 22:27:59 +0800 Subject: [PATCH 141/530] chore: adjust trust cert --- component/tls/config.go | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/component/tls/config.go b/component/tls/config.go index f0155d78..91b89f1d 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -14,7 +14,7 @@ import ( xtls "github.com/xtls/go" ) -var trustCert, _ = x509.SystemCertPool() +var trustCerts []*x509.Certificate var mutex sync.RWMutex var errNotMacth error = errors.New("certificate fingerprints do not match") @@ -25,16 +25,28 @@ func AddCertificate(certificate string) error { if certificate == "" { return fmt.Errorf("certificate is empty") } - if ok := trustCert.AppendCertsFromPEM([]byte(certificate)); !ok { + if cert, err := x509.ParseCertificate([]byte(certificate)); err == nil { + trustCerts = append(trustCerts, cert) + return nil + } else { return fmt.Errorf("add certificate failed") } - return nil } func ResetCertificate() { mutex.Lock() defer mutex.Unlock() - trustCert, _ = x509.SystemCertPool() + trustCerts = nil +} + +func getCertPool() *x509.CertPool { + certPool, err := x509.SystemCertPool() + if err == nil { + for _, cert := range trustCerts { + certPool.AddCert(cert) + } + } + return certPool } func verifyFingerprint(fingerprint *[32]byte) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { @@ -84,12 +96,13 @@ func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) } func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config { + certPool := getCertPool() if tlsConfig == nil { return &tls.Config{ - RootCAs: trustCert, + RootCAs: certPool, } } - tlsConfig.RootCAs = trustCert + tlsConfig.RootCAs = certPool return tlsConfig } @@ -106,12 +119,13 @@ func GetSpecifiedFingerprintXTLSConfig(tlsConfig *xtls.Config, fingerprint strin } func GetGlobalXTLSConfig(tlsConfig *xtls.Config) *xtls.Config { + certPool := getCertPool() if tlsConfig == nil { return &xtls.Config{ - RootCAs: trustCert, + RootCAs: certPool, } } - tlsConfig.RootCAs = trustCert + tlsConfig.RootCAs = certPool return tlsConfig } From 34c91e5fe0cf964247cf1c4fe1ebbc7281e0b2f0 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 28 Mar 2023 16:40:45 +0000 Subject: [PATCH 142/530] chore: add release branch --- .github/workflows/build.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dc43a10e..8c853ab0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -268,6 +268,18 @@ jobs: generate_release_notes: true body_path: release.txt + - name: Git push assets to "release" branch + run: | + cd bin || exit 1 + git init + git config --local user.name "github-actions[bot]" + git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" + git checkout -b release + git add . + git commit -m "${{ env.BUILDTIME }}" + git remote add origin "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" + git push -f -u origin release + Upload-Release: permissions: write-all if: ${{ github.ref_type=='tag' }} From 1fdd1f702e7cd2bedba2b9cbcdadd5f9c497c64c Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 28 Mar 2023 17:00:21 +0000 Subject: [PATCH 143/530] chore: better rename --- .github/rename-cgo.sh | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/rename-cgo.sh b/.github/rename-cgo.sh index 54841712..a0d736de 100644 --- a/.github/rename-cgo.sh +++ b/.github/rename-cgo.sh @@ -15,6 +15,15 @@ do elif [[ $FILENAME =~ "windows-4.0-amd64" ]];then echo "rename windows amd64 $FILENAME" mv $FILENAME clash.meta-windows-amd64-cgo.exe + elif [[ $FILENAME =~ "clash.meta-linux-arm-5" ]];then + echo "rename clash.meta-linux-arm-5 $FILENAME" + mv $FILENAME clash.meta-linux-armv5-cgo + elif [[ $FILENAME =~ "clash.meta-linux-arm-6" ]];then + echo "rename clash.meta-linux-arm-6 $FILENAME" + mv $FILENAME clash.meta-linux-armv6-cgo + elif [[ $FILENAME =~ "clash.meta-linux-arm-7" ]];then + echo "rename clash.meta-linux-arm-7 $FILENAME" + mv $FILENAME clash.meta-linux-armv7-cgo elif [[ $FILENAME =~ "linux" ]];then echo "rename linux $FILENAME" mv $FILENAME $FILENAME-cgo From d730feecb43aa85c409bb1b33775177d83184f0c Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 29 Mar 2023 06:03:13 +0000 Subject: [PATCH 144/530] chore: use inner for upgrade core --- constant/path.go | 6 ++--- hub/updater/updater.go | 55 +++++++++++++++++++++--------------------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/constant/path.go b/constant/path.go index 707c53f6..29ac9872 100644 --- a/constant/path.go +++ b/constant/path.go @@ -66,7 +66,7 @@ func (p *path) MMDB() string { // 目录则直接跳过 continue } else { - if strings.EqualFold(strings.ToLower(fi.Name()), "country.mmdb") { + if strings.EqualFold(fi.Name(), "Country.mmdb") { GeoipName = fi.Name() return P.Join(p.homeDir, fi.Name()) } @@ -93,7 +93,7 @@ func (p *path) GeoIP() string { // 目录则直接跳过 continue } else { - if strings.EqualFold(strings.ToLower(fi.Name()), "geoip.dat") { + if strings.EqualFold(fi.Name(), "GeoIP.dat") { GeoipName = fi.Name() return P.Join(p.homeDir, fi.Name()) } @@ -112,7 +112,7 @@ func (p *path) GeoSite() string { // 目录则直接跳过 continue } else { - if strings.EqualFold(strings.ToLower(fi.Name()), "geosite.dat") { + if strings.EqualFold(fi.Name(), "GeoSite.dat") { GeositeName = fi.Name() return P.Join(p.homeDir, fi.Name()) } diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 272b5017..84b0040f 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -3,6 +3,7 @@ package updater import ( "archive/zip" "compress/gzip" + "context" "fmt" "io" "net/http" @@ -11,7 +12,9 @@ import ( "runtime" "strings" "sync" + "time" + clashHttp "github.com/Dreamacro/clash/component/http" "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" ) @@ -19,21 +22,16 @@ import ( // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/updater/updater.go // Updater is the Clash.Meta updater. var ( - client http.Client - goarch string goos string goarm string gomips string - workDir string - versionCheckURL string + workDir string // mu protects all fields below. mu sync.RWMutex - // TODO(a.garipov): See if all of these fields actually have to be in - // this struct. currentExeName string // 当前可执行文件 updateDir string // 更新目录 packageName string // 更新压缩文件 @@ -42,8 +40,8 @@ var ( updateExeName string // 更新后的可执行文件 unpackedFile string - baseURL string = "https://ghproxy.com/https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/clash.meta" - versionURL string = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/version.txt" + baseURL string = "https://testingcf.jsdelivr.net/gh/MetaCubeX/Clash.Meta@release/clash.meta" + versionURL string = "https://raw.githubusercontent.com/MetaCubeX/Clash.Meta/release/version.txt" packageURL string latestVersion string ) @@ -61,7 +59,13 @@ func (e *updateError) Error() string { func Update() (err error) { goos = runtime.GOOS goarch = runtime.GOARCH - latestVersion = getLatestVersion() + latestVersion, err = getLatestVersion() + if err != nil { + err := &updateError{Message: err.Error()} + return err + } + + log.Infoln("current version alpha-%s, latest version alpha-%s", constant.Version, latestVersion) if latestVersion == constant.Version { err := &updateError{Message: "Already using latest version"} @@ -72,8 +76,6 @@ func Update() (err error) { mu.Lock() defer mu.Unlock() - log.Infoln("current version alpha-%s", constant.Version) - defer func() { if err != nil { log.Errorln("updater: failed: %v", err) @@ -115,14 +117,6 @@ func Update() (err error) { return nil } -// VersionCheckURL returns the version check URL. -func VersionCheckURL() (vcu string) { - mu.RLock() - defer mu.RUnlock() - - return versionCheckURL -} - // prepare fills all necessary fields in Updater object. func prepare(exePath string) (err error) { updateDir = filepath.Join(workDir, "meta-update") @@ -226,8 +220,11 @@ const MaxPackageFileSize = 32 * 1024 * 1024 // Download package file and save it to disk func downloadPackageFile() (err error) { - var resp *http.Response - resp, err = client.Get(packageURL) + // var resp *http.Response + // resp, err = client.Get(packageURL) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) + defer cancel() + resp, err := clashHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) if err != nil { return fmt.Errorf("http request failed: %w", err) } @@ -255,11 +252,11 @@ func downloadPackageFile() (err error) { log.Debugln("updateDir %s", updateDir) err = os.Mkdir(updateDir, 0o755) if err != nil { - fmt.Errorf("mkdir error: %w", err) + return fmt.Errorf("mkdir error: %w", err) } log.Debugln("updater: saving package to file %s", packageName) - err = os.WriteFile(packageName, body, 0o755) + err = os.WriteFile(packageName, body, 0o644) if err != nil { return fmt.Errorf("os.WriteFile() failed: %w", err) } @@ -405,10 +402,12 @@ func copyFile(src, dst string) error { return nil } -func getLatestVersion() string { - resp, err := http.Get(versionURL) +func getLatestVersion() (version string, err error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) + defer cancel() + resp, err := clashHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) if err != nil { - return "" + return "", fmt.Errorf("get Latest Version fail: %w", err) } defer func() { closeErr := resp.Body.Close() @@ -419,11 +418,11 @@ func getLatestVersion() string { body, err := io.ReadAll(resp.Body) if err != nil { - return "" + return "", fmt.Errorf("get Latest Version fail: %w", err) } content := strings.TrimRight(string(body), "\n") log.Infoln("latest:%s", content) - return content + return content, nil } func updateDownloadURL() { From 2c7153cd7a4fbd4fc1deb07cac06c8dffbf127ca Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 29 Mar 2023 16:19:26 +0800 Subject: [PATCH 145/530] chore: clean up code --- hub/route/restart.go | 2 +- hub/route/upgrade.go | 44 +------------------------------------------- 2 files changed, 2 insertions(+), 44 deletions(-) diff --git a/hub/route/restart.go b/hub/route/restart.go index bbf83f5e..9539296e 100644 --- a/hub/route/restart.go +++ b/hub/route/restart.go @@ -47,7 +47,7 @@ func restart(w http.ResponseWriter, r *http.Request) { cmd.Stderr = os.Stderr err = cmd.Start() if err != nil { - log.Fatalln("restarting:: %s", err) + log.Fatalln("restarting: %s", err) } os.Exit(0) diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index b60d60d4..5adf79eb 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -1,18 +1,12 @@ package route import ( - "fmt" "net/http" - "os" - "os/exec" - "runtime" - "syscall" "github.com/Dreamacro/clash/hub/updater" "github.com/Dreamacro/clash/log" "github.com/go-chi/chi/v5" - "github.com/go-chi/render" ) func upgradeRouter() http.Handler { @@ -30,41 +24,5 @@ func upgrade(w http.ResponseWriter, r *http.Request) { return } - execPath, err := os.Executable() - if err != nil { - render.Status(r, http.StatusInternalServerError) - render.JSON(w, r, newError(fmt.Sprintf("getting path: %s", err))) - return - } - - render.JSON(w, r, render.M{"status": "ok"}) - if f, ok := w.(http.Flusher); ok { - f.Flush() - } - - // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L180 - // The background context is used because the underlying functions wrap it - // with timeout and shut down the server, which handles current request. It - // also should be done in a separate goroutine for the same reason. - go func() { - if runtime.GOOS == "windows" { - cmd := exec.Command(execPath, os.Args[1:]...) - log.Infoln("restarting: %q %q", execPath, os.Args[1:]) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err = cmd.Start() - if err != nil { - log.Fatalln("restarting: %s", err) - } - - os.Exit(0) - } - - log.Infoln("restarting: %q %q", execPath, os.Args[1:]) - err = syscall.Exec(execPath, os.Args, os.Environ()) - if err != nil { - log.Fatalln("restarting: %s", err) - } - }() + restart(w, r) } From 7c80c88feb0aea7b83f31bed284dc3cf69056088 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 29 Mar 2023 12:26:10 +0000 Subject: [PATCH 146/530] chore: push latest alpha core to `MetaCubeX/AlphaBinary` --- .github/workflows/build.yml | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8c853ab0..b90c06ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -268,17 +268,13 @@ jobs: generate_release_notes: true body_path: release.txt - - name: Git push assets to "release" branch - run: | - cd bin || exit 1 - git init - git config --local user.name "github-actions[bot]" - git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com" - git checkout -b release - git add . - git commit -m "${{ env.BUILDTIME }}" - git remote add origin "https://${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}" - git push -f -u origin release + - name: Push to `MetaCubeX/AlphaBinary` + uses: s0/git-publish-subdir-action@develop + env: + REPO: git@github.com:MetaCubeX/AlphaBinary.git + BRANCH: release + FOLDER: bin + SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_PRIVATE_KEY }} Upload-Release: permissions: write-all From db7623968d1c677974335473b5eae255bc0c26ee Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 29 Mar 2023 20:50:46 +0800 Subject: [PATCH 147/530] fix: inner http use host of address --- adapter/inbound/socket.go | 2 ++ component/http/http.go | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index 4024ee42..a6b1288c 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -42,6 +42,8 @@ func NewInner(conn net.Conn, dst string, host string) *context.ConnContext { if host == "" { if ip, err := netip.ParseAddr(h); err == nil { metadata.DstIP = ip + } else { + metadata.Host = h } } } diff --git a/component/http/http.go b/component/http/http.go index eb8478cd..ece7b442 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -53,7 +53,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - conn := inner.HandleTcp(address, urlRes.Hostname()) + conn := inner.HandleTcp(address, "") return conn, nil }, TLSClientConfig: tls.GetDefaultTLSConfig(), From 2fef329319a33630c0d66703012ff8963e758476 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 29 Mar 2023 13:59:36 +0000 Subject: [PATCH 148/530] fix: upgrade backup --- .github/workflows/build.yml | 8 ------ hub/updater/updater.go | 55 +++++++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 28 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b90c06ef..dc43a10e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -268,14 +268,6 @@ jobs: generate_release_notes: true body_path: release.txt - - name: Push to `MetaCubeX/AlphaBinary` - uses: s0/git-publish-subdir-action@develop - env: - REPO: git@github.com:MetaCubeX/AlphaBinary.git - BRANCH: release - FOLDER: bin - SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_PRIVATE_KEY }} - Upload-Release: permissions: write-all if: ${{ github.ref_type=='tag' }} diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 84b0040f..077818fd 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -38,10 +38,9 @@ var ( backupDir string // 备份目录 backupExeName string // 备份文件名 updateExeName string // 更新后的可执行文件 - unpackedFile string - baseURL string = "https://testingcf.jsdelivr.net/gh/MetaCubeX/Clash.Meta@release/clash.meta" - versionURL string = "https://raw.githubusercontent.com/MetaCubeX/Clash.Meta/release/version.txt" + baseURL string = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/clash.meta" + versionURL string = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/version.txt" packageURL string latestVersion string ) @@ -57,6 +56,9 @@ func (e *updateError) Error() string { // Update performs the auto-updater. It returns an error if the updater failed. // If firstRun is true, it assumes the configuration file doesn't exist. func Update() (err error) { + mu.Lock() + defer mu.Unlock() + goos = runtime.GOOS goarch = runtime.GOARCH latestVersion, err = getLatestVersion() @@ -73,8 +75,6 @@ func Update() (err error) { } updateDownloadURL() - mu.Lock() - defer mu.Unlock() defer func() { if err != nil { @@ -90,7 +90,6 @@ func Update() (err error) { } workDir = filepath.Dir(execPath) - //log.Infoln("workDir %s", execPath) err = prepare(execPath) if err != nil { @@ -109,6 +108,11 @@ func Update() (err error) { return fmt.Errorf("unpacking: %w", err) } + err = backup() + if err != nil { + return fmt.Errorf("replacing: %w", err) + } + err = replace() if err != nil { return fmt.Errorf("replacing: %w", err) @@ -136,7 +140,7 @@ func prepare(exePath string) (err error) { updateExeName = "clash.meta" + "-" + goos + "-" + goarch } - log.Infoln("updateExeName: %s ,currentExeName: %s", updateExeName, currentExeName) + log.Infoln("updateExeName: %s ", updateExeName) backupExeName = filepath.Join(backupDir, filepath.Base(exePath)) updateExeName = filepath.Join(updateDir, updateExeName) @@ -162,13 +166,13 @@ func unpack() error { log.Debugln("updater: unpacking package") if strings.HasSuffix(pkgNameOnly, ".zip") { - unpackedFile, err = zipFileUnpack(packageName, updateDir) + _, err = zipFileUnpack(packageName, updateDir) if err != nil { return fmt.Errorf(".zip unpack failed: %w", err) } } else if strings.HasSuffix(pkgNameOnly, ".gz") { - unpackedFile, err = gzFileUnpack(packageName, updateDir) + _, err = gzFileUnpack(packageName, updateDir) if err != nil { return fmt.Errorf(".gz unpack failed: %w", err) } @@ -180,25 +184,37 @@ func unpack() error { return nil } +// backup makes a backup of the current configuration and supporting files. It +// ignores the configuration file if firstRun is true. +func backup() (err error) { + log.Infoln("updater: backing up current Exefile") + _ = os.Mkdir(backupDir, 0o755) + + err = copyFile(currentExeName, backupExeName) + if err != nil { + return fmt.Errorf("copySupportingFiles(%s, %s) failed: %w", currentExeName, backupExeName, err) + } + + return nil +} + // replace moves the current executable with the updated one and also copies the // supporting files. func replace() error { - //err := copySupportingFiles(unpackedFiles, updateDir, workDir) - //if err != nil { - // return fmt.Errorf("copySupportingFiles(%s, %s) failed: %w", updateDir, workDir, err) - //} + var err error - log.Infoln("updater: renaming: %s to %s", currentExeName, backupExeName) - err := os.Rename(currentExeName, backupExeName) - if err != nil { - return err - } + // log.Infoln("updater: renaming: %s to %s", currentExeName, backupExeName) + // err := os.Rename(currentExeName, backupExeName) + // if err != nil { + // return err + // } if goos == "windows" { // rename fails with "File in use" error - log.Infoln("copying:%s to %s", updateExeName, currentExeName) + log.Infoln("copying: %s to %s", updateExeName, currentExeName) err = copyFile(updateExeName, currentExeName) } else { + log.Infoln("copying: %s to %s", updateExeName, currentExeName) err = os.Rename(updateExeName, currentExeName) } if err != nil { @@ -421,7 +437,6 @@ func getLatestVersion() (version string, err error) { return "", fmt.Errorf("get Latest Version fail: %w", err) } content := strings.TrimRight(string(body), "\n") - log.Infoln("latest:%s", content) return content, nil } From 991de009beadf0b7cb82600cbbb578ea55c6b0d8 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 30 Mar 2023 15:57:52 +0000 Subject: [PATCH 149/530] chore: update readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 2e485db2..9339a935 100644 --- a/README.md +++ b/README.md @@ -30,8 +30,7 @@ - Comprehensive HTTP RESTful API controller ## Wiki - -Documentation and configuring examples are available on [Clash.Meta Wiki](https://clash-meta.wiki). +Configuration examples can be found at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml), while documentation can be found [Clash.Meta Wiki](https://clash-meta.wiki). ## Build From cfd03a99c22f7d5129877843874f322554452774 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 1 Apr 2023 11:53:39 +0800 Subject: [PATCH 150/530] feat: `nameserver-policy` support use rule-providers and reduce domain-set memory --- common/pool/buffer_low_memory.go | 15 ++ common/pool/buffer_standard.go | 15 ++ common/pool/pool.go | 12 -- common/utils/strings.go | 9 + component/sniffer/dispatcher.go | 12 +- component/tls/config.go | 20 +- component/trie/domain.go | 26 ++- component/trie/domain_test.go | 20 ++ component/trie/node.go | 12 ++ component/trie/set_test.go | 60 ++++++ component/trie/sskv.go | 178 ++++++++++++++++++ config/config.go | 58 +++--- constant/features/low_memory.go | 5 + constant/features/no_doq.go | 7 - constant/features/no_fake_tcp.go | 7 + constant/features/no_gvisor.go | 7 - constant/features/with_gvisor.go | 7 + dns/resolver.go | 43 ++++- docs/config.yaml | 1 + go.mod | 6 + go.sum | 16 +- hub/executor/executor.go | 35 +++- listener/sing_tun/dns.go | 5 +- rules/common/domain.go | 12 +- rules/common/domain_keyword.go | 12 +- rules/common/domain_suffix.go | 12 +- rules/common/network_type.go | 2 - rules/provider/domain_strategy.go | 22 +-- transport/hysteria/conns/faketcp/tcp_linux.go | 4 +- transport/hysteria/conns/faketcp/tcp_stub.go | 4 +- 30 files changed, 503 insertions(+), 141 deletions(-) create mode 100644 common/pool/buffer_low_memory.go create mode 100644 common/pool/buffer_standard.go create mode 100644 common/utils/strings.go create mode 100644 component/trie/set_test.go create mode 100644 component/trie/sskv.go create mode 100644 constant/features/low_memory.go delete mode 100644 constant/features/no_doq.go create mode 100644 constant/features/no_fake_tcp.go delete mode 100644 constant/features/no_gvisor.go create mode 100644 constant/features/with_gvisor.go diff --git a/common/pool/buffer_low_memory.go b/common/pool/buffer_low_memory.go new file mode 100644 index 00000000..24e18a75 --- /dev/null +++ b/common/pool/buffer_low_memory.go @@ -0,0 +1,15 @@ +//go:build with_low_memory + +package pool + +const ( + // io.Copy default buffer size is 32 KiB + // but the maximum packet size of vmess/shadowsocks is about 16 KiB + // so define a buffer of 20 KiB to reduce the memory of each TCP relay + RelayBufferSize = 16 * 1024 + + // RelayBufferSize uses 20KiB, but due to the allocator it will actually + // request 32Kib. Most UDPs are smaller than the MTU, and the TUN's MTU + // set to 9000, so the UDP Buffer size set to 16Kib + UDPBufferSize = 8 * 1024 +) diff --git a/common/pool/buffer_standard.go b/common/pool/buffer_standard.go new file mode 100644 index 00000000..ff758700 --- /dev/null +++ b/common/pool/buffer_standard.go @@ -0,0 +1,15 @@ +//go:build !with_low_memory + +package pool + +const ( + // io.Copy default buffer size is 32 KiB + // but the maximum packet size of vmess/shadowsocks is about 16 KiB + // so define a buffer of 20 KiB to reduce the memory of each TCP relay + RelayBufferSize = 20 * 1024 + + // RelayBufferSize uses 20KiB, but due to the allocator it will actually + // request 32Kib. Most UDPs are smaller than the MTU, and the TUN's MTU + // set to 9000, so the UDP Buffer size set to 16Kib + UDPBufferSize = 16 * 1024 +) diff --git a/common/pool/pool.go b/common/pool/pool.go index bee4887f..288ea467 100644 --- a/common/pool/pool.go +++ b/common/pool/pool.go @@ -1,17 +1,5 @@ package pool -const ( - // io.Copy default buffer size is 32 KiB - // but the maximum packet size of vmess/shadowsocks is about 16 KiB - // so define a buffer of 20 KiB to reduce the memory of each TCP relay - RelayBufferSize = 20 * 1024 - - // RelayBufferSize uses 20KiB, but due to the allocator it will actually - // request 32Kib. Most UDPs are smaller than the MTU, and the TUN's MTU - // set to 9000, so the UDP Buffer size set to 16Kib - UDPBufferSize = 16 * 1024 -) - func Get(size int) []byte { return defaultAllocator.Get(size) } diff --git a/common/utils/strings.go b/common/utils/strings.go new file mode 100644 index 00000000..5d5ae596 --- /dev/null +++ b/common/utils/strings.go @@ -0,0 +1,9 @@ +package utils + +func Reverse(s string) string { + a := []rune(s) + for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 { + a[i], a[j] = a[j], a[i] + } + return string(a) +} diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 97d448ce..bf0b1bb3 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -28,8 +28,8 @@ var Dispatcher *SnifferDispatcher type SnifferDispatcher struct { enable bool sniffers map[sniffer.Sniffer]SnifferConfig - forceDomain *trie.DomainTrie[struct{}] - skipSNI *trie.DomainTrie[struct{}] + forceDomain *trie.DomainSet + skipSNI *trie.DomainSet skipList *cache.LruCache[string, uint8] rwMux sync.RWMutex forceDnsMapping bool @@ -37,7 +37,7 @@ type SnifferDispatcher struct { } func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) { - if (metadata.Host == "" && sd.parsePureIp) || sd.forceDomain.Search(metadata.Host) != nil || (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) { + 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") @@ -74,7 +74,7 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%s] to [%s:%s]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort) return } else { - if sd.skipSNI.Search(host) != nil { + if sd.skipSNI.Has(host) { log.Debugln("[Sniffer] Skip sni[%s]", host) return } @@ -166,8 +166,8 @@ func NewCloseSnifferDispatcher() (*SnifferDispatcher, error) { return &dispatcher, nil } -func NewSnifferDispatcher(snifferConfig map[sniffer.Type]SnifferConfig, forceDomain *trie.DomainTrie[struct{}], - skipSNI *trie.DomainTrie[struct{}], +func NewSnifferDispatcher(snifferConfig map[sniffer.Type]SnifferConfig, + forceDomain *trie.DomainSet, skipSNI *trie.DomainSet, forceDnsMapping bool, parsePureIp bool) (*SnifferDispatcher, error) { dispatcher := SnifferDispatcher{ enable: true, diff --git a/component/tls/config.go b/component/tls/config.go index 91b89f1d..b5b56591 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -15,7 +15,7 @@ import ( ) var trustCerts []*x509.Certificate - +var certPool *x509.CertPool var mutex sync.RWMutex var errNotMacth error = errors.New("certificate fingerprints do not match") @@ -40,10 +40,20 @@ func ResetCertificate() { } func getCertPool() *x509.CertPool { - certPool, err := x509.SystemCertPool() - if err == nil { - for _, cert := range trustCerts { - certPool.AddCert(cert) + if len(trustCerts) == 0 { + return nil + } + if certPool == nil { + mutex.Lock() + defer mutex.Unlock() + if certPool != nil { + return certPool + } + certPool, err := x509.SystemCertPool() + if err == nil { + for _, cert := range trustCerts { + certPool.AddCert(cert) + } } } return certPool diff --git a/component/trie/domain.go b/component/trie/domain.go index d9463c6e..86e5245a 100644 --- a/component/trie/domain.go +++ b/component/trie/domain.go @@ -25,7 +25,7 @@ func ValidAndSplitDomain(domain string) ([]string, bool) { if domain != "" && domain[len(domain)-1] == '.' { return nil, false } - + domain=strings.ToLower(domain) parts := strings.Split(domain, domainStep) if len(parts) == 1 { if parts[0] == "" { @@ -123,6 +123,30 @@ func (t *DomainTrie[T]) Optimize() { t.root.optimize() } +func (t *DomainTrie[T]) Foreach(print func(domain string, data T)) { + for key, data := range t.root.getChildren() { + recursion([]string{key}, data, print) + } +} + +func recursion[T any](items []string, node *Node[T], fn func(domain string, data T)) { + for key, data := range node.getChildren() { + newItems := append([]string{key}, items...) + if data != nil && data.inited { + domain := joinDomain(newItems) + if domain[0] == domainStepByte { + domain = complexWildcard + domain + } + fn(domain, data.Data()) + } + recursion(newItems, data, fn) + } +} + +func joinDomain(items []string) string { + return strings.Join(items, domainStep) +} + // New returns a new, empty Trie. func New[T any]() *DomainTrie[T] { return &DomainTrie[T]{root: newNode[T]()} diff --git a/component/trie/domain_test.go b/component/trie/domain_test.go index c54b3d3b..2dfd1c34 100644 --- a/component/trie/domain_test.go +++ b/component/trie/domain_test.go @@ -105,3 +105,23 @@ func TestTrie_WildcardBoundary(t *testing.T) { assert.NotNil(t, tree.Search("example.com")) } + +func TestTrie_Foreach(t *testing.T) { + tree := New[netip.Addr]() + domainList := []string{ + "google.com", + "stun.*.*.*", + "test.*.google.com", + "+.baidu.com", + "*.baidu.com", + "*.*.baidu.com", + } + for _, domain := range domainList { + tree.Insert(domain, localIP) + } + count := 0 + tree.Foreach(func(domain string, data netip.Addr) { + count++ + }) + assert.Equal(t, 7, count) +} diff --git a/component/trie/node.go b/component/trie/node.go index e19b40ac..3aa2bc7d 100644 --- a/component/trie/node.go +++ b/component/trie/node.go @@ -116,6 +116,18 @@ func (n *Node[T]) setData(data T) { n.inited = true } +func (n *Node[T]) getChildren() map[string]*Node[T] { + if n.childMap == nil { + if n.childNode != nil { + m := make(map[string]*Node[T]) + m[n.childStr] = n.childNode + return m + } + } else { + return n.childMap + } + return nil +} func (n *Node[T]) Data() T { return n.data } diff --git a/component/trie/set_test.go b/component/trie/set_test.go new file mode 100644 index 00000000..346bb31a --- /dev/null +++ b/component/trie/set_test.go @@ -0,0 +1,60 @@ +package trie_test + +import ( + "testing" + + "github.com/Dreamacro/clash/component/trie" + "github.com/stretchr/testify/assert" +) + +func TestDomain(t *testing.T) { + domainSet := []string{ + "baidu.com", + "google.com", + "www.google.com", + "test.a.net", + "test.a.oc", + } + set := trie.NewDomainSet(domainSet) + assert.NotNil(t, set) + assert.True(t, set.Has("test.a.net")) + assert.True(t, set.Has("google.com")) + assert.False(t, set.Has("www.baidu.com")) +} + +func TestDomainComplexWildcard(t *testing.T) { + domainSet := []string{ + "+.baidu.com", + "+.a.baidu.com", + "www.baidu.com", + "+.bb.baidu.com", + "test.a.net", + "test.a.oc", + "www.qq.com", + } + set := trie.NewDomainSet(domainSet) + assert.NotNil(t, set) + assert.False(t, set.Has("google.com")) + assert.True(t, set.Has("www.baidu.com")) + assert.True(t, set.Has("test.test.baidu.com")) +} + +func TestDomainWildcard(t *testing.T) { + domainSet := []string{ + "*.*.*.baidu.com", + "www.baidu.*", + "stun.*.*", + "*.*.qq.com", + "test.*.baidu.com", + } + set := trie.NewDomainSet(domainSet) + assert.NotNil(t, set) + assert.True(t, set.Has("www.baidu.com")) + assert.True(t, set.Has("test.test.baidu.com")) + assert.True(t, set.Has("test.test.qq.com")) + assert.True(t,set.Has("stun.ab.cd")) + assert.False(t, set.Has("test.baidu.com")) + assert.False(t,set.Has("www.google.com")) + assert.False(t, set.Has("test.qq.com")) + assert.False(t, set.Has("test.test.test.qq.com")) +} diff --git a/component/trie/sskv.go b/component/trie/sskv.go new file mode 100644 index 00000000..6a661a85 --- /dev/null +++ b/component/trie/sskv.go @@ -0,0 +1,178 @@ +package trie + +// Package succinct provides several succinct data types. +// Modify from https://github.com/openacid/succinct/blob/d4684c35d123f7528b14e03c24327231723db704/sskv.go + +import ( + "sort" + "strings" + + "github.com/Dreamacro/clash/common/utils" + "github.com/openacid/low/bitmap" +) + +const ( + complexWildcardByte = byte('+') + wildcardByte = byte('*') + domainStepByte = byte('.') +) + +type DomainSet struct { + leaves, labelBitmap []uint64 + labels []byte + ranks, selects []int32 +} + +// NewDomainSet creates a new *DomainSet struct, from a slice of sorted strings. +func NewDomainSet(keys []string) *DomainSet { + domainTrie := New[struct{}]() + for _, domain := range keys { + domainTrie.Insert(domain, struct{}{}) + } + reserveDomains := make([]string, 0, len(keys)) + domainTrie.Foreach(func(domain string, data struct{}) { + reserveDomains = append(reserveDomains, utils.Reverse(domain)) + }) + // ensure that the same prefix is continuous + // and according to the ascending sequence of length + sort.Strings(reserveDomains) + keys = reserveDomains + if len(keys) == 0 { + return nil + } + 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] + if elt.col == len(keys[elt.s]) { + elt.s++ + // a leaf node + setBit(&ss.leaves, i, 1) + } + + for j := elt.s; j < elt.e; { + + frm := j + + for ; j < elt.e && keys[j][elt.col] == keys[frm][elt.col]; j++ { + } + queue = append(queue, qElt{frm, j, elt.col + 1}) + ss.labels = append(ss.labels, keys[frm][elt.col]) + setBit(&ss.labelBitmap, lIdx, 0) + lIdx++ + } + setBit(&ss.labelBitmap, lIdx, 1) + lIdx++ + } + + ss.init() + return ss +} + +// Has query for a key and return whether it presents in the DomainSet. +func (ss *DomainSet) Has(key string) bool { + if ss == nil { + return false + } + key = utils.Reverse(key) + key = strings.ToLower(key) + // no more labels in this node + // skip character matching + // go to next level + nodeId, bmIdx := 0, 0 + type wildcardCursor struct { + bmIdx, index int + } + stack := make([]wildcardCursor, 0) + for i := 0; i < len(key); i++ { + RESTART: + c := key[i] + for ; ; bmIdx++ { + if getBit(ss.labelBitmap, bmIdx) != 0 { + if len(stack) > 0 { + cursor := stack[len(stack)-1] + stack = stack[0 : len(stack)-1] + // back wildcard and find next node + nextNodeId := countZeros(ss.labelBitmap, ss.ranks, cursor.bmIdx+1) + nextBmIdx := selectIthOne(ss.labelBitmap, ss.ranks, ss.selects, nextNodeId-1) + 1 + j := cursor.index + for ; j < len(key) && key[j] != domainStepByte; j++ { + } + if j == len(key) { + if getBit(ss.leaves, nextNodeId) != 0 { + return true + }else { + goto RESTART + } + } + for ; ; nextBmIdx++ { + if ss.labels[nextBmIdx-nextNodeId] == domainStepByte { + bmIdx = nextBmIdx + nodeId = nextNodeId + i = j + goto RESTART + } + } + } + return false + } + // handle wildcard for domain + if ss.labels[bmIdx-nodeId] == complexWildcardByte { + return true + } else if ss.labels[bmIdx-nodeId] == wildcardByte { + cursor := wildcardCursor{} + cursor.bmIdx = bmIdx + cursor.index = i + stack = append(stack, cursor) + } else if ss.labels[bmIdx-nodeId] == c { + break + } + } + nodeId = countZeros(ss.labelBitmap, ss.ranks, bmIdx+1) + bmIdx = selectIthOne(ss.labelBitmap, ss.ranks, ss.selects, nodeId-1) + 1 + } + + return getBit(ss.leaves, nodeId) != 0 + +} + +func setBit(bm *[]uint64, i int, v int) { + for i>>6 >= len(*bm) { + *bm = append(*bm, 0) + } + (*bm)[i>>6] |= uint64(v) << uint(i&63) +} + +func getBit(bm []uint64, i int) uint64 { + return bm[i>>6] & (1 << uint(i&63)) +} + +// init builds pre-calculated cache to speed up rank() and select() +func (ss *DomainSet) init() { + ss.selects, ss.ranks = bitmap.IndexSelect32R64(ss.labelBitmap) +} + +// countZeros counts the number of "0" in a bitmap before the i-th bit(excluding +// the i-th bit) on behalf of rank index. +// E.g.: +// +// countZeros("010010", 4) == 3 +// // 012345 +func countZeros(bm []uint64, ranks []int32, i int) int { + a, _ := bitmap.Rank64(bm, ranks, int32(i)) + return i - int(a) +} + +// selectIthOne returns the index of the i-th "1" in a bitmap, on behalf of rank +// and select indexes. +// E.g.: +// +// selectIthOne("010010", 1) == 4 +// // 012345 +func selectIthOne(bm []uint64, ranks, selects []int32, i int) int { + a, _ := bitmap.Select32R64(bm, selects, ranks, int32(i)) + return int(a) +} diff --git a/config/config.go b/config/config.go index c407aad5..d2378822 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,6 @@ import ( "net/url" "os" "regexp" - "runtime" "strconv" "strings" "time" @@ -136,9 +135,8 @@ type IPTables struct { type Sniffer struct { Enable bool Sniffers map[snifferTypes.Type]SNIFF.SnifferConfig - Reverses *trie.DomainTrie[struct{}] - ForceDomain *trie.DomainTrie[struct{}] - SkipDomain *trie.DomainTrie[struct{}] + ForceDomain *trie.DomainSet + SkipDomain *trie.DomainSet ForceDnsMapping bool ParsePureIp bool } @@ -490,7 +488,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } config.Hosts = hosts - dnsCfg, err := parseDNS(rawCfg, hosts, rules) + dnsCfg, err := parseDNS(rawCfg, hosts, rules, ruleProviders) if err != nil { return nil, err } @@ -822,8 +820,6 @@ func parseRules(rulesConfig []string, proxies map[string]C.Proxy, subRules map[s rules = append(rules, parsed) } - runtime.GC() - return rules, nil } @@ -983,7 +979,7 @@ func parsePureDNSServer(server string) string { } } } -func parseNameServerPolicy(nsPolicy map[string]any, preferH3 bool) (map[string][]dns.NameServer, error) { +func parseNameServerPolicy(nsPolicy map[string]any, ruleProviders map[string]providerTypes.RuleProvider, preferH3 bool) (map[string][]dns.NameServer, error) { policy := map[string][]dns.NameServer{} updatedPolicy := make(map[string]interface{}) re := regexp.MustCompile(`[a-zA-Z0-9\-]+\.[a-zA-Z]{2,}(\.[a-zA-Z]{2,})?`) @@ -998,6 +994,14 @@ func parseNameServerPolicy(nsPolicy map[string]any, preferH3 bool) (map[string][ newKey := "geosite:" + subkey updatedPolicy[newKey] = v } + } else if strings.Contains(k, "rule-set:") { + subkeys := strings.Split(k, ":") + subkeys = subkeys[1:] + subkeys = strings.Split(subkeys[0], ",") + for _, subkey := range subkeys { + newKey := "rule-set:" + subkey + updatedPolicy[newKey] = v + } } else if re.MatchString(k) { subkeys := strings.Split(k, ",") for _, subkey := range subkeys { @@ -1021,6 +1025,19 @@ func parseNameServerPolicy(nsPolicy map[string]any, preferH3 bool) (map[string][ if _, valid := trie.ValidAndSplitDomain(domain); !valid { return nil, fmt.Errorf("DNS ResoverRule invalid domain: %s", domain) } + if strings.HasPrefix(domain, "rule-set:") { + domainSetName := domain[9:] + if provider, ok := ruleProviders[domainSetName]; !ok { + return nil, fmt.Errorf("not found rule-set: %s", domainSetName) + } else { + switch provider.Behavior() { + case providerTypes.IPCIDR: + return nil, fmt.Errorf("rule provider type error, except domain,actual %s", provider.Behavior()) + case providerTypes.Classical: + log.Warnln("%s provider is %s, only matching it contain domain rule", provider.Name(), provider.Behavior()) + } + } + } policy[domain] = nameservers } @@ -1073,11 +1090,10 @@ func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainM log.Infoln("Start initial GeoSite dns fallback filter `%s`, records: %d", country, recordsCount) } } - runtime.GC() return sites, nil } -func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule) (*DNS, error) { +func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) { cfg := rawCfg.DNS if cfg.Enable && len(cfg.NameServer) == 0 { return nil, fmt.Errorf("if DNS configuration is turned on, NameServer cannot be empty") @@ -1104,7 +1120,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul return nil, err } - if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, cfg.PreferH3); err != nil { + if dnsCfg.NameServerPolicy, err = parseNameServerPolicy(cfg.NameServerPolicy, ruleProviders, cfg.PreferH3); err != nil { return nil, err } @@ -1324,24 +1340,8 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { } sniffer.Sniffers = loadSniffer - sniffer.ForceDomain = trie.New[struct{}]() - for _, domain := range snifferRaw.ForceDomain { - err := sniffer.ForceDomain.Insert(domain, struct{}{}) - if err != nil { - return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err) - } - } - sniffer.ForceDomain.Optimize() - - sniffer.SkipDomain = trie.New[struct{}]() - for _, domain := range snifferRaw.SkipDomain { - err := sniffer.SkipDomain.Insert(domain, struct{}{}) - if err != nil { - return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err) - } - } - sniffer.SkipDomain.Optimize() - + sniffer.ForceDomain = trie.NewDomainSet(snifferRaw.ForceDomain) + sniffer.SkipDomain = trie.NewDomainSet(snifferRaw.SkipDomain) return sniffer, nil } diff --git a/constant/features/low_memory.go b/constant/features/low_memory.go new file mode 100644 index 00000000..32d10fa6 --- /dev/null +++ b/constant/features/low_memory.go @@ -0,0 +1,5 @@ +package features + +func init() { + TAGS = append(TAGS, "with_low_memory") +} diff --git a/constant/features/no_doq.go b/constant/features/no_doq.go deleted file mode 100644 index c915272f..00000000 --- a/constant/features/no_doq.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build no_doq - -package features - -func init() { - TAGS = append(TAGS, "no_doq") -} diff --git a/constant/features/no_fake_tcp.go b/constant/features/no_fake_tcp.go new file mode 100644 index 00000000..f536a066 --- /dev/null +++ b/constant/features/no_fake_tcp.go @@ -0,0 +1,7 @@ +//go:build no_fake_tcp + +package features + +func init() { + TAGS = append(TAGS, "no_fake_tcp") +} diff --git a/constant/features/no_gvisor.go b/constant/features/no_gvisor.go deleted file mode 100644 index d0d5391a..00000000 --- a/constant/features/no_gvisor.go +++ /dev/null @@ -1,7 +0,0 @@ -//go:build no_gvisor - -package features - -func init() { - TAGS = append(TAGS, "no_gvisor") -} diff --git a/constant/features/with_gvisor.go b/constant/features/with_gvisor.go new file mode 100644 index 00000000..1b3417b3 --- /dev/null +++ b/constant/features/with_gvisor.go @@ -0,0 +1,7 @@ +//go:build with_gvisor + +package features + +func init() { + TAGS = append(TAGS, "with_gvisor") +} diff --git a/dns/resolver.go b/dns/resolver.go index c16aad40..b5a09fd0 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -16,6 +16,7 @@ import ( "github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/component/trie" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/log" D "github.com/miekg/dns" @@ -40,6 +41,11 @@ type geositePolicyRecord struct { inversedMatching bool } +type domainSetPolicyRecord struct { + domainSetProvider provider.RuleProvider + policy *Policy +} + type Resolver struct { ipv6 bool ipv6Timeout time.Duration @@ -51,6 +57,7 @@ type Resolver struct { group singleflight.Group lruCache *cache.LruCache[string, *D.Msg] policy *trie.DomainTrie[*Policy] + domainSetPolicy []domainSetPolicyRecord geositePolicy []geositePolicyRecord proxyServer []dnsClient } @@ -301,6 +308,12 @@ func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient { return geositeRecord.policy.GetData() } } + metadata := &C.Metadata{Host: domain} + for _, domainSetRecord := range r.domainSetPolicy { + if ok := domainSetRecord.domainSetProvider.Match(metadata); ok { + return domainSetRecord.policy.GetData() + } + } return nil } @@ -422,16 +435,18 @@ type FallbackFilter struct { } type Config struct { - Main, Fallback []NameServer - Default []NameServer - ProxyServer []NameServer - IPv6 bool - IPv6Timeout uint - EnhancedMode C.DNSMode - FallbackFilter FallbackFilter - Pool *fakeip.Pool - Hosts *trie.DomainTrie[resolver.HostValue] - Policy map[string][]NameServer + Main, Fallback []NameServer + Default []NameServer + ProxyServer []NameServer + IPv6 bool + IPv6Timeout uint + EnhancedMode C.DNSMode + FallbackFilter FallbackFilter + Pool *fakeip.Pool + Hosts *trie.DomainTrie[resolver.HostValue] + Policy map[string][]NameServer + DomainSetPolicy map[provider.RuleProvider][]NameServer + GeositePolicy map[router.DomainMatcher][]NameServer } func NewResolver(config Config) *Resolver { @@ -483,6 +498,14 @@ func NewResolver(config Config) *Resolver { } r.policy.Optimize() } + if len(config.DomainSetPolicy) > 0 { + for p, n := range config.DomainSetPolicy { + r.domainSetPolicy = append(r.domainSetPolicy, domainSetPolicyRecord{ + domainSetProvider: p, + policy: NewPolicy(transform(n, defaultResolver)), + }) + } + } fallbackIPFilters := []fallbackIPFilter{} if config.FallbackFilter.GeoIP { diff --git a/docs/config.yaml b/docs/config.yaml index 3ef09342..c2acc1d4 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -238,6 +238,7 @@ dns: - https://doh.pub/dns-query - https://dns.alidns.com/dns-query "www.baidu.com,+.google.cn": [223.5.5.5, https://dns.alidns.com/dns-query] + # "rule-set:global,dns": 8.8.8.8 # global,dns 为 rule-providers 中的名为 global 和 dns 的规则提供器名字,且 behavior 必须为 domain proxies: # socks5 - name: "socks" diff --git a/go.mod b/go.mod index c8eb6e10..a5e6220e 100644 --- a/go.mod +++ b/go.mod @@ -51,6 +51,11 @@ require ( lukechampine.com/blake3 v1.1.7 ) +require ( + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect +) + require ( github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect @@ -67,6 +72,7 @@ require ( github.com/mdlayher/socket v0.4.0 // indirect github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect + github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.10.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect diff --git a/go.sum b/go.sum index f56aed7a..fe7a51f4 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,7 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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= @@ -34,6 +35,7 @@ github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1 github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= 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= @@ -75,6 +77,8 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 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/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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= @@ -105,13 +109,21 @@ github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c= github.com/miekg/dns v1.1.52/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= 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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= 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/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= +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/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= @@ -148,6 +160,7 @@ github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9 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= @@ -243,7 +256,8 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 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= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 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= diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 1b2ec572..8ca844d2 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -5,6 +5,7 @@ import ( "net/netip" "os" "runtime" + "strings" "sync" "github.com/Dreamacro/clash/adapter" @@ -91,7 +92,7 @@ func ApplyConfig(cfg *config.Config, force bool) { updateSniffer(cfg.Sniffer) updateHosts(cfg.Hosts) updateGeneral(cfg.General) - updateDNS(cfg.DNS, cfg.General.IPv6) + updateDNS(cfg.DNS, cfg.RuleProviders, cfg.General.IPv6) updateListeners(cfg.General, cfg.Listeners, force) updateIPTables(cfg) updateTun(cfg.General) @@ -104,7 +105,7 @@ func ApplyConfig(cfg *config.Config, force bool) { loadProxyProvider(cfg.Providers) updateProfile(cfg) loadRuleProvider(cfg.RuleProviders) - + runtime.GC() tunnel.OnRunning() log.SetLevel(cfg.General.LogLevel) @@ -175,10 +176,9 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList } func updateExperimental(c *config.Config) { - runtime.GC() } -func updateDNS(c *config.DNS, generalIPv6 bool) { +func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, generalIPv6 bool) { if !c.Enable { resolver.DefaultResolver = nil resolver.DefaultHostMapper = nil @@ -186,7 +186,25 @@ func updateDNS(c *config.DNS, generalIPv6 bool) { dns.ReCreateServer("", nil, nil) return } - + policy := make(map[string][]dns.NameServer) + domainSetPolicies := make(map[provider.RuleProvider][]dns.NameServer) + for key, nameservers := range c.NameServerPolicy { + temp := strings.Split(key, ":") + if len(temp) == 2 { + prefix := temp[0] + key := temp[1] + switch strings.ToLower(prefix) { + case "rule-set": + if p, ok := ruleProvider[key]; ok { + domainSetPolicies[p] = nameservers + } + case "geosite": + // TODO: + } + } else { + policy[key] = nameservers + } + } cfg := dns.Config{ Main: c.NameServer, Fallback: c.Fallback, @@ -202,9 +220,10 @@ func updateDNS(c *config.DNS, generalIPv6 bool) { Domain: c.FallbackFilter.Domain, GeoSite: c.FallbackFilter.GeoSite, }, - Default: c.DefaultNameserver, - Policy: c.NameServerPolicy, - ProxyServer: c.ProxyServerNameserver, + Default: c.DefaultNameserver, + Policy: c.NameServerPolicy, + ProxyServer: c.ProxyServerNameserver, + DomainSetPolicy: domainSetPolicies, } r := dns.NewResolver(cfg) diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 21dee43c..f2daaf0c 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -110,7 +110,10 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. conn2 = nil }() for { - buff := buf.NewPacket() + // safe size which is 1232 from https://dnsflagday.net/2020/. + // so 2048 is enough + buff := buf.NewSize(2 * 1024) + _ = conn.SetReadDeadline(time.Now().Add(DefaultDnsReadTimeout)) dest, err := conn.ReadPacket(buff) if err != nil { buff.Release() diff --git a/rules/common/domain.go b/rules/common/domain.go index 6b3eba22..35a06a70 100644 --- a/rules/common/domain.go +++ b/rules/common/domain.go @@ -1,7 +1,6 @@ package common import ( - "golang.org/x/net/idna" "strings" C "github.com/Dreamacro/clash/constant" @@ -11,7 +10,6 @@ type Domain struct { *Base domain string adapter string - isIDNA bool } func (d *Domain) RuleType() C.RuleType { @@ -27,20 +25,14 @@ func (d *Domain) Adapter() string { } func (d *Domain) Payload() string { - domain := d.domain - if d.isIDNA { - domain, _ = idna.ToUnicode(domain) - } - return domain + return d.domain } func NewDomain(domain string, adapter string) *Domain { - actualDomain, _ := idna.ToASCII(domain) return &Domain{ Base: &Base{}, - domain: strings.ToLower(actualDomain), + domain: strings.ToLower(domain), adapter: adapter, - isIDNA: actualDomain != domain, } } diff --git a/rules/common/domain_keyword.go b/rules/common/domain_keyword.go index 94d2a949..d945f200 100644 --- a/rules/common/domain_keyword.go +++ b/rules/common/domain_keyword.go @@ -1,7 +1,6 @@ package common import ( - "golang.org/x/net/idna" "strings" C "github.com/Dreamacro/clash/constant" @@ -11,7 +10,6 @@ type DomainKeyword struct { *Base keyword string adapter string - isIDNA bool } func (dk *DomainKeyword) RuleType() C.RuleType { @@ -28,20 +26,14 @@ func (dk *DomainKeyword) Adapter() string { } func (dk *DomainKeyword) Payload() string { - keyword := dk.keyword - if dk.isIDNA { - keyword, _ = idna.ToUnicode(keyword) - } - return keyword + return dk.keyword } func NewDomainKeyword(keyword string, adapter string) *DomainKeyword { - actualDomainKeyword, _ := idna.ToASCII(keyword) return &DomainKeyword{ Base: &Base{}, - keyword: strings.ToLower(actualDomainKeyword), + keyword: strings.ToLower(keyword), adapter: adapter, - isIDNA: keyword != actualDomainKeyword, } } diff --git a/rules/common/domain_suffix.go b/rules/common/domain_suffix.go index 4bdc2e2e..b13036a3 100644 --- a/rules/common/domain_suffix.go +++ b/rules/common/domain_suffix.go @@ -1,7 +1,6 @@ package common import ( - "golang.org/x/net/idna" "strings" C "github.com/Dreamacro/clash/constant" @@ -11,7 +10,6 @@ type DomainSuffix struct { *Base suffix string adapter string - isIDNA bool } func (ds *DomainSuffix) RuleType() C.RuleType { @@ -28,20 +26,14 @@ func (ds *DomainSuffix) Adapter() string { } func (ds *DomainSuffix) Payload() string { - suffix := ds.suffix - if ds.isIDNA { - suffix, _ = idna.ToUnicode(suffix) - } - return suffix + return ds.suffix } func NewDomainSuffix(suffix string, adapter string) *DomainSuffix { - actualDomainSuffix, _ := idna.ToASCII(suffix) return &DomainSuffix{ Base: &Base{}, - suffix: strings.ToLower(actualDomainSuffix), + suffix: strings.ToLower(suffix), adapter: adapter, - isIDNA: suffix != actualDomainSuffix, } } diff --git a/rules/common/network_type.go b/rules/common/network_type.go index fb6b5077..1184ba89 100644 --- a/rules/common/network_type.go +++ b/rules/common/network_type.go @@ -21,10 +21,8 @@ func NewNetworkType(network, adapter string) (*NetworkType, error) { switch strings.ToUpper(network) { case "TCP": ntType.network = C.TCP - break case "UDP": ntType.network = C.UDP - break default: return nil, fmt.Errorf("unsupported network type, only TCP/UDP") } diff --git a/rules/provider/domain_strategy.go b/rules/provider/domain_strategy.go index add64e76..0b2a5d3c 100644 --- a/rules/provider/domain_strategy.go +++ b/rules/provider/domain_strategy.go @@ -3,13 +3,11 @@ package provider import ( "github.com/Dreamacro/clash/component/trie" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "golang.org/x/net/idna" ) type domainStrategy struct { count int - domainRules *trie.DomainTrie[struct{}] + domainRules *trie.DomainSet } func (d *domainStrategy) ShouldFindProcess() bool { @@ -17,7 +15,7 @@ func (d *domainStrategy) ShouldFindProcess() bool { } func (d *domainStrategy) Match(metadata *C.Metadata) bool { - return d.domainRules != nil && d.domainRules.Search(metadata.RuleHost()) != nil + return d.domainRules != nil && d.domainRules.Has(metadata.RuleHost()) } func (d *domainStrategy) Count() int { @@ -29,21 +27,9 @@ func (d *domainStrategy) ShouldResolveIP() bool { } func (d *domainStrategy) OnUpdate(rules []string) { - domainTrie := trie.New[struct{}]() - count := 0 - for _, rule := range rules { - actualDomain, _ := idna.ToASCII(rule) - err := domainTrie.Insert(actualDomain, struct{}{}) - if err != nil { - log.Warnln("invalid domain:[%s]", rule) - } else { - count++ - } - } - domainTrie.Optimize() - + domainTrie := trie.NewDomainSet(rules) d.domainRules = domainTrie - d.count = count + d.count = len(rules) } func NewDomainStrategy() *domainStrategy { diff --git a/transport/hysteria/conns/faketcp/tcp_linux.go b/transport/hysteria/conns/faketcp/tcp_linux.go index dadb0912..cdee9fda 100644 --- a/transport/hysteria/conns/faketcp/tcp_linux.go +++ b/transport/hysteria/conns/faketcp/tcp_linux.go @@ -1,5 +1,5 @@ -//go:build linux -// +build linux +//go:build linux && !no_fake_tcp +// +build linux,!no_fake_tcp package faketcp diff --git a/transport/hysteria/conns/faketcp/tcp_stub.go b/transport/hysteria/conns/faketcp/tcp_stub.go index 9bc55077..9f9ff97d 100644 --- a/transport/hysteria/conns/faketcp/tcp_stub.go +++ b/transport/hysteria/conns/faketcp/tcp_stub.go @@ -1,5 +1,5 @@ -//go:build !linux -// +build !linux +//go:build !linux || no_fake_tcp +// +build !linux no_fake_tcp package faketcp From 54cad53f5f5480794130ceb7efcc180085d3814e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 1 Apr 2023 12:15:03 +0800 Subject: [PATCH 151/530] chore: DomainSet now build from a DomainTrie --- component/trie/{sskv.go => domain_set.go} | 16 ++++------ .../trie/{set_test.go => domain_set_test.go} | 31 ++++++++++++++----- component/trie/domain_test.go | 29 ++++++++--------- config/config.go | 21 +++++++++++-- rules/provider/domain_strategy.go | 11 +++++-- 5 files changed, 72 insertions(+), 36 deletions(-) rename component/trie/{sskv.go => domain_set.go} (91%) rename component/trie/{set_test.go => domain_set_test.go} (62%) diff --git a/component/trie/sskv.go b/component/trie/domain_set.go similarity index 91% rename from component/trie/sskv.go rename to component/trie/domain_set.go index 6a661a85..ce416e16 100644 --- a/component/trie/sskv.go +++ b/component/trie/domain_set.go @@ -23,20 +23,16 @@ type DomainSet struct { ranks, selects []int32 } -// NewDomainSet creates a new *DomainSet struct, from a slice of sorted strings. -func NewDomainSet(keys []string) *DomainSet { - domainTrie := New[struct{}]() - for _, domain := range keys { - domainTrie.Insert(domain, struct{}{}) - } - reserveDomains := make([]string, 0, len(keys)) - domainTrie.Foreach(func(domain string, data struct{}) { +// NewDomainSet creates a new *DomainSet struct, from a DomainTrie. +func (t *DomainTrie[T]) NewDomainSet() *DomainSet { + reserveDomains := make([]string, 0) + t.Foreach(func(domain string, data T) { reserveDomains = append(reserveDomains, utils.Reverse(domain)) }) // ensure that the same prefix is continuous // and according to the ascending sequence of length sort.Strings(reserveDomains) - keys = reserveDomains + keys := reserveDomains if len(keys) == 0 { return nil } @@ -104,7 +100,7 @@ func (ss *DomainSet) Has(key string) bool { if j == len(key) { if getBit(ss.leaves, nextNodeId) != 0 { return true - }else { + } else { goto RESTART } } diff --git a/component/trie/set_test.go b/component/trie/domain_set_test.go similarity index 62% rename from component/trie/set_test.go rename to component/trie/domain_set_test.go index 346bb31a..090bd495 100644 --- a/component/trie/set_test.go +++ b/component/trie/domain_set_test.go @@ -7,7 +7,8 @@ import ( "github.com/stretchr/testify/assert" ) -func TestDomain(t *testing.T) { +func TestDomainSet(t *testing.T) { + tree := trie.New[struct{}]() domainSet := []string{ "baidu.com", "google.com", @@ -15,14 +16,19 @@ func TestDomain(t *testing.T) { "test.a.net", "test.a.oc", } - set := trie.NewDomainSet(domainSet) + + for _, domain := range domainSet { + assert.NoError(t, tree.Insert(domain, struct{}{})) + } + set := tree.NewDomainSet() assert.NotNil(t, set) assert.True(t, set.Has("test.a.net")) assert.True(t, set.Has("google.com")) assert.False(t, set.Has("www.baidu.com")) } -func TestDomainComplexWildcard(t *testing.T) { +func TestDomainSetComplexWildcard(t *testing.T) { + tree := trie.New[struct{}]() domainSet := []string{ "+.baidu.com", "+.a.baidu.com", @@ -32,14 +38,19 @@ func TestDomainComplexWildcard(t *testing.T) { "test.a.oc", "www.qq.com", } - set := trie.NewDomainSet(domainSet) + + for _, domain := range domainSet { + assert.NoError(t, tree.Insert(domain, struct{}{})) + } + set := tree.NewDomainSet() assert.NotNil(t, set) assert.False(t, set.Has("google.com")) assert.True(t, set.Has("www.baidu.com")) assert.True(t, set.Has("test.test.baidu.com")) } -func TestDomainWildcard(t *testing.T) { +func TestDomainSetWildcard(t *testing.T) { + tree := trie.New[struct{}]() domainSet := []string{ "*.*.*.baidu.com", "www.baidu.*", @@ -47,14 +58,18 @@ func TestDomainWildcard(t *testing.T) { "*.*.qq.com", "test.*.baidu.com", } - set := trie.NewDomainSet(domainSet) + + for _, domain := range domainSet { + assert.NoError(t, tree.Insert(domain, struct{}{})) + } + set := tree.NewDomainSet() assert.NotNil(t, set) assert.True(t, set.Has("www.baidu.com")) assert.True(t, set.Has("test.test.baidu.com")) assert.True(t, set.Has("test.test.qq.com")) - assert.True(t,set.Has("stun.ab.cd")) + assert.True(t, set.Has("stun.ab.cd")) assert.False(t, set.Has("test.baidu.com")) - assert.False(t,set.Has("www.google.com")) + assert.False(t, set.Has("www.google.com")) assert.False(t, set.Has("test.qq.com")) assert.False(t, set.Has("test.test.test.qq.com")) } diff --git a/component/trie/domain_test.go b/component/trie/domain_test.go index 2dfd1c34..976055a9 100644 --- a/component/trie/domain_test.go +++ b/component/trie/domain_test.go @@ -1,16 +1,17 @@ -package trie +package trie_test import ( "net/netip" "testing" + "github.com/Dreamacro/clash/component/trie" "github.com/stretchr/testify/assert" ) var localIP = netip.AddrFrom4([4]byte{127, 0, 0, 1}) func TestTrie_Basic(t *testing.T) { - tree := New[netip.Addr]() + tree := trie.New[netip.Addr]() domains := []string{ "example.com", "google.com", @@ -18,7 +19,7 @@ func TestTrie_Basic(t *testing.T) { } for _, domain := range domains { - tree.Insert(domain, localIP) + assert.NoError(t, tree.Insert(domain, localIP)) } node := tree.Search("example.com") @@ -31,7 +32,7 @@ func TestTrie_Basic(t *testing.T) { } func TestTrie_Wildcard(t *testing.T) { - tree := New[netip.Addr]() + tree := trie.New[netip.Addr]() domains := []string{ "*.example.com", "sub.*.example.com", @@ -47,7 +48,7 @@ func TestTrie_Wildcard(t *testing.T) { } for _, domain := range domains { - tree.Insert(domain, localIP) + assert.NoError(t, tree.Insert(domain, localIP)) } assert.NotNil(t, tree.Search("sub.example.com")) @@ -64,7 +65,7 @@ func TestTrie_Wildcard(t *testing.T) { } func TestTrie_Priority(t *testing.T) { - tree := New[int]() + tree := trie.New[int]() domains := []string{ ".dev", "example.dev", @@ -79,7 +80,7 @@ func TestTrie_Priority(t *testing.T) { } for idx, domain := range domains { - tree.Insert(domain, idx+1) + assert.NoError(t, tree.Insert(domain, idx+1)) } assertFn("test.dev", 1) @@ -90,8 +91,8 @@ func TestTrie_Priority(t *testing.T) { } func TestTrie_Boundary(t *testing.T) { - tree := New[netip.Addr]() - tree.Insert("*.dev", localIP) + tree := trie.New[netip.Addr]() + assert.NoError(t, tree.Insert("*.dev", localIP)) assert.NotNil(t, tree.Insert(".", localIP)) assert.NotNil(t, tree.Insert("..dev", localIP)) @@ -99,15 +100,15 @@ func TestTrie_Boundary(t *testing.T) { } func TestTrie_WildcardBoundary(t *testing.T) { - tree := New[netip.Addr]() - tree.Insert("+.*", localIP) - tree.Insert("stun.*.*.*", localIP) + tree := trie.New[netip.Addr]() + assert.NoError(t, tree.Insert("+.*", localIP)) + assert.NoError(t, tree.Insert("stun.*.*.*", localIP)) assert.NotNil(t, tree.Search("example.com")) } func TestTrie_Foreach(t *testing.T) { - tree := New[netip.Addr]() + tree := trie.New[netip.Addr]() domainList := []string{ "google.com", "stun.*.*.*", @@ -117,7 +118,7 @@ func TestTrie_Foreach(t *testing.T) { "*.*.baidu.com", } for _, domain := range domainList { - tree.Insert(domain, localIP) + assert.NoError(t, tree.Insert(domain, localIP)) } count := 0 tree.Foreach(func(domain string, data netip.Addr) { diff --git a/config/config.go b/config/config.go index d2378822..e7720c40 100644 --- a/config/config.go +++ b/config/config.go @@ -1340,8 +1340,25 @@ func parseSniffer(snifferRaw RawSniffer) (*Sniffer, error) { } sniffer.Sniffers = loadSniffer - sniffer.ForceDomain = trie.NewDomainSet(snifferRaw.ForceDomain) - sniffer.SkipDomain = trie.NewDomainSet(snifferRaw.SkipDomain) + + forceDomainTrie := trie.New[struct{}]() + for _, domain := range snifferRaw.ForceDomain { + err := forceDomainTrie.Insert(domain, struct{}{}) + if err != nil { + return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err) + } + } + sniffer.ForceDomain = forceDomainTrie.NewDomainSet() + + skipDomainTrie := trie.New[struct{}]() + for _, domain := range snifferRaw.SkipDomain { + err := skipDomainTrie.Insert(domain, struct{}{}) + if err != nil { + return nil, fmt.Errorf("error domian[%s] in force-domain, error:%v", domain, err) + } + } + sniffer.SkipDomain = skipDomainTrie.NewDomainSet() + return sniffer, nil } diff --git a/rules/provider/domain_strategy.go b/rules/provider/domain_strategy.go index 0b2a5d3c..a2cb795d 100644 --- a/rules/provider/domain_strategy.go +++ b/rules/provider/domain_strategy.go @@ -3,6 +3,7 @@ package provider import ( "github.com/Dreamacro/clash/component/trie" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" ) type domainStrategy struct { @@ -27,8 +28,14 @@ func (d *domainStrategy) ShouldResolveIP() bool { } func (d *domainStrategy) OnUpdate(rules []string) { - domainTrie := trie.NewDomainSet(rules) - d.domainRules = domainTrie + domainTrie := trie.New[struct{}]() + for _, rule := range rules { + err := domainTrie.Insert(rule, struct{}{}) + if err != nil { + log.Warnln("invalid domain:[%s]", rule) + } + } + d.domainRules = domainTrie.NewDomainSet() d.count = len(rules) } From 54c2fa98b47d199ca83c3708b90197a6b006eb58 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 1 Apr 2023 14:11:09 +0800 Subject: [PATCH 152/530] chore: rule-provider now read yaml line-by-line --- rules/provider/classical_strategy.go | 48 +++++++------ rules/provider/domain_strategy.go | 33 +++++---- rules/provider/ipcidr_strategy.go | 31 ++++---- rules/provider/provider.go | 102 ++++++++++++++++++++++----- 4 files changed, 148 insertions(+), 66 deletions(-) diff --git a/rules/provider/classical_strategy.go b/rules/provider/classical_strategy.go index 25360ec7..e187e213 100644 --- a/rules/provider/classical_strategy.go +++ b/rules/provider/classical_strategy.go @@ -37,36 +37,38 @@ func (c *classicalStrategy) ShouldFindProcess() bool { return c.shouldFindProcess } -func (c *classicalStrategy) OnUpdate(rules []string) { - var classicalRules []C.Rule - shouldResolveIP := false - for _, rawRule := range rules { - ruleType, rule, params := ruleParse(rawRule) +func (c *classicalStrategy) Reset() { + c.rules = nil + c.count = 0 + c.shouldFindProcess = false + c.shouldResolveIP = false +} - if ruleType == "PROCESS-NAME" { +func (c *classicalStrategy) Insert(rule string) { + ruleType, rule, params := ruleParse(rule) + + if ruleType == "PROCESS-NAME" { + c.shouldFindProcess = true + } + + r, err := c.parse(ruleType, rule, "", params) + if err != nil { + log.Warnln("parse rule error:[%s]", err.Error()) + } else { + if r.ShouldResolveIP() { + c.shouldResolveIP = true + } + if r.ShouldFindProcess() { c.shouldFindProcess = true } - r, err := c.parse(ruleType, rule, "", params) - if err != nil { - log.Warnln("parse rule error:[%s]", err.Error()) - } else { - if !shouldResolveIP { - shouldResolveIP = r.ShouldResolveIP() - } - - if !c.shouldFindProcess { - c.shouldFindProcess = r.ShouldFindProcess() - } - - classicalRules = append(classicalRules, r) - } + c.rules = append(c.rules, r) + c.count++ } - - c.rules = classicalRules - c.count = len(classicalRules) } +func (c *classicalStrategy) FinishInsert() {} + func ruleParse(ruleRaw string) (string, string, []string) { item := strings.Split(ruleRaw, ",") if len(item) == 1 { diff --git a/rules/provider/domain_strategy.go b/rules/provider/domain_strategy.go index a2cb795d..d686d598 100644 --- a/rules/provider/domain_strategy.go +++ b/rules/provider/domain_strategy.go @@ -7,8 +7,9 @@ import ( ) type domainStrategy struct { - count int - domainRules *trie.DomainSet + count int + domainTrie *trie.DomainTrie[struct{}] + domainSet *trie.DomainSet } func (d *domainStrategy) ShouldFindProcess() bool { @@ -16,7 +17,7 @@ func (d *domainStrategy) ShouldFindProcess() bool { } func (d *domainStrategy) Match(metadata *C.Metadata) bool { - return d.domainRules != nil && d.domainRules.Has(metadata.RuleHost()) + return d.domainSet != nil && d.domainSet.Has(metadata.RuleHost()) } func (d *domainStrategy) Count() int { @@ -27,16 +28,24 @@ func (d *domainStrategy) ShouldResolveIP() bool { return false } -func (d *domainStrategy) OnUpdate(rules []string) { - domainTrie := trie.New[struct{}]() - for _, rule := range rules { - err := domainTrie.Insert(rule, struct{}{}) - if err != nil { - log.Warnln("invalid domain:[%s]", rule) - } +func (d *domainStrategy) Reset() { + d.domainTrie = trie.New[struct{}]() + d.domainSet = nil + d.count = 0 +} + +func (d *domainStrategy) Insert(rule string) { + err := d.domainTrie.Insert(rule, struct{}{}) + if err != nil { + log.Warnln("invalid domain:[%s]", rule) + } else { + d.count++ } - d.domainRules = domainTrie.NewDomainSet() - d.count = len(rules) +} + +func (d *domainStrategy) FinishInsert() { + d.domainSet = d.domainTrie.NewDomainSet() + d.domainTrie = nil } func NewDomainStrategy() *domainStrategy { diff --git a/rules/provider/ipcidr_strategy.go b/rules/provider/ipcidr_strategy.go index 88228301..f54302f1 100644 --- a/rules/provider/ipcidr_strategy.go +++ b/rules/provider/ipcidr_strategy.go @@ -28,23 +28,24 @@ func (i *ipcidrStrategy) ShouldResolveIP() bool { return i.shouldResolveIP } -func (i *ipcidrStrategy) OnUpdate(rules []string) { - ipCidrTrie := trie.NewIpCidrTrie() - count := 0 - for _, rule := range rules { - err := ipCidrTrie.AddIpCidrForString(rule) - if err != nil { - log.Warnln("invalid Ipcidr:[%s]", rule) - } else { - count++ - } - } - - i.trie = ipCidrTrie - i.count = count - i.shouldResolveIP = i.count > 0 +func (i *ipcidrStrategy) Reset() { + i.trie = trie.NewIpCidrTrie() + i.count = 0 + i.shouldResolveIP = false } +func (i *ipcidrStrategy) Insert(rule string) { + err := i.trie.AddIpCidrForString(rule) + if err != nil { + log.Warnln("invalid Ipcidr:[%s]", rule) + } else { + i.shouldResolveIP = true + i.count++ + } +} + +func (i *ipcidrStrategy) FinishInsert() {} + func NewIPCidrStrategy() *ipcidrStrategy { return &ipcidrStrategy{} } diff --git a/rules/provider/provider.go b/rules/provider/provider.go index 175917c2..c46861e1 100644 --- a/rules/provider/provider.go +++ b/rules/provider/provider.go @@ -1,13 +1,19 @@ package provider import ( + "bufio" + "bytes" "encoding/json" + "errors" + "gopkg.in/yaml.v3" + "io" + "runtime" + "time" + + "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/component/resource" C "github.com/Dreamacro/clash/constant" P "github.com/Dreamacro/clash/constant/provider" - "gopkg.in/yaml.v3" - "runtime" - "time" ) var ( @@ -29,8 +35,8 @@ type RulePayload struct { key: Domain or IP Cidr value: Rule type or is empty */ - Rules []string `yaml:"payload"` - Rules2 []string `yaml:"rules"` + Payload []string `yaml:"payload"` + Rules []string `yaml:"rules"` } type ruleStrategy interface { @@ -38,7 +44,9 @@ type ruleStrategy interface { Count() int ShouldResolveIP() bool ShouldFindProcess() bool - OnUpdate(rules []string) + Reset() + Insert(rule string) + FinishInsert() } func RuleProviders() map[string]P.RuleProvider { @@ -114,13 +122,12 @@ func NewRuleSetProvider(name string, behavior P.RuleType, interval time.Duration } onUpdate := func(elm interface{}) { - rulesRaw := elm.([]string) - rp.strategy.OnUpdate(rulesRaw) + strategy := elm.(ruleStrategy) + rp.strategy = strategy } - fetcher := resource.NewFetcher(name, interval, vehicle, rulesParse, onUpdate) - rp.Fetcher = fetcher rp.strategy = newStrategy(behavior, parse) + rp.Fetcher = resource.NewFetcher(name, interval, vehicle, func(bytes []byte) (any, error) { return rulesParse(bytes, newStrategy(behavior, parse)) }, onUpdate) wrapper := &RuleSetProvider{ rp, @@ -147,12 +154,75 @@ func newStrategy(behavior P.RuleType, parse func(tp, payload, target string, par } } -func rulesParse(buf []byte) (any, error) { - rulePayload := RulePayload{} - err := yaml.Unmarshal(buf, &rulePayload) - if err != nil { - return nil, err +var ErrNoPayload = errors.New("file must have a `payload` field") + +func rulesParse(buf []byte, strategy ruleStrategy) (any, error) { + strategy.Reset() + + schema := &RulePayload{} + + reader := bufio.NewReader(bytes.NewReader(buf)) + + firstLineBuffer := pool.GetBuffer() + defer pool.PutBuffer(firstLineBuffer) + firstLineLength := 0 + + for { + line, isPrefix, err := reader.ReadLine() + if err != nil { + if err == io.EOF { + if firstLineLength == 0 { // find payload head + return nil, ErrNoPayload + } + break + } + return nil, err + } + firstLineBuffer.Write(line) // need a copy because the returned buffer is only valid until the next call to ReadLine + if isPrefix { + // If the line was too long for the buffer then isPrefix is set and the + // beginning of the line is returned. The rest of the line will be returned + // from future calls. + continue + } + if firstLineLength == 0 { // find payload head + firstLineBuffer.WriteByte('\n') + firstLineLength = firstLineBuffer.Len() + firstLineBuffer.WriteString(" - ''") // a test line + + err = yaml.Unmarshal(firstLineBuffer.Bytes(), schema) + firstLineBuffer.Truncate(firstLineLength) + if err == nil && (len(schema.Rules) > 0 || len(schema.Payload) > 0) { // found + continue + } + + // not found or err!=nil + firstLineBuffer.Truncate(0) + firstLineLength = 0 + continue + } + + // parse payload body + err = yaml.Unmarshal(firstLineBuffer.Bytes(), schema) + firstLineBuffer.Truncate(firstLineLength) + if err != nil { + continue + } + var str string + if len(schema.Rules) > 0 { + str = schema.Rules[0] + } + if len(schema.Payload) > 0 { + str = schema.Payload[0] + } + if str == "" { + continue + } + + strategy.Insert(str) } - return append(rulePayload.Rules, rulePayload.Rules2...), nil + strategy.FinishInsert() + + return strategy, nil } From 9d7a78e1ef301d8faaa37b05838126309903ee73 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 1 Apr 2023 14:32:34 +0800 Subject: [PATCH 153/530] chore: update use compatible version for windows/linux amd64 --- hub/updater/updater.go | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 077818fd..b428ca9c 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -67,7 +67,7 @@ func Update() (err error) { return err } - log.Infoln("current version alpha-%s, latest version alpha-%s", constant.Version, latestVersion) + log.Infoln("current version %s, latest version %s", constant.Version, latestVersion) if latestVersion == constant.Version { err := &updateError{Message: "Already using latest version"} @@ -134,8 +134,10 @@ func prepare(exePath string) (err error) { //log.Infoln(packageName) backupDir = filepath.Join(workDir, "meta-backup") - if goos == "windows" { - updateExeName = "clash.meta" + "-" + goos + "-" + goarch + ".exe" + if goos == "windows" && goarch == "amd64" { + updateExeName = "clash.meta" + "-" + goos + "-" + goarch + "-compatible.exe" + } else if goos == "linux" && goarch == "amd64" { + updateExeName = "clash.meta" + "-" + goos + "-" + goarch + "-compatible" } else { updateExeName = "clash.meta" + "-" + goos + "-" + goarch } @@ -164,7 +166,7 @@ func unpack() error { var err error _, pkgNameOnly := filepath.Split(packageURL) - log.Debugln("updater: unpacking package") + log.Infoln("updater: unpacking package") if strings.HasSuffix(pkgNameOnly, ".zip") { _, err = zipFileUnpack(packageName, updateDir) if err != nil { @@ -184,15 +186,14 @@ func unpack() error { return nil } -// backup makes a backup of the current configuration and supporting files. It -// ignores the configuration file if firstRun is true. +// backup makes a backup of the current configuration and supporting files. func backup() (err error) { - log.Infoln("updater: backing up current Exefile") + log.Infoln("updater: backing up current ExecFile:%s", currentExeName) _ = os.Mkdir(backupDir, 0o755) - err = copyFile(currentExeName, backupExeName) + err = os.Rename(currentExeName, backupExeName) if err != nil { - return fmt.Errorf("copySupportingFiles(%s, %s) failed: %w", currentExeName, backupExeName, err) + return err } return nil @@ -203,24 +204,17 @@ func backup() (err error) { func replace() error { var err error - // log.Infoln("updater: renaming: %s to %s", currentExeName, backupExeName) - // err := os.Rename(currentExeName, backupExeName) - // if err != nil { - // return err - // } - + log.Infoln("copying: %s to %s", updateExeName, currentExeName) if goos == "windows" { // rename fails with "File in use" error - log.Infoln("copying: %s to %s", updateExeName, currentExeName) err = copyFile(updateExeName, currentExeName) } else { - log.Infoln("copying: %s to %s", updateExeName, currentExeName) err = os.Rename(updateExeName, currentExeName) } if err != nil { return err } - + log.Infoln("updater: renamed: %s to %s", updateExeName, currentExeName) return nil } @@ -236,8 +230,6 @@ const MaxPackageFileSize = 32 * 1024 * 1024 // Download package file and save it to disk func downloadPackageFile() (err error) { - // var resp *http.Response - // resp, err = client.Get(packageURL) ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() resp, err := clashHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) @@ -447,6 +439,8 @@ func updateDownloadURL() { middle = fmt.Sprintf("-%s-%sv%s-%s", goos, goarch, goarm, latestVersion) } else if isMIPS(goarch) && gomips != "" { middle = fmt.Sprintf("-%s-%s-%s-%s", goos, goarch, gomips, latestVersion) + } else if goarch == "amd64" && (goos == "windows" || goos == "linux") { + middle = fmt.Sprintf("-%s-%s-compatible-%s", goos, goarch, latestVersion) } else { middle = fmt.Sprintf("-%s-%s-%s", goos, goarch, latestVersion) } From 9442880a5af379ba3067a6ff0e40ddf87a082cd9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 1 Apr 2023 16:55:02 +0800 Subject: [PATCH 154/530] chore: rule-provider direct using IndexByte in bytes for find new line --- rules/provider/provider.go | 38 +++++++++++++++----------------------- 1 file changed, 15 insertions(+), 23 deletions(-) diff --git a/rules/provider/provider.go b/rules/provider/provider.go index c46861e1..6b3c0290 100644 --- a/rules/provider/provider.go +++ b/rules/provider/provider.go @@ -1,12 +1,10 @@ package provider import ( - "bufio" "bytes" "encoding/json" "errors" "gopkg.in/yaml.v3" - "io" "runtime" "time" @@ -161,36 +159,30 @@ func rulesParse(buf []byte, strategy ruleStrategy) (any, error) { schema := &RulePayload{} - reader := bufio.NewReader(bytes.NewReader(buf)) - firstLineBuffer := pool.GetBuffer() defer pool.PutBuffer(firstLineBuffer) firstLineLength := 0 - for { - line, isPrefix, err := reader.ReadLine() - if err != nil { - if err == io.EOF { - if firstLineLength == 0 { // find payload head - return nil, ErrNoPayload - } - break + s := 0 // search start index + for s < len(buf) { + // search buffer for a new line. + line := buf[s:] + if i := bytes.IndexByte(line, '\n'); i >= 0 { + i += s + line = buf[s : i+1] + s = i + 1 + } else { + s = len(buf) // stop loop in next step + if firstLineLength == 0 { // no head or only one line body + return nil, ErrNoPayload } - return nil, err - } - firstLineBuffer.Write(line) // need a copy because the returned buffer is only valid until the next call to ReadLine - if isPrefix { - // If the line was too long for the buffer then isPrefix is set and the - // beginning of the line is returned. The rest of the line will be returned - // from future calls. - continue } + firstLineBuffer.Write(line) if firstLineLength == 0 { // find payload head - firstLineBuffer.WriteByte('\n') firstLineLength = firstLineBuffer.Len() firstLineBuffer.WriteString(" - ''") // a test line - err = yaml.Unmarshal(firstLineBuffer.Bytes(), schema) + err := yaml.Unmarshal(firstLineBuffer.Bytes(), schema) firstLineBuffer.Truncate(firstLineLength) if err == nil && (len(schema.Rules) > 0 || len(schema.Payload) > 0) { // found continue @@ -203,7 +195,7 @@ func rulesParse(buf []byte, strategy ruleStrategy) (any, error) { } // parse payload body - err = yaml.Unmarshal(firstLineBuffer.Bytes(), schema) + err := yaml.Unmarshal(firstLineBuffer.Bytes(), schema) firstLineBuffer.Truncate(firstLineLength) if err != nil { continue From 4af4935e7edebed6a8f799643d734fa81909e10f Mon Sep 17 00:00:00 2001 From: Hellojack <106379370+h1jk@users.noreply.github.com> Date: Sat, 1 Apr 2023 20:08:49 +0800 Subject: [PATCH 155/530] fix: Vision slice out of bounds error --- transport/vless/filter.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/transport/vless/filter.go b/transport/vless/filter.go index 3ddfb8b9..f577be7a 100644 --- a/transport/vless/filter.go +++ b/transport/vless/filter.go @@ -34,7 +34,7 @@ func (vc *Conn) FilterTLS(buffer []byte) (index int) { lenP := len(buffer) vc.packetsToFilter-- if index = bytes.Index(buffer, tlsServerHandshakeStart); index != -1 { - if lenP >= index+5 { + if lenP > index+5 { if buffer[0] == 22 && buffer[1] == 3 && buffer[2] == 3 { vc.isTLS = true if buffer[5] == tlsHandshakeTypeServerHello { @@ -49,7 +49,7 @@ func (vc *Conn) FilterTLS(buffer []byte) (index int) { } } } else if index = bytes.Index(buffer, tlsClientHandshakeStart); index != -1 { - if lenP >= index+5 && buffer[index+5] == tlsHandshakeTypeClientHello { + if lenP > index+5 && buffer[index+5] == tlsHandshakeTypeClientHello { vc.isTLS = true } } From cd95cf48493074e1ed4219f19af16d6c5b9498c4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 1 Apr 2023 20:56:49 +0800 Subject: [PATCH 156/530] fix: firstWriteCallBackConn can pass N.ExtendedConn too --- adapter/outboundgroup/fallback.go | 17 ++++---- adapter/outboundgroup/loadbalance.go | 17 ++++---- adapter/outboundgroup/urltest.go | 17 ++++---- common/callback/callback.go | 62 +++++++++++++++++++++++++--- 4 files changed, 78 insertions(+), 35 deletions(-) diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index d1d5e6b3..02ba0ac6 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -37,16 +37,13 @@ func (f *Fallback) DialContext(ctx context.Context, metadata *C.Metadata, opts . } if N.NeedHandshake(c) { - c = &callback.FirstWriteCallBackConn{ - Conn: c, - Callback: func(err error) { - if err == nil { - f.onDialSuccess() - } else { - f.onDialFailed(proxy.Type(), err) - } - }, - } + c = callback.NewFirstWriteCallBackConn(c, func(err error) { + if err == nil { + f.onDialSuccess() + } else { + f.onDialFailed(proxy.Type(), err) + } + }) } return c, err diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 1ed80496..15e17a13 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -95,16 +95,13 @@ func (lb *LoadBalance) DialContext(ctx context.Context, metadata *C.Metadata, op } if N.NeedHandshake(c) { - c = &callback.FirstWriteCallBackConn{ - Conn: c, - Callback: func(err error) { - if err == nil { - lb.onDialSuccess() - } else { - lb.onDialFailed(proxy.Type(), err) - } - }, - } + c = callback.NewFirstWriteCallBackConn(c, func(err error) { + if err == nil { + lb.onDialSuccess() + } else { + lb.onDialFailed(proxy.Type(), err) + } + }) } return diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index d340539c..64ce17f6 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -45,16 +45,13 @@ func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts .. } if N.NeedHandshake(c) { - c = &callback.FirstWriteCallBackConn{ - Conn: c, - Callback: func(err error) { - if err == nil { - u.onDialSuccess() - } else { - u.onDialFailed(proxy.Type(), err) - } - }, - } + c = callback.NewFirstWriteCallBackConn(c, func(err error) { + if err == nil { + u.onDialSuccess() + } else { + u.onDialFailed(proxy.Type(), err) + } + }) } return c, err diff --git a/common/callback/callback.go b/common/callback/callback.go index a0f1e717..9d64bb92 100644 --- a/common/callback/callback.go +++ b/common/callback/callback.go @@ -1,25 +1,77 @@ package callback import ( + "github.com/Dreamacro/clash/common/buf" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" ) -type FirstWriteCallBackConn struct { +type firstWriteCallBackConn struct { C.Conn - Callback func(error) + callback func(error) written bool } -func (c *FirstWriteCallBackConn) Write(b []byte) (n int, err error) { +func (c *firstWriteCallBackConn) Write(b []byte) (n int, err error) { defer func() { if !c.written { c.written = true - c.Callback(err) + c.callback(err) } }() return c.Conn.Write(b) } -func (c *FirstWriteCallBackConn) Upstream() any { +func (c *firstWriteCallBackConn) Upstream() any { return c.Conn } + +type extendedConn interface { + C.Conn + N.ExtendedConn +} + +type firstWriteCallBackExtendedConn struct { + extendedConn + callback func(error) + written bool +} + +func (c *firstWriteCallBackExtendedConn) Write(b []byte) (n int, err error) { + defer func() { + if !c.written { + c.written = true + c.callback(err) + } + }() + return c.extendedConn.Write(b) +} + +func (c *firstWriteCallBackExtendedConn) WriteBuffer(buffer *buf.Buffer) (err error) { + defer func() { + if !c.written { + c.written = true + c.callback(err) + } + }() + return c.extendedConn.WriteBuffer(buffer) +} + +func (c *firstWriteCallBackExtendedConn) Upstream() any { + return c.extendedConn +} + +func NewFirstWriteCallBackConn(c C.Conn, callback func(error)) C.Conn { + if c, ok := c.(extendedConn); ok { + return &firstWriteCallBackExtendedConn{ + extendedConn: c, + callback: callback, + written: false, + } + } + return &firstWriteCallBackConn{ + Conn: c, + callback: callback, + written: false, + } +} From 526ac3906dab9744122668c1fbdffdf09f0e3a9c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 2 Apr 2023 13:15:41 +0800 Subject: [PATCH 157/530] chore: Update dependencies --- go.mod | 31 +++++++++++++------- go.sum | 93 ++++++++++++++++++++++++---------------------------------- 2 files changed, 59 insertions(+), 65 deletions(-) diff --git a/go.mod b/go.mod index a5e6220e..7b33fcb5 100644 --- a/go.mod +++ b/go.mod @@ -15,19 +15,19 @@ 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-20221215072855-de60144f33f8 + github.com/insomniacslk/dhcp v0.0.0-20230307103557-e252950ab961 github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 - github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947 - github.com/metacubex/sing-tun v0.1.3-0.20230323115055-7935ba0ac8b3 + github.com/metacubex/sing-shadowsocks v0.2.1 + github.com/metacubex/sing-tun v0.1.3 github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb github.com/miekg/dns v1.1.52 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.1-0.20230323071235-f8038854d286 + github.com/sagernet/sing v0.2.1 github.com/sagernet/sing-shadowtls v0.1.0 github.com/sagernet/sing-vmess v0.1.3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 @@ -40,7 +40,7 @@ require ( github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.6 go.uber.org/atomic v1.10.0 - go.uber.org/automaxprocs v1.5.1 + go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.7.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 golang.org/x/net v0.8.0 @@ -52,14 +52,15 @@ require ( ) require ( - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect -) - -require ( + github.com/RyuaNerin/go-krypto v1.0.2 // indirect + github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 // indirect github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/ericlagergren/aegis v0.0.0-20230312195928-b4ce538b56f9 // indirect + github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect + github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect + github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect github.com/golang/mock v1.6.0 // indirect @@ -71,20 +72,28 @@ require ( github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/mdlayher/socket v0.4.0 // indirect github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 // indirect + github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // 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 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 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/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect - github.com/u-root/uio v0.0.0-20221213070652-c3537552635f // 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/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // 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.8.0 // indirect golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.org/x/tools v0.6.0 // indirect + gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect ) replace go.uber.org/atomic v1.10.0 => github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 diff --git a/go.sum b/go.sum index fe7a51f4..7c60b4bf 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ github.com/3andne/restls-client-go v0.1.4 h1:kLNC2aSRHPlEVYmTj6EOqJoorCpobEe2toMRSfBF7FU= github.com/3andne/restls-client-go v0.1.4/go.mod h1:04CGbRk1BwBiEDles8b5mlKgTqIwE5MqF7JDloJV47I= +github.com/RyuaNerin/go-krypto v1.0.2 h1:9KiZrrBs+tDrQ66dNy4nrX6SzntKtSKdm0wKHhdB4WM= +github.com/RyuaNerin/go-krypto v1.0.2/go.mod h1:17LzMeJCgzGTkPH3TmfzRnEJ/yA7ErhTPp9sxIqONtA= +github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok= +github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= @@ -19,7 +23,15 @@ 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/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= +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= +github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391/go.mod h1:K2R7GhgxrlJzHw2qiPWsCZXf/kXEJN9PLnQK73Ll0po= +github.com/ericlagergren/saferand v0.0.0-20220206064634-960a4dd2bc5c h1:RUzBDdZ+e/HEe2Nh8lYsduiPAZygUfVXJn0Ncj5sHMg= +github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBEz5nGDMvswiajqh7k8ogWRlhRwKy5mY= +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/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw= @@ -40,11 +52,6 @@ github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaS 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/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/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= @@ -52,25 +59,19 @@ github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +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/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8 h1:Z72DOke2yOK0Ms4Z2LK1E1OrRJXOxSj5DllTz2FYTRg= -github.com/insomniacslk/dhcp v0.0.0-20221215072855-de60144f33f8/go.mod h1:m5WMe03WCvWcXjRnhvaAbAAXdCnu20J5P+mmH44ZzpE= +github.com/insomniacslk/dhcp v0.0.0-20230307103557-e252950ab961 h1:x/YtdDlmypenG1te/FfH6LVM+3krhXk5CFV8VYNNX5M= +github.com/insomniacslk/dhcp v0.0.0-20230307103557-e252950ab961/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI= 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= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= -github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= -github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= -github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/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= @@ -82,25 +83,18 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 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/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= -github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= -github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= -github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= -github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= github.com/mdlayher/netlink v1.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/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= github.com/mdlayher/socket v0.4.0 h1:280wsy40IC9M9q1uPGcLBwXpcTQDtoGwVt+BNoITxIw= github.com/mdlayher/socket v0.4.0/go.mod h1:xxFqz5GRCUN3UEOm9CZqEJsAbe1C8OwSK46NlmWuVoc= github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 h1:gREIdurac9fpyBMBRPPMF/Sk3gKfPfdNCa4GQyR9FoA= github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03/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.1.1-0.20230226153717-4e80da7e6947 h1:NnjC2+aIiyzzvFlo+C2WzBOJdsp+HAtu18FZomqYhUE= -github.com/metacubex/sing-shadowsocks v0.1.1-0.20230226153717-4e80da7e6947/go.mod h1:U2gwhxzqgbhKCgn2B4z3t0Cj0LpMWFl/02BGCoG421w= -github.com/metacubex/sing-tun v0.1.3-0.20230323115055-7935ba0ac8b3 h1:LnKcLs0HI0HX4xH/2XerX+1BLXS1Uj6Xvzn20xFuCOk= -github.com/metacubex/sing-tun v0.1.3-0.20230323115055-7935ba0ac8b3/go.mod h1:0i22nk0tgkQz/N96hrhPib1O/C5AjxSnco7Mwi2YSF0= +github.com/metacubex/sing-shadowsocks v0.2.1 h1:tpSZQIzXT/qWDNPZjnb6jnj/htkcESLRJ37SNg2mXy4= +github.com/metacubex/sing-shadowsocks v0.2.1/go.mod h1:PNgGOvhangviWQkUH/spVwVt5w42nvs8jYckRh5WoCM= +github.com/metacubex/sing-tun v0.1.3 h1:LCz8TlAZUWwnBYZxs1PEE04PyfLA9xdsye6CjHZlZGQ= +github.com/metacubex/sing-tun v0.1.3/go.mod h1:kHkYHoRlYA4I12QPTt/ADyRGqy5YweLUfye1E1hC/q4= github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb h1:uhvzbtOvyg2c1k1H2EeVPuPvTEjDHCq4+U0AljG40P8= github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= @@ -111,6 +105,8 @@ github.com/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/ 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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +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= @@ -123,6 +119,8 @@ github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6 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/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= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= @@ -139,8 +137,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.1-0.20230323071235-f8038854d286 h1:0Td2b5l1KgrdlOnbRWgFFWsyb0TLoq/tP6j9Lut4JN0= -github.com/sagernet/sing v0.2.1-0.20230323071235-f8038854d286/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= +github.com/sagernet/sing v0.2.1 h1:r0STYeyfKBBtoAHsBtW1dQonxG+3Qidde7/1VAMhdn8= +github.com/sagernet/sing v0.2.1/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM= @@ -153,10 +151,14 @@ github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aW github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA= +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/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 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= @@ -168,8 +170,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/u-root/uio v0.0.0-20221213070652-c3537552635f h1:dpx1PHxYqAnXzbryJrWP1NQLzEjwcVgFLhkknuFQ7ww= -github.com/u-root/uio v0.0.0-20221213070652-c3537552635f/go.mod h1:IogEAUBXDEwX7oR/BMmCctShYs80ql4hF0ySdzGxf7E= +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.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= @@ -177,13 +179,14 @@ github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837/go.mod h1:YJTRELIWrGxR1s8x github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= 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.uber.org/automaxprocs v1.5.1 h1:e1YG66Lrk73dn4qhg8WFSvhF0JuFQF0ERIp4rpuV8Qk= -go.uber.org/automaxprocs v1.5.1/go.mod h1:BF4eumQw0P9GtnuxxovUd06vwm1o18oMzFtK66vU6XU= +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.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug= @@ -193,16 +196,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB 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/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= @@ -211,20 +206,11 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/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-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -242,7 +228,6 @@ golang.org/x/text v0.8.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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 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= From affc453b6ea2e6d4d280b3a1d8ced0c76be5f9bb Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 2 Apr 2023 15:16:42 +0800 Subject: [PATCH 158/530] chore: better upgrade --- hub/route/restart.go | 34 +++++++++++++++++++--------------- hub/route/upgrade.go | 22 +++++++++++++++++++--- hub/updater/updater.go | 23 +++++++++-------------- 3 files changed, 47 insertions(+), 32 deletions(-) diff --git a/hub/route/restart.go b/hub/route/restart.go index 9539296e..69b4f5b8 100644 --- a/hub/route/restart.go +++ b/hub/route/restart.go @@ -38,25 +38,29 @@ func restart(w http.ResponseWriter, r *http.Request) { // The background context is used because the underlying functions wrap it // with timeout and shut down the server, which handles current request. It // also should be done in a separate goroutine for the same reason. - go func() { - if runtime.GOOS == "windows" { - cmd := exec.Command(execPath, os.Args[1:]...) - log.Infoln("restarting: %q %q", execPath, os.Args[1:]) - cmd.Stdin = os.Stdin - cmd.Stdout = os.Stdout - cmd.Stderr = os.Stderr - err = cmd.Start() - if err != nil { - log.Fatalln("restarting: %s", err) - } + go runRestart(execPath) +} - os.Exit(0) - } +func runRestart(execPath string) { + var err error + if runtime.GOOS == "windows" { + cmd := exec.Command(execPath, os.Args[1:]...) log.Infoln("restarting: %q %q", execPath, os.Args[1:]) - err = syscall.Exec(execPath, os.Args, os.Environ()) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err = cmd.Start() if err != nil { log.Fatalln("restarting: %s", err) } - }() + + os.Exit(0) + } + + log.Infoln("restarting: %q %q", execPath, os.Args[1:]) + err = syscall.Exec(execPath, os.Args, os.Environ()) + if err != nil { + log.Fatalln("restarting: %s", err) + } } diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index 5adf79eb..0a7c54f9 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -1,12 +1,15 @@ package route import ( + "fmt" "net/http" + "os" "github.com/Dreamacro/clash/hub/updater" "github.com/Dreamacro/clash/log" "github.com/go-chi/chi/v5" + "github.com/go-chi/render" ) func upgradeRouter() http.Handler { @@ -18,11 +21,24 @@ func upgradeRouter() http.Handler { func upgrade(w http.ResponseWriter, r *http.Request) { // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L108 log.Infoln("start update") - err := updater.Update() + execPath, err := os.Executable() if err != nil { - log.Errorln("err:%s", err) + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, newError(fmt.Sprintf("getting path: %s", err))) return } - restart(w, r) + err = updater.Update(execPath) + if err != nil { + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, newError(fmt.Sprintf("Upgrade: %s", err))) + return + } + + render.JSON(w, r, render.M{"status": "ok"}) + if f, ok := w.(http.Flusher); ok { + f.Flush() + } + + go runRestart(execPath) } diff --git a/hub/updater/updater.go b/hub/updater/updater.go index b428ca9c..3d80707a 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -50,12 +50,12 @@ type updateError struct { } func (e *updateError) Error() string { - return fmt.Sprintf("error: %s", e.Message) + return fmt.Sprintf("update error: %s", e.Message) } // Update performs the auto-updater. It returns an error if the updater failed. // If firstRun is true, it assumes the configuration file doesn't exist. -func Update() (err error) { +func Update(execPath string) (err error) { mu.Lock() defer mu.Unlock() @@ -63,7 +63,6 @@ func Update() (err error) { goarch = runtime.GOARCH latestVersion, err = getLatestVersion() if err != nil { - err := &updateError{Message: err.Error()} return err } @@ -84,11 +83,6 @@ func Update() (err error) { } }() - execPath, err := os.Executable() - if err != nil { - return fmt.Errorf("getting executable path: %w", err) - } - workDir = filepath.Dir(execPath) err = prepare(execPath) @@ -110,7 +104,7 @@ func Update() (err error) { err = backup() if err != nil { - return fmt.Errorf("replacing: %w", err) + return fmt.Errorf("backuping: %w", err) } err = replace() @@ -186,9 +180,9 @@ func unpack() error { return nil } -// backup makes a backup of the current configuration and supporting files. +// backup makes a backup of the current executable file func backup() (err error) { - log.Infoln("updater: backing up current ExecFile:%s", currentExeName) + log.Infoln("updater: backing up current ExecFile:%s to %s", currentExeName, backupExeName) _ = os.Mkdir(backupDir, 0o755) err = os.Rename(currentExeName, backupExeName) @@ -199,12 +193,11 @@ func backup() (err error) { return nil } -// replace moves the current executable with the updated one and also copies the -// supporting files. +// replace moves the current executable with the updated one func replace() error { var err error - log.Infoln("copying: %s to %s", updateExeName, currentExeName) + log.Infoln("replacing: %s to %s", updateExeName, currentExeName) if goos == "windows" { // rename fails with "File in use" error err = copyFile(updateExeName, currentExeName) @@ -214,7 +207,9 @@ func replace() error { if err != nil { return err } + log.Infoln("updater: renamed: %s to %s", updateExeName, currentExeName) + return nil } From 2ff0f9426272aa963d159bcfb4303640195a871f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 2 Apr 2023 17:29:17 +0800 Subject: [PATCH 159/530] chore: sync sing-wireguard's update --- adapter/outbound/wireguard.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 7eae30fc..881bdf99 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -105,7 +105,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { reserved[2] = uint8(option.Reserved[2]) } peerAddr := M.ParseSocksaddrHostPort(option.Server, uint16(option.Port)) - outbound.bind = wireguard.NewClientBind(context.Background(), outbound.dialer, peerAddr, reserved) + outbound.bind = wireguard.NewClientBind(context.Background(), outbound.dialer, true, peerAddr, reserved) localPrefixes := make([]netip.Prefix, 0, 2) if len(option.Ip) > 0 { if !strings.Contains(option.Ip, "/") { diff --git a/go.mod b/go.mod index 7b33fcb5..b495a36a 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 github.com/metacubex/sing-shadowsocks v0.2.1 github.com/metacubex/sing-tun v0.1.3 - github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb + github.com/metacubex/sing-wireguard v0.0.0-20230402083957-d134f603ac98 github.com/miekg/dns v1.1.52 github.com/mroth/weightedrand/v2 v2.0.0 github.com/oschwald/geoip2-golang v1.8.0 diff --git a/go.sum b/go.sum index 7c60b4bf..e8667af9 100644 --- a/go.sum +++ b/go.sum @@ -95,8 +95,8 @@ github.com/metacubex/sing-shadowsocks v0.2.1 h1:tpSZQIzXT/qWDNPZjnb6jnj/htkcESLR github.com/metacubex/sing-shadowsocks v0.2.1/go.mod h1:PNgGOvhangviWQkUH/spVwVt5w42nvs8jYckRh5WoCM= github.com/metacubex/sing-tun v0.1.3 h1:LCz8TlAZUWwnBYZxs1PEE04PyfLA9xdsye6CjHZlZGQ= github.com/metacubex/sing-tun v0.1.3/go.mod h1:kHkYHoRlYA4I12QPTt/ADyRGqy5YweLUfye1E1hC/q4= -github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb h1:uhvzbtOvyg2c1k1H2EeVPuPvTEjDHCq4+U0AljG40P8= -github.com/metacubex/sing-wireguard v0.0.0-20230310035749-f7595fcae5cb/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= +github.com/metacubex/sing-wireguard v0.0.0-20230402083957-d134f603ac98 h1:Dr6A4drhVkjPaJ5lIf3DwhH2HSo+Qmf8fCQmJoDG5YU= +github.com/metacubex/sing-wireguard v0.0.0-20230402083957-d134f603ac98/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c= From 99f84b8a66de6bf32b6c3d6d6e725633dece7047 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 2 Apr 2023 22:24:46 +0800 Subject: [PATCH 160/530] chore: make all net.Conn wrapper can pass through N.ExtendedConn --- adapter/outbound/trojan.go | 3 +- adapter/outbound/wireguard.go | 4 +- common/callback/callback.go | 52 ++++++------------------- common/net/refconn.go | 18 ++++++++- constant/adapters.go | 3 +- listener/sing/sing.go | 9 +++-- transport/tuic/congestion/bbr_sender.go | 2 +- transport/tuic/conn.go | 4 +- transport/tuic/server.go | 4 +- tunnel/statistic/tracker.go | 11 ++---- 10 files changed, 45 insertions(+), 65 deletions(-) diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 030e74a9..4a31538b 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -8,7 +8,6 @@ import ( "net/http" "strconv" - N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" @@ -105,7 +104,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) return c, err } err = t.instance.WriteHeader(c, trojan.CommandTCP, serializesSocksAddr(metadata)) - return N.NewExtendedConn(c), err + return c, err } // DialContext implements C.ProxyAdapter diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 881bdf99..f82d120e 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -60,7 +60,7 @@ type wgSingDialer struct { dialer dialer.Dialer } -var _ N.Dialer = &wgSingDialer{} +var _ N.Dialer = (*wgSingDialer)(nil) func (d *wgSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { return d.dialer.DialContext(ctx, network, destination.String()) @@ -74,7 +74,7 @@ type wgNetDialer struct { tunDevice wireguard.Device } -var _ dialer.NetDialer = &wgNetDialer{} +var _ dialer.NetDialer = (*wgNetDialer)(nil) func (d wgNetDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { return d.tunDevice.DialContext(ctx, network, M.ParseSocksaddr(address).Unwrap()) diff --git a/common/callback/callback.go b/common/callback/callback.go index 9d64bb92..0bf720f4 100644 --- a/common/callback/callback.go +++ b/common/callback/callback.go @@ -22,53 +22,23 @@ func (c *firstWriteCallBackConn) Write(b []byte) (n int, err error) { return c.Conn.Write(b) } +func (c *firstWriteCallBackConn) WriteBuffer(buffer *buf.Buffer) (err error) { + defer func() { + if !c.written { + c.written = true + c.callback(err) + } + }() + return c.Conn.WriteBuffer(buffer) +} + func (c *firstWriteCallBackConn) Upstream() any { return c.Conn } -type extendedConn interface { - C.Conn - N.ExtendedConn -} - -type firstWriteCallBackExtendedConn struct { - extendedConn - callback func(error) - written bool -} - -func (c *firstWriteCallBackExtendedConn) Write(b []byte) (n int, err error) { - defer func() { - if !c.written { - c.written = true - c.callback(err) - } - }() - return c.extendedConn.Write(b) -} - -func (c *firstWriteCallBackExtendedConn) WriteBuffer(buffer *buf.Buffer) (err error) { - defer func() { - if !c.written { - c.written = true - c.callback(err) - } - }() - return c.extendedConn.WriteBuffer(buffer) -} - -func (c *firstWriteCallBackExtendedConn) Upstream() any { - return c.extendedConn -} +var _ N.ExtendedConn = (*firstWriteCallBackConn)(nil) func NewFirstWriteCallBackConn(c C.Conn, callback func(error)) C.Conn { - if c, ok := c.(extendedConn); ok { - return &firstWriteCallBackExtendedConn{ - extendedConn: c, - callback: callback, - written: false, - } - } return &firstWriteCallBackConn{ Conn: c, callback: callback, diff --git a/common/net/refconn.go b/common/net/refconn.go index 324e6474..59225db0 100644 --- a/common/net/refconn.go +++ b/common/net/refconn.go @@ -4,10 +4,12 @@ import ( "net" "runtime" "time" + + "github.com/Dreamacro/clash/common/buf" ) type refConn struct { - conn net.Conn + conn ExtendedConn ref any } @@ -55,8 +57,20 @@ func (c *refConn) Upstream() any { return c.conn } +func (c *refConn) ReadBuffer(buffer *buf.Buffer) error { + defer runtime.KeepAlive(c.ref) + return c.conn.ReadBuffer(buffer) +} + +func (c *refConn) WriteBuffer(buffer *buf.Buffer) error { + defer runtime.KeepAlive(c.ref) + return c.conn.WriteBuffer(buffer) +} + +var _ ExtendedConn = (*refConn)(nil) + func NewRefConn(conn net.Conn, ref any) net.Conn { - return &refConn{conn: conn, ref: ref} + return &refConn{conn: NewExtendedConn(conn), ref: ref} } type refPacketConn struct { diff --git a/constant/adapters.go b/constant/adapters.go index bf5f7fdb..ce9f9911 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -8,6 +8,7 @@ import ( "sync" "time" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" ) @@ -72,7 +73,7 @@ func (c Chain) Last() string { } type Conn interface { - net.Conn + N.ExtendedConn Connection } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 70462728..2a5a7d50 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -10,6 +10,7 @@ import ( "time" "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" @@ -33,7 +34,7 @@ type ListenerHandler struct { } type waitCloseConn struct { - net.Conn + N.ExtendedConn wg *sync.WaitGroup close sync.Once rAddr net.Addr @@ -43,7 +44,7 @@ func (c *waitCloseConn) Close() error { // call from handleTCPConn(connCtx C.Con c.close.Do(func() { c.wg.Done() }) - return c.Conn.Close() + return c.ExtendedConn.Close() } func (c *waitCloseConn) RemoteAddr() net.Addr { @@ -51,7 +52,7 @@ func (c *waitCloseConn) RemoteAddr() net.Addr { } func (c *waitCloseConn) Upstream() any { - return c.Conn + return c.ExtendedConn } func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { @@ -79,7 +80,7 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta defer wg.Wait() // this goroutine must exit after conn.Close() wg.Add(1) - h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{Conn: conn, wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, additions...) + h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, additions...) return nil } diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index d848a9a8..99164362 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -955,7 +955,7 @@ func (b *bbrSender) CalculateRecoveryWindow(ackedBytes, lostBytes congestion.Byt b.recoveryWindow = maxByteCount(b.recoveryWindow, b.minCongestionWindow()) } -var _ congestion.CongestionControl = &bbrSender{} +var _ congestion.CongestionControl = (*bbrSender)(nil) func (b *bbrSender) GetMinRtt() time.Duration { if b.minRtt > 0 { diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index d5955e13..8f63da75 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -103,7 +103,7 @@ func (q *quicStreamConn) RemoteAddr() net.Addr { return q.rAddr } -var _ net.Conn = &quicStreamConn{} +var _ net.Conn = (*quicStreamConn)(nil) type quicStreamPacketConn struct { connId uint32 @@ -252,4 +252,4 @@ func (q *quicStreamPacketConn) LocalAddr() net.Addr { return q.quicConn.LocalAddr() } -var _ net.PacketConn = &quicStreamPacketConn{} +var _ net.PacketConn = (*quicStreamPacketConn)(nil) diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 5eb6e611..88169aed 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -294,5 +294,5 @@ func (s *serverUDPPacket) Drop() { s.packet.DATA = nil } -var _ C.UDPPacket = &serverUDPPacket{} -var _ C.UDPPacketInAddr = &serverUDPPacket{} +var _ C.UDPPacket = (*serverUDPPacket)(nil) +var _ C.UDPPacketInAddr = (*serverUDPPacket)(nil) diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index f7e9d971..11b9c0cd 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -5,7 +5,6 @@ import ( "time" "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" @@ -32,9 +31,7 @@ type trackerInfo struct { type tcpTracker struct { C.Conn `json:"-"` *trackerInfo - manager *Manager - extendedReader N.ExtendedReader - extendedWriter N.ExtendedWriter + manager *Manager } func (tt *tcpTracker) ID() string { @@ -50,7 +47,7 @@ func (tt *tcpTracker) Read(b []byte) (int, error) { } func (tt *tcpTracker) ReadBuffer(buffer *buf.Buffer) (err error) { - err = tt.extendedReader.ReadBuffer(buffer) + err = tt.Conn.ReadBuffer(buffer) download := int64(buffer.Len()) tt.manager.PushDownloaded(download) tt.DownloadTotal.Add(download) @@ -67,7 +64,7 @@ func (tt *tcpTracker) Write(b []byte) (int, error) { func (tt *tcpTracker) WriteBuffer(buffer *buf.Buffer) (err error) { upload := int64(buffer.Len()) - err = tt.extendedWriter.WriteBuffer(buffer) + err = tt.Conn.WriteBuffer(buffer) tt.manager.PushUploaded(upload) tt.UploadTotal.Add(upload) return @@ -103,8 +100,6 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R UploadTotal: atomic.NewInt64(uploadTotal), DownloadTotal: atomic.NewInt64(downloadTotal), }, - extendedReader: N.NewExtendedReader(conn), - extendedWriter: N.NewExtendedWriter(conn), } if rule != nil { From 7308c6c2a9ced1a28689f719ce395522b7ec44cc Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 3 Apr 2023 08:54:28 +0800 Subject: [PATCH 161/530] feat: Add multi-peer support for wireguard outbound --- adapter/outbound/wireguard.go | 220 +++++++++++++++++++++++----------- docs/config.yaml | 13 +- 2 files changed, 162 insertions(+), 71 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index f82d120e..f136a20a 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -41,19 +41,26 @@ type WireGuard struct { type WireGuardOption struct { BasicOption - Name string `proxy:"name"` - Server string `proxy:"server"` - Port int `proxy:"port"` - Ip string `proxy:"ip,omitempty"` - Ipv6 string `proxy:"ipv6,omitempty"` - PrivateKey string `proxy:"private-key"` - PublicKey string `proxy:"public-key"` - PreSharedKey string `proxy:"pre-shared-key,omitempty"` - Reserved []uint8 `proxy:"reserved,omitempty"` - Workers int `proxy:"workers,omitempty"` - MTU int `proxy:"mtu,omitempty"` - UDP bool `proxy:"udp,omitempty"` - PersistentKeepalive int `proxy:"persistent-keepalive,omitempty"` + WireGuardPeerOption + Name string `proxy:"name"` + PrivateKey string `proxy:"private-key"` + Workers int `proxy:"workers,omitempty"` + MTU int `proxy:"mtu,omitempty"` + UDP bool `proxy:"udp,omitempty"` + PersistentKeepalive int `proxy:"persistent-keepalive,omitempty"` + + Peers []WireGuardPeerOption `proxy:"peers,omitempty"` +} + +type WireGuardPeerOption struct { + Server string `proxy:"server"` + Port int `proxy:"port"` + Ip string `proxy:"ip,omitempty"` + Ipv6 string `proxy:"ipv6,omitempty"` + PublicKey string `proxy:"public-key,omitempty"` + PreSharedKey string `proxy:"pre-shared-key,omitempty"` + Reserved []uint8 `proxy:"reserved,omitempty"` + AllowedIPs []string `proxy:"allowed_ips,omitempty"` } type wgSingDialer struct { @@ -80,32 +87,11 @@ func (d wgNetDialer) DialContext(ctx context.Context, network, address string) ( return d.tunDevice.DialContext(ctx, network, M.ParseSocksaddr(address).Unwrap()) } -func NewWireGuard(option WireGuardOption) (*WireGuard, error) { - outbound := &WireGuard{ - Base: &Base{ - name: option.Name, - addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), - tp: C.WireGuard, - udp: option.UDP, - iface: option.Interface, - rmark: option.RoutingMark, - prefer: C.NewDNSPrefer(option.IPVersion), - }, - dialer: &wgSingDialer{dialer: dialer.NewDialer()}, - } - runtime.SetFinalizer(outbound, closeWireGuard) +func (option WireGuardPeerOption) Addr() M.Socksaddr { + return M.ParseSocksaddrHostPort(option.Server, uint16(option.Port)) +} - var reserved [3]uint8 - if len(option.Reserved) > 0 { - if len(option.Reserved) != 3 { - return nil, E.New("invalid reserved value, required 3 bytes, got ", len(option.Reserved)) - } - reserved[0] = uint8(option.Reserved[0]) - reserved[1] = uint8(option.Reserved[1]) - reserved[2] = uint8(option.Reserved[2]) - } - peerAddr := M.ParseSocksaddrHostPort(option.Server, uint16(option.Port)) - outbound.bind = wireguard.NewClientBind(context.Background(), outbound.dialer, true, peerAddr, reserved) +func (option WireGuardPeerOption) Prefixes() ([]netip.Prefix, error) { localPrefixes := make([]netip.Prefix, 0, 2) if len(option.Ip) > 0 { if !strings.Contains(option.Ip, "/") { @@ -130,7 +116,46 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { if len(localPrefixes) == 0 { return nil, E.New("missing local address") } - var privateKey, peerPublicKey, preSharedKey string + return localPrefixes, nil +} + +func NewWireGuard(option WireGuardOption) (*WireGuard, error) { + outbound := &WireGuard{ + Base: &Base{ + name: option.Name, + addr: net.JoinHostPort(option.Server, strconv.Itoa(option.Port)), + tp: C.WireGuard, + udp: option.UDP, + iface: option.Interface, + rmark: option.RoutingMark, + prefer: C.NewDNSPrefer(option.IPVersion), + }, + dialer: &wgSingDialer{dialer: dialer.NewDialer()}, + } + runtime.SetFinalizer(outbound, closeWireGuard) + + var reserved [3]uint8 + if len(option.Reserved) > 0 { + if len(option.Reserved) != 3 { + return nil, E.New("invalid reserved value, required 3 bytes, got ", len(option.Reserved)) + } + copy(reserved[:], option.Reserved) + } + var isConnect bool + var connectAddr M.Socksaddr + if len(option.Peers) < 2 { + isConnect = true + if len(option.Peers) == 1 { + connectAddr = option.Peers[0].Addr() + } else { + connectAddr = option.Addr() + } + } + outbound.bind = wireguard.NewClientBind(context.Background(), outbound.dialer, isConnect, connectAddr, reserved) + + var localPrefixes []netip.Prefix + + var privateKey string { bytes, err := base64.StdEncoding.DecodeString(option.PrivateKey) if err != nil { @@ -138,40 +163,92 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { } privateKey = hex.EncodeToString(bytes) } - { - bytes, err := base64.StdEncoding.DecodeString(option.PublicKey) - if err != nil { - return nil, E.Cause(err, "decode peer public key") - } - peerPublicKey = hex.EncodeToString(bytes) - } - if option.PreSharedKey != "" { - bytes, err := base64.StdEncoding.DecodeString(option.PreSharedKey) - if err != nil { - return nil, E.Cause(err, "decode pre shared key") - } - preSharedKey = hex.EncodeToString(bytes) - } ipcConf := "private_key=" + privateKey - ipcConf += "\npublic_key=" + peerPublicKey - ipcConf += "\nendpoint=" + peerAddr.String() - if preSharedKey != "" { - ipcConf += "\npreshared_key=" + preSharedKey - } - var has4, has6 bool - for _, address := range localPrefixes { - if address.Addr().Is4() { - has4 = true - } else { - has6 = true + if peersLen := len(option.Peers); peersLen > 0 { + localPrefixes = make([]netip.Prefix, 0, peersLen*2) + for i, peer := range option.Peers { + var peerPublicKey, preSharedKey string + { + bytes, err := base64.StdEncoding.DecodeString(peer.PublicKey) + if err != nil { + return nil, E.Cause(err, "decode public key for peer ", i) + } + peerPublicKey = hex.EncodeToString(bytes) + } + if peer.PreSharedKey != "" { + bytes, err := base64.StdEncoding.DecodeString(peer.PreSharedKey) + if err != nil { + return nil, E.Cause(err, "decode pre shared key for peer ", i) + } + preSharedKey = hex.EncodeToString(bytes) + } + destination := peer.Addr() + ipcConf += "\npublic_key=" + peerPublicKey + ipcConf += "\nendpoint=" + destination.String() + if preSharedKey != "" { + ipcConf += "\npreshared_key=" + preSharedKey + } + if len(peer.AllowedIPs) == 0 { + return nil, E.New("missing allowed_ips for peer ", i) + } + for _, allowedIP := range peer.AllowedIPs { + ipcConf += "\nallowed_ip=" + allowedIP + } + if len(peer.Reserved) > 0 { + if len(peer.Reserved) != 3 { + return nil, E.New("invalid reserved value for peer ", i, ", required 3 bytes, got ", len(peer.Reserved)) + } + copy(reserved[:], option.Reserved) + outbound.bind.SetReservedForEndpoint(destination, reserved) + } + prefixes, err := peer.Prefixes() + if err != nil { + return nil, err + } + localPrefixes = append(localPrefixes, prefixes...) + } + } else { + var peerPublicKey, preSharedKey string + { + bytes, err := base64.StdEncoding.DecodeString(option.PublicKey) + if err != nil { + return nil, E.Cause(err, "decode peer public key") + } + peerPublicKey = hex.EncodeToString(bytes) + } + if option.PreSharedKey != "" { + bytes, err := base64.StdEncoding.DecodeString(option.PreSharedKey) + if err != nil { + return nil, E.Cause(err, "decode pre shared key") + } + preSharedKey = hex.EncodeToString(bytes) + } + ipcConf += "\npublic_key=" + peerPublicKey + ipcConf += "\nendpoint=" + connectAddr.String() + if preSharedKey != "" { + ipcConf += "\npreshared_key=" + preSharedKey + } + var err error + localPrefixes, err = option.Prefixes() + if err != nil { + return nil, err + } + var has4, has6 bool + for _, address := range localPrefixes { + if address.Addr().Is4() { + has4 = true + } else { + has6 = true + } + } + if has4 { + ipcConf += "\nallowed_ip=0.0.0.0/0" + } + if has6 { + ipcConf += "\nallowed_ip=::/0" } } - if has4 { - ipcConf += "\nallowed_ip=0.0.0.0/0" - } - if has6 { - ipcConf += "\nallowed_ip=::/0" - } + if option.PersistentKeepalive != 0 { ipcConf += fmt.Sprintf("\npersistent_keepalive_interval=%d", option.PersistentKeepalive) } @@ -179,6 +256,9 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { if mtu == 0 { mtu = 1408 } + if len(localPrefixes) == 0 { + return nil, E.New("missing local address") + } var err error outbound.tunDevice, err = wireguard.NewStackDevice(localPrefixes, uint32(mtu)) if err != nil { diff --git a/docs/config.yaml b/docs/config.yaml index c2acc1d4..32665aaf 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -620,12 +620,23 @@ proxies: # socks5 port: 2480 ip: 172.16.0.2 ipv6: fd01:5ca1:ab1e:80fa:ab85:6eea:213f:f4a5 - private-key: eCtXsJZ27+4PbhDkHnB923tkUn2Gj59wZw5wFA75MnU= public-key: Cr8hWlKvtDt7nrvf+f0brNQQzabAqrjfBvas9pmowjo= + # pre-shared-key: 31aIhAPwktDGpH4JDhA8GNvjFXEf/a6+UaQRyOAiyfM= + private-key: eCtXsJZ27+4PbhDkHnB923tkUn2Gj59wZw5wFA75MnU= udp: true reserved: "U4An" # 数组格式也是合法的 # reserved: [209,98,59] + # 如果peers不为空,该段落中的allowed_ips不可为空;前面段落的server,port,ip,ipv6,public-key,pre-shared-key均会被忽略,但private-key会被保留且只能在顶层指定 + # peers: + # - server: 162.159.192.1 + # port: 2480 + # ip: 172.16.0.2 + # ipv6: fd01:5ca1:ab1e:80fa:ab85:6eea:213f:f4a5 + # public-key: Cr8hWlKvtDt7nrvf+f0brNQQzabAqrjfBvas9pmowjo= + # # pre-shared-key: 31aIhAPwktDGpH4JDhA8GNvjFXEf/a6+UaQRyOAiyfM= + # allowed_ips: ['0.0.0.0/0'] + # reserved: [209,98,59] # tuic - name: tuic From 2fc37501f569203fde44154aa946fc7e14658a5f Mon Sep 17 00:00:00 2001 From: Skyxim Date: Mon, 3 Apr 2023 01:06:04 +0000 Subject: [PATCH 162/530] chore: update demo --- docs/config.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index 32665aaf..0b179dd4 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -238,7 +238,9 @@ dns: - https://doh.pub/dns-query - https://dns.alidns.com/dns-query "www.baidu.com,+.google.cn": [223.5.5.5, https://dns.alidns.com/dns-query] - # "rule-set:global,dns": 8.8.8.8 # global,dns 为 rule-providers 中的名为 global 和 dns 的规则提供器名字,且 behavior 必须为 domain + ## global,dns 为 rule-providers 中的名为 global 和 dns 规则订阅, + ## 且 behavior 必须为 domain/classical,当为 classical 时仅会生效域名类规则 + # "rule-set:global,dns": 8.8.8.8 proxies: # socks5 - name: "socks" From bf31abee22cd235bbedf29499e7156ce51720746 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 3 Apr 2023 12:03:18 +0000 Subject: [PATCH 163/530] chore: clean up code --- .github/workflows/build.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index dc43a10e..87cfb07f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,17 +5,15 @@ on: paths-ignore: - "docs/**" - "README.md" + - ".github/ISSUE_TEMPLATE/**" branches: - Alpha - - Beta - Meta tags: - "v*" pull_request_target: branches: - Alpha - - Beta - - Meta concurrency: group: ${{ github.ref }}-${{ github.workflow }} From ee5c4cb83bfd46994ca9ad1922bb9a1e9803bc46 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 3 Apr 2023 21:07:52 +0800 Subject: [PATCH 164/530] fix: tuic fast-open not work --- transport/tuic/client.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/transport/tuic/client.go b/transport/tuic/client.go index 4932dc9b..af00da03 100644 --- a/transport/tuic/client.go +++ b/transport/tuic/client.go @@ -12,6 +12,7 @@ import ( "sync/atomic" "time" + "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" @@ -338,6 +339,14 @@ func (conn *earlyConn) Read(b []byte) (n int, err error) { return conn.BufferedConn.Read(b) } +func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) { + err = conn.Response() + if err != nil { + return err + } + return conn.BufferedConn.ReadBuffer(buffer) +} + func (t *clientImpl) ListenPacketWithDialer(ctx context.Context, metadata *C.Metadata, dialer C.Dialer, dialFn DialFunc) (net.PacketConn, error) { quicConn, err := t.getQuicConn(ctx, dialer, dialFn) if err != nil { From ae722bb1a0b965a51a5df2d30f2f6f972a135b03 Mon Sep 17 00:00:00 2001 From: H1JK Date: Wed, 5 Apr 2023 13:51:50 +0800 Subject: [PATCH 165/530] chore: Add early bounds checks --- transport/gun/gun.go | 1 + transport/vmess/websocket.go | 1 + 2 files changed, 2 insertions(+) diff --git a/transport/gun/gun.go b/transport/gun/gun.go index ae2ea6a4..0e5d2321 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -147,6 +147,7 @@ func (g *Conn) WriteBuffer(buffer *buf.Buffer) error { dataLen := buffer.Len() varLen := UVarintLen(uint64(dataLen)) header := buffer.ExtendHeader(6 + varLen) + _ = header[6] // bounds check hint to compiler header[0] = 0x00 binary.BigEndian.PutUint32(header[1:5], uint32(1+varLen+dataLen)) header[5] = 0x0A diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 5fcaa0b8..179da886 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -107,6 +107,7 @@ func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { headerLen += 4 // MASK KEY header := buffer.ExtendHeader(headerLen) + _ = header[2] // bounds check hint to compiler header[0] = websocket.BinaryMessage | 1<<7 header[1] = 1 << 7 From f92f34bb207520700418b7213bac50de3b1ac2d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8C=85=E5=B8=83=E4=B8=81?= Date: Sun, 26 Mar 2023 16:22:23 +0800 Subject: [PATCH 166/530] Fix: return pooled buffer when simple-obfs tls read error (#2643) --- transport/simple-obfs/tls.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/transport/simple-obfs/tls.go b/transport/simple-obfs/tls.go index f41e3263..20166bbe 100644 --- a/transport/simple-obfs/tls.go +++ b/transport/simple-obfs/tls.go @@ -28,10 +28,10 @@ type TLSObfs struct { func (to *TLSObfs) read(b []byte, discardN int) (int, error) { buf := pool.Get(discardN) _, err := io.ReadFull(to.Conn, buf) + pool.Put(buf) if err != nil { return 0, err } - pool.Put(buf) sizeBuf := make([]byte, 2) _, err = io.ReadFull(to.Conn, sizeBuf) From 8ab70d76e7300b73641cd7276ef1d77e35a506b1 Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Wed, 5 Apr 2023 14:05:23 +0800 Subject: [PATCH 167/530] Fix: should always drop packet when handle UDP packet (#2659) --- tunnel/connection.go | 2 -- tunnel/tunnel.go | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tunnel/connection.go b/tunnel/connection.go index e21bbdbf..c64a5266 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -13,8 +13,6 @@ import ( ) func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error { - defer packet.Drop() - addr := metadata.UDPAddr() if addr == nil { return errors.New("udp addr invalid") diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index c4f55fbd..e982afa6 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -273,6 +273,7 @@ func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, r func handleUDPConn(packet C.PacketAdapter) { metadata := packet.Metadata() if !metadata.Valid() { + packet.Drop() log.Warnln("[Metadata] not valid: %#v", metadata) return } @@ -284,6 +285,7 @@ func handleUDPConn(packet C.PacketAdapter) { } if err := preHandleMetadata(metadata); err != nil { + packet.Drop() log.Debugln("[Metadata PreHandle] error: %s", err) return } @@ -292,6 +294,7 @@ func handleUDPConn(packet C.PacketAdapter) { if !metadata.Resolved() { ip, err := resolver.ResolveIP(context.Background(), metadata.Host) if err != nil { + packet.Drop() return } metadata.DstIP = ip @@ -309,6 +312,7 @@ func handleUDPConn(packet C.PacketAdapter) { } if handle() { + packet.Drop() return } @@ -316,6 +320,8 @@ func handleUDPConn(packet C.PacketAdapter) { cond, loaded := natTable.GetOrCreateLock(lockKey) go func() { + defer packet.Drop() + if loaded { cond.L.Lock() cond.Wait() From eb07aafce8d0e07304242b756b922dde3e2db40d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 7 Apr 2023 22:37:01 +0800 Subject: [PATCH 168/530] doc: update config.yaml --- docs/config.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index 0b179dd4..66eff537 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -680,7 +680,9 @@ proxies: # socks5 # protocol-param: "#" # udp: true -proxy-groups: # 代理链,若落地协议支持 UDP over TCP 则可支持 UDP +proxy-groups: + # 代理链,目前relay可以支持udp的只有vmess/vless/trojan/ss/ssr/tuic + # wireguard目前不支持在relay中使用,请使用tunnels功能模拟 # Traffic: clash <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet - name: "relay" type: relay From 36b35813894641ff102449d0324ce63d7ce15271 Mon Sep 17 00:00:00 2001 From: rookisbusy <129355218+rookisbusy@users.noreply.github.com> Date: Fri, 7 Apr 2023 22:55:01 +0800 Subject: [PATCH 169/530] Alpha (#490) * feat: add memory status for snapshot * feat: add memory status for snapshot --- tunnel/statistic/manager.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index e67d3871..251450fb 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -1,6 +1,7 @@ package statistic import ( + "runtime" "sync" "time" @@ -61,10 +62,17 @@ func (m *Manager) Snapshot() *Snapshot { return true }) + getMem := func() uint64 { + var memStats runtime.MemStats + runtime.ReadMemStats(&memStats) + return memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased + } + return &Snapshot{ UploadTotal: m.uploadTotal.Load(), DownloadTotal: m.downloadTotal.Load(), Connections: connections, + Memory: getMem(), } } @@ -92,4 +100,5 @@ type Snapshot struct { DownloadTotal int64 `json:"downloadTotal"` UploadTotal int64 `json:"uploadTotal"` Connections []tracker `json:"connections"` + Memory uint64 `json:"memory"` } From eecd8fff71c3ff1d673110eaa4bf1f27a9c62c05 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 7 Apr 2023 23:53:46 +0800 Subject: [PATCH 170/530] feat: add memory status for snapshot --- go.mod | 10 +++++++++- go.sum | 22 ++++++++++++++++++++++ tunnel/statistic/manager.go | 17 +++++++++++++---- 3 files changed, 44 insertions(+), 5 deletions(-) diff --git a/go.mod b/go.mod index b495a36a..68e3a09b 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,7 @@ require ( github.com/metacubex/sing-wireguard v0.0.0-20230402083957-d134f603ac98 github.com/miekg/dns v1.1.52 github.com/mroth/weightedrand/v2 v2.0.0 + 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.1 @@ -34,6 +35,7 @@ require ( github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c github.com/samber/lo v1.37.0 + github.com/shirou/gopsutil/v3 v3.23.3 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.2 github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 @@ -62,6 +64,7 @@ require ( github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect 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/golang/mock v1.6.0 // indirect github.com/google/btree v1.0.1 // indirect @@ -70,24 +73,29 @@ require ( github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect + github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mdlayher/socket v0.4.0 // indirect github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // 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 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 + 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/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect + github.com/shoenig/go-m1cpu v0.1.4 // 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.0-20211101163701-50045581ed74 // indirect + github.com/yusufpapurcu/wmi v1.2.2 // 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.8.0 // indirect diff --git a/go.sum b/go.sum index e8667af9..d6320fbe 100644 --- a/go.sum +++ b/go.sum @@ -41,6 +41,8 @@ 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-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/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= @@ -53,6 +55,7 @@ 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/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= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gopacket v1.1.19 h1:ves8RnFZPGiFnTS0uPQStjwru6uO6h+nlr9j6fL7kF8= @@ -81,6 +84,8 @@ github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 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= @@ -124,6 +129,8 @@ github.com/pierrec/lz4/v4 v4.1.14/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFu github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= 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= @@ -151,6 +158,12 @@ github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aW github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA= +github.com/shirou/gopsutil/v3 v3.23.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE= +github.com/shirou/gopsutil/v3 v3.23.3/go.mod h1:lSBNN6t3+D6W5e5nXTxc8KIMMVxAcS+6IJlffjRRlMU= +github.com/shoenig/go-m1cpu v0.1.4 h1:SZPIgRM2sEF9NJy50mRHu9PKGwxyyTTJIWvCtgVbozs= +github.com/shoenig/go-m1cpu v0.1.4/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/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= @@ -170,6 +183,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +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.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= @@ -177,6 +194,8 @@ github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1 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/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/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= @@ -208,16 +227,19 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/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-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= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 251450fb..09bb3410 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -1,10 +1,11 @@ package statistic import ( - "runtime" + "os" "sync" "time" + "github.com/shirou/gopsutil/v3/process" "go.uber.org/atomic" ) @@ -18,6 +19,7 @@ func init() { downloadBlip: atomic.NewInt64(0), uploadTotal: atomic.NewInt64(0), downloadTotal: atomic.NewInt64(0), + pid: os.Getpid(), } go DefaultManager.handle() @@ -31,6 +33,7 @@ type Manager struct { downloadBlip *atomic.Int64 uploadTotal *atomic.Int64 downloadTotal *atomic.Int64 + pid int } func (m *Manager) Join(c tracker) { @@ -63,9 +66,15 @@ func (m *Manager) Snapshot() *Snapshot { }) getMem := func() uint64 { - var memStats runtime.MemStats - runtime.ReadMemStats(&memStats) - return memStats.StackInuse + memStats.HeapInuse + memStats.HeapIdle - memStats.HeapReleased + p, err := process.NewProcess(int32(m.pid)) + if err != nil { + return 0 + } + stat, err := p.MemoryInfo() + if err != nil { + return 0 + } + return stat.RSS } return &Snapshot{ From 76340cc99c99adb45597cd194346a70d5f610002 Mon Sep 17 00:00:00 2001 From: rookisbusy Date: Sat, 8 Apr 2023 00:55:25 +0800 Subject: [PATCH 171/530] feat: core support memory chat --- hub/route/server.go | 48 +++++++++++++++++++++++++++++++++++++ tunnel/statistic/manager.go | 8 ++++++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/hub/route/server.go b/hub/route/server.go index 848face9..47cb7839 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -39,6 +39,11 @@ type Traffic struct { Down int64 `json:"down"` } +type Memory struct { + Inuse uint64 `json:"inuse"` + OSLimit uint64 `json:"oslimit"` // maybe we need it in the future +} + func SetUIPath(path string) { uiPath = C.Path.Resolve(path) } @@ -76,6 +81,7 @@ func Start(addr string, tlsAddr string, secret string, r.Get("/", hello) r.Get("/logs", getLogs) r.Get("/traffic", traffic) + r.Get("/memory", memory) r.Get("/version", version) r.Mount("/configs", configRouter()) r.Mount("/proxies", proxyRouter()) @@ -224,6 +230,48 @@ func traffic(w http.ResponseWriter, r *http.Request) { } } +func memory(w http.ResponseWriter, r *http.Request) { + var wsConn *websocket.Conn + if websocket.IsWebSocketUpgrade(r) { + var err error + wsConn, err = upgrader.Upgrade(w, r, nil) + if err != nil { + return + } + } + + if wsConn == nil { + w.Header().Set("Content-Type", "application/json") + render.Status(r, http.StatusOK) + } + + tick := time.NewTicker(time.Second) + defer tick.Stop() + t := statistic.DefaultManager + buf := &bytes.Buffer{} + var err error + for range tick.C { + buf.Reset() + + if err := json.NewEncoder(buf).Encode(Memory{ + Inuse: t.Memory(), + OSLimit: 0, + }); err != nil { + break + } + if wsConn == nil { + _, err = w.Write(buf.Bytes()) + w.(http.Flusher).Flush() + } else { + err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + } + + if err != nil { + break + } + } +} + type Log struct { Type string `json:"type"` Payload string `json:"payload"` diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 09bb3410..7d0ee5e4 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -34,6 +34,7 @@ type Manager struct { uploadTotal *atomic.Int64 downloadTotal *atomic.Int64 pid int + memory uint64 } func (m *Manager) Join(c tracker) { @@ -58,6 +59,10 @@ func (m *Manager) Now() (up int64, down int64) { return m.uploadBlip.Load(), m.downloadBlip.Load() } +func (m *Manager) Memory() uint64 { + return m.memory +} + func (m *Manager) Snapshot() *Snapshot { connections := []tracker{} m.connections.Range(func(key, value any) bool { @@ -76,12 +81,13 @@ func (m *Manager) Snapshot() *Snapshot { } return stat.RSS } + m.memory = getMem() return &Snapshot{ UploadTotal: m.uploadTotal.Load(), DownloadTotal: m.downloadTotal.Load(), Connections: connections, - Memory: getMem(), + Memory: m.memory, } } From 8fb2c68722898801adbe3933933a488379fc8688 Mon Sep 17 00:00:00 2001 From: rookisbusy Date: Sat, 8 Apr 2023 01:39:48 +0800 Subject: [PATCH 172/530] fix: chat.js not begin with zero --- hub/route/server.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hub/route/server.go b/hub/route/server.go index 47cb7839..d8124d33 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -250,11 +250,19 @@ func memory(w http.ResponseWriter, r *http.Request) { t := statistic.DefaultManager buf := &bytes.Buffer{} var err error + first := true for range tick.C { buf.Reset() + inuse := t.Memory() + // make chat.js begin with zero + // this is shit var,but we need output 0 for first time + if first { + inuse = 0 + first = false + } if err := json.NewEncoder(buf).Encode(Memory{ - Inuse: t.Memory(), + Inuse: inuse, OSLimit: 0, }); err != nil { break From 2c09ce44f6a439524fcc97a66ea24dd92a17d3cb Mon Sep 17 00:00:00 2001 From: metacubex Date: Sat, 8 Apr 2023 02:04:16 +0800 Subject: [PATCH 173/530] feat: urltest can be select by user --- adapter/outboundgroup/urltest.go | 36 +++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 64ce17f6..f3426a3e 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -3,6 +3,7 @@ package outboundgroup import ( "context" "encoding/json" + "errors" "time" "github.com/Dreamacro/clash/adapter/outbound" @@ -24,6 +25,8 @@ func urlTestWithTolerance(tolerance uint16) urlTestOption { type URLTest struct { *GroupBase + selected string + testUrl string tolerance uint16 disableUDP bool fastNode C.Proxy @@ -34,6 +37,22 @@ func (u *URLTest) Now() string { return u.fast(false).Name() } +func (u *URLTest) Set(name string) error { + var p C.Proxy + for _, proxy := range u.GetProxies(false) { + if proxy.Name() == name { + p = proxy + break + } + } + if p == nil { + return errors.New("proxy not exist") + } + u.selected = name + u.fast(false) + return nil +} + // DialContext implements C.ProxyAdapter func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (c C.Conn, err error) { proxy := u.fast(true) @@ -74,16 +93,24 @@ 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 + } 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 } @@ -94,12 +121,15 @@ func (u *URLTest) fast(touch bool) C.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 @@ -114,7 +144,6 @@ func (u *URLTest) SupportUDP() bool { if u.disableUDP { return false } - return u.fast(false).SupportUDP() } @@ -161,6 +190,7 @@ func NewURLTest(option *GroupCommonOption, providers []provider.ProxyProvider, o }), fastSingle: singledo.NewSingle[C.Proxy](time.Second * 10), disableUDP: option.DisableUDP, + testUrl: option.URL, } for _, option := range options { From e9c9d17a9b7b8d3d69338af72fd195caf94a9033 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 8 Apr 2023 09:56:02 +0800 Subject: [PATCH 174/530] chore: init gopsutil's Process direct from struct --- tunnel/statistic/manager.go | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 7d0ee5e4..66e3857d 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -19,7 +19,7 @@ func init() { downloadBlip: atomic.NewInt64(0), uploadTotal: atomic.NewInt64(0), downloadTotal: atomic.NewInt64(0), - pid: os.Getpid(), + process: &process.Process{Pid: int32(os.Getpid())}, } go DefaultManager.handle() @@ -33,7 +33,7 @@ type Manager struct { downloadBlip *atomic.Int64 uploadTotal *atomic.Int64 downloadTotal *atomic.Int64 - pid int + process *process.Process memory uint64 } @@ -71,11 +71,7 @@ func (m *Manager) Snapshot() *Snapshot { }) getMem := func() uint64 { - p, err := process.NewProcess(int32(m.pid)) - if err != nil { - return 0 - } - stat, err := p.MemoryInfo() + stat, err := m.process.MemoryInfo() if err != nil { return 0 } From 8e8cddf4624c4dfa022e1b9834d883350cbd07e5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 9 Apr 2023 15:40:17 +0800 Subject: [PATCH 175/530] chore: Update dependencies --- common/utils/uuid.go | 2 +- common/utils/uuid_test.go | 2 +- constant/context.go | 2 +- context/conn.go | 2 +- context/dns.go | 2 +- context/packetconn.go | 2 +- go.mod | 18 +++++++++--------- go.sum | 35 ++++++++++++++++++----------------- transport/tuic/server.go | 2 +- transport/vless/conn.go | 2 +- transport/vless/vision.go | 2 +- transport/vless/vless.go | 2 +- transport/vmess/user.go | 2 +- transport/vmess/vmess.go | 2 +- tunnel/statistic/tracker.go | 2 +- 15 files changed, 40 insertions(+), 39 deletions(-) diff --git a/common/utils/uuid.go b/common/utils/uuid.go index 930fda7d..f559b471 100644 --- a/common/utils/uuid.go +++ b/common/utils/uuid.go @@ -1,7 +1,7 @@ package utils import ( - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" "github.com/zhangyunhao116/fastrand" ) diff --git a/common/utils/uuid_test.go b/common/utils/uuid_test.go index ba00ea08..3e0507d8 100644 --- a/common/utils/uuid_test.go +++ b/common/utils/uuid_test.go @@ -1,7 +1,7 @@ package utils import ( - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" "reflect" "testing" ) diff --git a/constant/context.go b/constant/context.go index da1e4155..1c70124b 100644 --- a/constant/context.go +++ b/constant/context.go @@ -5,7 +5,7 @@ import ( N "github.com/Dreamacro/clash/common/net" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" ) type PlainContext interface { diff --git a/context/conn.go b/context/conn.go index c5477780..afeed852 100644 --- a/context/conn.go +++ b/context/conn.go @@ -7,7 +7,7 @@ import ( N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" ) type ConnContext struct { diff --git a/context/dns.go b/context/dns.go index c41de724..ae29154f 100644 --- a/context/dns.go +++ b/context/dns.go @@ -4,7 +4,7 @@ import ( "context" "github.com/Dreamacro/clash/common/utils" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" "github.com/miekg/dns" ) diff --git a/context/packetconn.go b/context/packetconn.go index b9afef41..d695bae5 100644 --- a/context/packetconn.go +++ b/context/packetconn.go @@ -6,7 +6,7 @@ import ( "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" ) type PacketConnContext struct { diff --git a/go.mod b/go.mod index 68e3a09b..275e9595 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( 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 - github.com/gofrs/uuid v4.4.0+incompatible + 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 @@ -20,7 +20,7 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 - github.com/metacubex/sing-shadowsocks v0.2.1 + github.com/metacubex/sing-shadowsocks v0.2.2-0.20230409073201-1ce3505114ae github.com/metacubex/sing-tun v0.1.3 github.com/metacubex/sing-wireguard v0.0.0-20230402083957-d134f603ac98 github.com/miekg/dns v1.1.52 @@ -28,9 +28,9 @@ require ( 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.1 - github.com/sagernet/sing-shadowtls v0.1.0 - github.com/sagernet/sing-vmess v0.1.3 + github.com/sagernet/sing v0.2.2 + github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 + github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 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-20221116151939-c99467f53f2c @@ -43,11 +43,11 @@ require ( go.etcd.io/bbolt v1.3.6 go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.2 - golang.org/x/crypto v0.7.0 + golang.org/x/crypto v0.8.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 - golang.org/x/net v0.8.0 + golang.org/x/net v0.9.0 golang.org/x/sync v0.1.0 - golang.org/x/sys v0.6.0 + golang.org/x/sys v0.7.0 google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.1.7 @@ -98,7 +98,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.2 // 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.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 gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect diff --git a/go.sum b/go.sum index d6320fbe..05dc5abe 100644 --- a/go.sum +++ b/go.sum @@ -45,8 +45,8 @@ 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/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= -github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +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= @@ -96,8 +96,8 @@ github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 h1:gREIdurac9fpyB github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03/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.1 h1:tpSZQIzXT/qWDNPZjnb6jnj/htkcESLRJ37SNg2mXy4= -github.com/metacubex/sing-shadowsocks v0.2.1/go.mod h1:PNgGOvhangviWQkUH/spVwVt5w42nvs8jYckRh5WoCM= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230409073201-1ce3505114ae h1:SNnvqnJrqVErz1Qoo3thxa4lgdTPgBSQpJKQJcQjz9Y= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230409073201-1ce3505114ae/go.mod h1:JefDbbkQHCn8w+IcjFqMOMV2VmN9wvbYX4RaeBUkPwM= github.com/metacubex/sing-tun v0.1.3 h1:LCz8TlAZUWwnBYZxs1PEE04PyfLA9xdsye6CjHZlZGQ= github.com/metacubex/sing-tun v0.1.3/go.mod h1:kHkYHoRlYA4I12QPTt/ADyRGqy5YweLUfye1E1hC/q4= github.com/metacubex/sing-wireguard v0.0.0-20230402083957-d134f603ac98 h1:Dr6A4drhVkjPaJ5lIf3DwhH2HSo+Qmf8fCQmJoDG5YU= @@ -144,12 +144,12 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.1 h1:r0STYeyfKBBtoAHsBtW1dQonxG+3Qidde7/1VAMhdn8= -github.com/sagernet/sing v0.2.1/go.mod h1:9uHswk2hITw8leDbiLS/xn0t9nzBcbePxzm9PJhwdlw= -github.com/sagernet/sing-shadowtls v0.1.0 h1:05MYce8aR5xfKIn+y7xRFsdKhKt44QZTSEQW+lG5IWQ= -github.com/sagernet/sing-shadowtls v0.1.0/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= -github.com/sagernet/sing-vmess v0.1.3 h1:q/+tsF46dvvapL6CpQBgPHJ6nQrDUZqEtLHCbsjO7iM= -github.com/sagernet/sing-vmess v0.1.3/go.mod h1:GVXqAHwe9U21uS+Voh4YBIrADQyE4F9v0ayGSixSQAE= +github.com/sagernet/sing v0.2.2 h1:qfEdSLuwFgIIkeLOcwVQkVDzKLHtclXb93Ql0zZA+aE= +github.com/sagernet/sing v0.2.2/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 h1:QnV79JbJbJGT0MJJfd8o7QMEfRu3eUVKsmahxFMonrc= +github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661/go.mod h1:xCeSRP8cV32aPsY+6BbRdJjyD6q8ufdKwhgqxEbU/3U= +github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 h1:ZArINfN+zcHMdZCeRFOm4rO3SWyvYuLg3VhWcA5zonc= +github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7/go.mod h1:A9iGfwYmAEmVg8bavkqQ7Hx7nr9Pc2oWMYDwbLIBDjY= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= @@ -206,8 +206,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.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= -golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= +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/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -218,8 +218,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.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= -golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= +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/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.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= @@ -240,13 +240,14 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.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.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= -golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/transport/tuic/server.go b/transport/tuic/server.go index 88169aed..00c33fcb 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -17,7 +17,7 @@ import ( C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" ) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 1f7d2cb3..6c3714e0 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -18,7 +18,7 @@ import ( tlsC "github.com/Dreamacro/clash/component/tls" "github.com/Dreamacro/clash/log" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" utls "github.com/sagernet/utls" xtls "github.com/xtls/go" "google.golang.org/protobuf/proto" diff --git a/transport/vless/vision.go b/transport/vless/vision.go index 8dc84e40..5649dde4 100644 --- a/transport/vless/vision.go +++ b/transport/vless/vision.go @@ -7,7 +7,7 @@ import ( "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/log" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/vless/vless.go b/transport/vless/vless.go index 6989374c..c2066afe 100644 --- a/transport/vless/vless.go +++ b/transport/vless/vless.go @@ -5,7 +5,7 @@ import ( "github.com/Dreamacro/clash/common/utils" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" ) const ( diff --git a/transport/vmess/user.go b/transport/vmess/user.go index c098389e..091df0a8 100644 --- a/transport/vmess/user.go +++ b/transport/vmess/user.go @@ -4,7 +4,7 @@ import ( "bytes" "crypto/md5" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" ) // ID cmdKey length diff --git a/transport/vmess/vmess.go b/transport/vmess/vmess.go index ee7ce121..2dd071eb 100644 --- a/transport/vmess/vmess.go +++ b/transport/vmess/vmess.go @@ -7,7 +7,7 @@ import ( "github.com/Dreamacro/clash/common/utils" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" "github.com/zhangyunhao116/fastrand" ) diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 11b9c0cd..b5f65338 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -8,7 +8,7 @@ import ( "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" - "github.com/gofrs/uuid" + "github.com/gofrs/uuid/v5" "go.uber.org/atomic" ) From 99dfa4c73a24742c820b57b8311f18d9173cf9ae Mon Sep 17 00:00:00 2001 From: rookisbusy Date: Sun, 9 Apr 2023 19:00:45 +0800 Subject: [PATCH 176/530] fix: tun warn timeout --- listener/sing_tun/dns.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index f2daaf0c..e5ec82e2 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -6,6 +6,7 @@ import ( "io" "net" "net/netip" + "os" "sync" "time" @@ -117,7 +118,8 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. dest, err := conn.ReadPacket(buff) if err != nil { buff.Release() - if E.IsClosed(err) { + // ignore simple error + if err == os.ErrDeadlineExceeded || E.IsClosed(err) { break } return err From 20b0af9a03832fa015ba20469990e9e974ef6026 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 9 Apr 2023 19:15:32 +0800 Subject: [PATCH 177/530] chore: fix build --- adapter/outbound/shadowsocks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 1c64b3ca..ae4037dc 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -187,7 +187,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - pc = ss.method.DialPacketConn(&bufio.BindPacketConn{PacketConn: pc, Addr: addr}) + pc = ss.method.DialPacketConn(bufio.NewBindPacketConn(pc, addr)) return newPacketConn(pc, ss), nil } From 6c76312e5c6e836da256cbaf3da6a7297beaff83 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 9 Apr 2023 22:58:05 +0800 Subject: [PATCH 178/530] chore: Add read deadline implementation --- adapter/outbound/base.go | 4 ++-- common/net/sing.go | 15 +++++++++++++++ go.mod | 2 +- go.sum | 4 ++-- listener/shadowsocks/tcp.go | 3 ++- listener/shadowsocks/udp.go | 3 ++- 6 files changed, 24 insertions(+), 7 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 156bc114..f356ae2d 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -199,7 +199,7 @@ func (c *conn) Upstream() any { } func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { - return &conn{N.NewExtendedConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())} + return &conn{N.NewDeadlineConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())} } type packetConn struct { @@ -230,7 +230,7 @@ func (c *packetConn) LocalAddr() net.Addr { } func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn { - return &packetConn{pc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} + return &packetConn{N.NewDeadlinePacketConn(pc), []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} } func parseRemoteDestination(addr string) string { diff --git a/common/net/sing.go b/common/net/sing.go index 5c980738..4aad5523 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -6,6 +6,7 @@ import ( "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" + "github.com/sagernet/sing/common/bufio/deadline" "github.com/sagernet/sing/common/network" ) @@ -17,6 +18,20 @@ type ExtendedConn = network.ExtendedConn type ExtendedWriter = network.ExtendedWriter type ExtendedReader = network.ExtendedReader +func NewDeadlineConn(conn net.Conn) ExtendedConn { + if dc, ok := conn.(*deadline.Conn); ok { + return dc + } + return deadline.NewConn(conn) +} + +func NewDeadlinePacketConn(pc net.PacketConn) net.PacketConn { + if dpc, ok := pc.(*deadline.PacketConn); ok { + return dpc + } + return deadline.NewPacketConn(bufio.NewPacketConn(pc)) +} + func NeedHandshake(conn any) bool { if earlyConn, isEarlyConn := common.Cast[network.EarlyConn](conn); isEarlyConn && earlyConn.NeedHandshake() { return true diff --git a/go.mod b/go.mod index 275e9595..e7ceadf9 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( 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.2 + github.com/sagernet/sing v0.2.3-0.20230409094616-7f8eaee1b6c8 github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index 05dc5abe..38a2e16c 100644 --- a/go.sum +++ b/go.sum @@ -144,8 +144,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.2 h1:qfEdSLuwFgIIkeLOcwVQkVDzKLHtclXb93Ql0zZA+aE= -github.com/sagernet/sing v0.2.2/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.3-0.20230409094616-7f8eaee1b6c8 h1:BWQjek8tNzDzCeHh/8yvjfZ8Id0tl+6pJ+gcPI8tjl8= +github.com/sagernet/sing v0.2.3-0.20230409094616-7f8eaee1b6c8/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 h1:QnV79JbJbJGT0MJJfd8o7QMEfRu3eUVKsmahxFMonrc= github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661/go.mod h1:xCeSRP8cV32aPsY+6BbRdJjyD6q8ufdKwhgqxEbU/3U= github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 h1:ZArINfN+zcHMdZCeRFOm4rO3SWyvYuLg3VhWcA5zonc= diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index c0fd490f..4e25a7b9 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -5,6 +5,7 @@ import ( "strings" "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" LC "github.com/Dreamacro/clash/listener/config" "github.com/Dreamacro/clash/transport/shadowsocks/core" @@ -99,7 +100,7 @@ func (l *Listener) AddrList() (addrList []net.Addr) { } func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { - conn = l.pickCipher.StreamConn(conn) + conn = N.NewDeadlineConn(l.pickCipher.StreamConn(conn)) target, err := socks5.ReadAddr(conn, make([]byte, socks5.MaxAddrLen)) if err != nil { diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index 3f058406..d884c2b8 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -4,6 +4,7 @@ import ( "net" "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/common/sockopt" C "github.com/Dreamacro/clash/constant" @@ -29,7 +30,7 @@ func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UD } sl := &UDPListener{l, false} - conn := pickCipher.PacketConn(l) + conn := N.NewDeadlinePacketConn(pickCipher.PacketConn(l)) go func() { for { buf := pool.Get(pool.RelayBufferSize) From 1dbefc40c8a44744262c6d68e66c6c4620cf5c26 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 9 Apr 2023 23:06:56 +0800 Subject: [PATCH 179/530] chore: better error ignore --- listener/sing/sing.go | 10 +++++++++- listener/sing_tun/dns.go | 5 +---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 2a5a7d50..7421a4f1 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -103,7 +103,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. dest, err := conn.ReadPacket(buff) if err != nil { buff.Release() - if E.IsClosed(err) { + if ShouldIgnorePacketError(err) { break } return err @@ -128,6 +128,14 @@ func (h *ListenerHandler) NewError(ctx context.Context, err error) { log.Warnln("%s listener get error: %+v", h.Type.String(), err) } +func ShouldIgnorePacketError(err error) bool { + // ignore simple error + if E.IsTimeout(err) || E.IsClosed(err) || E.IsCanceled(err) { + return true + } + return false +} + type packet struct { conn *network.PacketConn mutex *sync.Mutex diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index e5ec82e2..dc33be91 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -6,7 +6,6 @@ import ( "io" "net" "net/netip" - "os" "sync" "time" @@ -18,7 +17,6 @@ import ( D "github.com/miekg/dns" "github.com/sagernet/sing/common/buf" - E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/network" ) @@ -118,8 +116,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. dest, err := conn.ReadPacket(buff) if err != nil { buff.Release() - // ignore simple error - if err == os.ErrDeadlineExceeded || E.IsClosed(err) { + if sing.ShouldIgnorePacketError(err) { break } return err From 87b9e3d977c4ae3dc8368e3a81908fd995ca5ba4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 10 Apr 2023 08:54:10 +0800 Subject: [PATCH 180/530] feat: wireguard add `dialer-proxy` config to support chain forwarding --- adapter/outbound/wireguard.go | 27 ++++++++-- adapter/outboundgroup/relay.go | 46 ++-------------- adapter/outboundgroup/util.go | 27 ---------- component/proxydialer/proxydialer.go | 78 ++++++++++++++++++++++++++++ docs/config.yaml | 2 + 5 files changed, 106 insertions(+), 74 deletions(-) create mode 100644 component/proxydialer/proxydialer.go diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index f136a20a..834e5fe2 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -15,6 +15,7 @@ import ( CN "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" @@ -48,6 +49,7 @@ type WireGuardOption struct { MTU int `proxy:"mtu,omitempty"` UDP bool `proxy:"udp,omitempty"` PersistentKeepalive int `proxy:"persistent-keepalive,omitempty"` + DialerProxy string `proxy:"dialer-proxy,omitempty"` Peers []WireGuardPeerOption `proxy:"peers,omitempty"` } @@ -64,17 +66,34 @@ type WireGuardPeerOption struct { } type wgSingDialer struct { - dialer dialer.Dialer + dialer dialer.Dialer + proxyName string } var _ N.Dialer = (*wgSingDialer)(nil) func (d *wgSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - return d.dialer.DialContext(ctx, network, destination.String()) + var cDialer C.Dialer = d.dialer + if len(d.proxyName) > 0 { + pd, err := proxydialer.NewByName(d.proxyName, d.dialer) + if err != nil { + return nil, err + } + cDialer = pd + } + return cDialer.DialContext(ctx, network, destination.String()) } func (d *wgSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - return d.dialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) + var cDialer C.Dialer = d.dialer + if len(d.proxyName) > 0 { + pd, err := proxydialer.NewByName(d.proxyName, d.dialer) + if err != nil { + return nil, err + } + cDialer = pd + } + return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) } type wgNetDialer struct { @@ -130,7 +149,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, - dialer: &wgSingDialer{dialer: dialer.NewDialer()}, + dialer: &wgSingDialer{dialer: dialer.NewDialer(), proxyName: option.DialerProxy}, } runtime.SetFinalizer(outbound, closeWireGuard) diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go index e17ae132..74c2f73b 100644 --- a/adapter/outboundgroup/relay.go +++ b/adapter/outboundgroup/relay.go @@ -3,13 +3,9 @@ package outboundgroup import ( "context" "encoding/json" - "net" - "net/netip" - "strings" - "github.com/Dreamacro/clash/adapter/outbound" - N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/proxydialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" ) @@ -18,36 +14,6 @@ type Relay struct { *GroupBase } -type proxyDialer struct { - proxy C.Proxy - dialer C.Dialer -} - -func (p proxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { - currentMeta, err := addrToMetadata(address) - if err != nil { - return nil, err - } - if strings.Contains(network, "udp") { // should not support this operation - currentMeta.NetWork = C.UDP - pc, err := p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) - if err != nil { - return nil, err - } - return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil - } - return p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) -} - -func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { - currentMeta, err := addrToMetadata(rAddrPort.String()) - if err != nil { - return nil, err - } - currentMeta.NetWork = C.UDP - return p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) -} - // DialContext implements C.ProxyAdapter func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { proxies, chainProxies := r.proxies(metadata, true) @@ -61,10 +27,7 @@ func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d var d C.Dialer d = dialer.NewDialer(r.Base.DialOptions(opts...)...) for _, proxy := range proxies[:len(proxies)-1] { - d = proxyDialer{ - proxy: proxy, - dialer: d, - } + d = proxydialer.New(proxy, d) } last := proxies[len(proxies)-1] conn, err := last.DialContextWithDialer(ctx, d, metadata) @@ -95,10 +58,7 @@ func (r *Relay) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o var d C.Dialer d = dialer.NewDialer(r.Base.DialOptions(opts...)...) for _, proxy := range proxies[:len(proxies)-1] { - d = proxyDialer{ - proxy: proxy, - dialer: d, - } + d = proxydialer.New(proxy, d) } last := proxies[len(proxies)-1] pc, err := last.ListenPacketWithDialer(ctx, d, metadata) diff --git a/adapter/outboundgroup/util.go b/adapter/outboundgroup/util.go index 578011f8..adcda1aa 100644 --- a/adapter/outboundgroup/util.go +++ b/adapter/outboundgroup/util.go @@ -1,37 +1,10 @@ package outboundgroup import ( - "fmt" "net" - "net/netip" "time" - - C "github.com/Dreamacro/clash/constant" ) -func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { - host, port, err := net.SplitHostPort(rawAddress) - if err != nil { - err = fmt.Errorf("addrToMetadata failed: %w", err) - return - } - - if ip, err := netip.ParseAddr(host); err != nil { - addr = &C.Metadata{ - Host: host, - DstPort: port, - } - } else { - addr = &C.Metadata{ - Host: "", - DstIP: ip.Unmap(), - DstPort: port, - } - } - - return -} - func tcpKeepAlive(c net.Conn) { if tcp, ok := c.(*net.TCPConn); ok { _ = tcp.SetKeepAlive(true) diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go new file mode 100644 index 00000000..83428d59 --- /dev/null +++ b/component/proxydialer/proxydialer.go @@ -0,0 +1,78 @@ +package proxydialer + +import ( + "context" + "fmt" + "net" + "net/netip" + "strings" + + N "github.com/Dreamacro/clash/common/net" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/tunnel" +) + +type proxyDialer struct { + proxy C.Proxy + dialer C.Dialer +} + +func New(proxy C.Proxy, dialer C.Dialer) C.Dialer { + return proxyDialer{proxy: proxy, dialer: dialer} +} + +func NewByName(proxyName string, dialer C.Dialer) (C.Dialer, error) { + proxies := tunnel.Proxies() + if proxy, ok := proxies[proxyName]; ok { + return New(proxy, dialer), nil + } + return nil, fmt.Errorf("proxyName[%s] not found", proxyName) +} + +func (p proxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { + currentMeta, err := addrToMetadata(address) + if err != nil { + return nil, err + } + if strings.Contains(network, "udp") { // using in wireguard outbound + currentMeta.NetWork = C.UDP + pc, err := p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + if err != nil { + return nil, err + } + return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil + } + return p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) +} + +func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { + currentMeta, err := addrToMetadata(rAddrPort.String()) + if err != nil { + return nil, err + } + currentMeta.NetWork = C.UDP + return p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) +} + +func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { + host, port, err := net.SplitHostPort(rawAddress) + if err != nil { + err = fmt.Errorf("addrToMetadata failed: %w", err) + return + } + + if ip, err := netip.ParseAddr(host); err != nil { + addr = &C.Metadata{ + Host: host, + DstPort: port, + } + } else { + addr = &C.Metadata{ + Host: "", + DstIP: ip.Unmap(), + DstPort: port, + } + } + + return +} diff --git a/docs/config.yaml b/docs/config.yaml index 66eff537..11891478 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -629,6 +629,8 @@ proxies: # socks5 reserved: "U4An" # 数组格式也是合法的 # reserved: [209,98,59] + # 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出连接 + # dialer-proxy: "ss1" # 如果peers不为空,该段落中的allowed_ips不可为空;前面段落的server,port,ip,ipv6,public-key,pre-shared-key均会被忽略,但private-key会被保留且只能在顶层指定 # peers: # - server: 162.159.192.1 From 2c48d2da3fdace9fc36f5bf9d9971cda47bfd9cf Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 10 Apr 2023 10:13:36 +0800 Subject: [PATCH 181/530] chore: clarify the wireguard logging --- adapter/outbound/wireguard.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 834e5fe2..2eb56210 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -285,14 +285,14 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { } outbound.device = device.NewDevice(outbound.tunDevice, outbound.bind, &device.Logger{ Verbosef: func(format string, args ...interface{}) { - log.SingLogger.Debug(fmt.Sprintf(strings.ToLower(format), args...)) + log.SingLogger.Debug(fmt.Sprintf("[WG](%s) %s", option.Name, fmt.Sprintf(format, args...))) }, Errorf: func(format string, args ...interface{}) { - log.SingLogger.Error(fmt.Sprintf(strings.ToLower(format), args...)) + log.SingLogger.Error(fmt.Sprintf("[WG](%s) %s", option.Name, fmt.Sprintf(format, args...))) }, }, option.Workers) if debug.Enabled { - log.SingLogger.Trace("created wireguard ipc conf: \n", ipcConf) + log.SingLogger.Trace(fmt.Sprintf("[WG](%s) created wireguard ipc conf: \n %s", option.Name, ipcConf)) } err = outbound.device.IpcSet(ipcConf) if err != nil { From 9afcb7071ff59c9992468f81d248587f6faa8b53 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 10 Apr 2023 11:20:28 +0800 Subject: [PATCH 182/530] feat: support `dialer-proxy` config for all outbound --- adapter/outbound/base.go | 1 + adapter/outbound/http.go | 7 ++++++ adapter/outbound/hysteria.go | 42 ++++++++++++++++++-------------- adapter/outbound/shadowsocks.go | 13 ++++++++++ adapter/outbound/shadowsocksr.go | 15 ++++++++++++ adapter/outbound/snell.go | 26 +++++++++++++++++++- adapter/outbound/socks5.go | 18 +++++++++++++- adapter/outbound/trojan.go | 23 ++++++++++++++++- adapter/outbound/tuic.go | 9 +++++++ adapter/outbound/vless.go | 23 ++++++++++++++++- adapter/outbound/vmess.go | 23 ++++++++++++++++- adapter/outbound/wireguard.go | 1 - 12 files changed, 177 insertions(+), 24 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index f356ae2d..76f9bd39 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -146,6 +146,7 @@ type BasicOption struct { 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"` + DialerProxy string `proxy:"dialer-proxy,omitempty"` // don't apply this option into groups, but can set a group name in a proxy } type BaseOption struct { diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 6a668ebb..645177a4 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -14,6 +14,7 @@ import ( "strconv" "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" ) @@ -66,6 +67,12 @@ func (h *Http) DialContext(ctx context.Context, metadata *C.Metadata, opts ...di // DialContextWithDialer implements C.ProxyAdapter func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + if len(h.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(h.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", h.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", h.addr, err) diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index bd75cc3c..6024ea10 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -20,6 +20,7 @@ import ( M "github.com/sagernet/sing/common/metadata" "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/log" @@ -28,6 +29,7 @@ import ( "github.com/Dreamacro/clash/transport/hysteria/obfs" "github.com/Dreamacro/clash/transport/hysteria/pmtud_fix" "github.com/Dreamacro/clash/transport/hysteria/transport" + "github.com/Dreamacro/clash/transport/hysteria/utils" ) const ( @@ -46,21 +48,12 @@ var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`) type Hysteria struct { *Base + option *HysteriaOption client *core.Client } func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { - hdc := hyDialerWithContext{ - ctx: context.Background(), - hyDialer: func(network string) (net.PacketConn, error) { - return dialer.ListenPacket(ctx, network, "", h.Base.DialOptions(opts...)...) - }, - remoteAddr: func(addr string) (net.Addr, error) { - return resolveUDPAddrWithPrefer(ctx, "udp", addr, h.prefer) - }, - } - - tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), &hdc) + tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), h.genHdc(ctx, opts...)) if err != nil { return nil, err } @@ -69,20 +62,32 @@ func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts . } func (h *Hysteria) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { - hdc := hyDialerWithContext{ + udpConn, err := h.client.DialUDP(h.genHdc(ctx, opts...)) + if err != nil { + return nil, err + } + return newPacketConn(&hyPacketConn{udpConn}, h), nil +} + +func (h *Hysteria) genHdc(ctx context.Context, opts ...dialer.Option) utils.PacketDialer { + return &hyDialerWithContext{ ctx: context.Background(), hyDialer: func(network string) (net.PacketConn, error) { - return dialer.ListenPacket(ctx, network, "", h.Base.DialOptions(opts...)...) + var err error + var cDialer C.Dialer = dialer.NewDialer(h.Base.DialOptions(opts...)...) + if len(h.option.DialerProxy) > 0 { + cDialer, err = proxydialer.NewByName(h.option.DialerProxy, cDialer) + if err != nil { + return nil, err + } + } + rAddrPort, _ := netip.ParseAddrPort(h.Addr()) + return cDialer.ListenPacket(ctx, network, "", rAddrPort) }, remoteAddr: func(addr string) (net.Addr, error) { return resolveUDPAddrWithPrefer(ctx, "udp", addr, h.prefer) }, } - udpConn, err := h.client.DialUDP(&hdc) - if err != nil { - return nil, err - } - return newPacketConn(&hyPacketConn{udpConn}, h), nil } type HysteriaOption struct { @@ -258,6 +263,7 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, + option: &option, client: client, }, nil } diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index ae4037dc..ac4cc31e 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -11,6 +11,7 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/proxydialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/restls" obfs "github.com/Dreamacro/clash/transport/simple-obfs" @@ -145,6 +146,12 @@ func (ss *ShadowSocks) DialContext(ctx context.Context, metadata *C.Metadata, op // DialContextWithDialer implements C.ProxyAdapter func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + if len(ss.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", ss.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) @@ -166,6 +173,12 @@ func (ss *ShadowSocks) ListenPacketContext(ctx context.Context, metadata *C.Meta // ListenPacketWithDialer implements C.ProxyAdapter func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { + if len(ss.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } if ss.option.UDPOverTCP { tcpConn, err := ss.DialContextWithDialer(ctx, dialer, metadata) if err != nil { diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 135e7132..e96116d4 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -7,6 +7,7 @@ import ( "strconv" "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/proxydialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/shadowsocks/core" "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" @@ -17,6 +18,7 @@ import ( type ShadowSocksR struct { *Base + option *ShadowSocksROption cipher core.Cipher obfs obfs.Obfs protocol protocol.Protocol @@ -65,6 +67,12 @@ func (ssr *ShadowSocksR) DialContext(ctx context.Context, metadata *C.Metadata, // DialContextWithDialer implements C.ProxyAdapter func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + if len(ssr.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(ssr.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", ssr.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err) @@ -86,6 +94,12 @@ func (ssr *ShadowSocksR) ListenPacketContext(ctx context.Context, metadata *C.Me // ListenPacketWithDialer implements C.ProxyAdapter func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { + if len(ssr.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(ssr.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ssr.addr, ssr.prefer) if err != nil { return nil, err @@ -168,6 +182,7 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, + option: &option, cipher: coreCiph, obfs: obfs, protocol: protocol, diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index d6f1efee..d6d0436d 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -8,6 +8,7 @@ import ( "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/proxydialer" C "github.com/Dreamacro/clash/constant" obfs "github.com/Dreamacro/clash/transport/simple-obfs" "github.com/Dreamacro/clash/transport/snell" @@ -15,6 +16,7 @@ import ( type Snell struct { *Base + option *SnellOption psk []byte pool *snell.Pool obfsOption *simpleObfsOption @@ -83,6 +85,12 @@ func (s *Snell) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d // DialContextWithDialer implements C.ProxyAdapter func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + if len(s.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(s.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", s.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", s.addr, err) @@ -104,6 +112,13 @@ func (s *Snell) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o // ListenPacketWithDialer implements C.ProxyAdapter func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (C.PacketConn, error) { + var err error + if len(s.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(s.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", s.addr) if err != nil { return nil, err @@ -172,6 +187,7 @@ func NewSnell(option SnellOption) (*Snell, error) { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, + option: &option, psk: psk, obfsOption: obfsOption, version: option.Version, @@ -179,7 +195,15 @@ func NewSnell(option SnellOption) (*Snell, error) { if option.Version == snell.Version2 { s.pool = snell.NewPool(func(ctx context.Context) (*snell.Snell, error) { - c, err := dialer.DialContext(ctx, "tcp", addr, s.Base.DialOptions()...) + var err error + var cDialer C.Dialer = dialer.NewDialer(s.Base.DialOptions()...) + if len(s.option.DialerProxy) > 0 { + cDialer, err = proxydialer.NewByName(s.option.DialerProxy, cDialer) + if err != nil { + return nil, err + } + } + c, err := cDialer.DialContext(ctx, "tcp", addr) if err != nil { return nil, err } diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index cdb89cc2..b328b634 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -10,6 +10,7 @@ import ( "strconv" "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/socks5" @@ -17,6 +18,7 @@ import ( type Socks5 struct { *Base + option *Socks5Option user string pass string tls bool @@ -70,6 +72,12 @@ func (ss *Socks5) DialContext(ctx context.Context, metadata *C.Metadata, opts .. // DialContextWithDialer implements C.ProxyAdapter func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + if len(ss.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", ss.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) @@ -95,7 +103,14 @@ func (ss *Socks5) SupportWithDialer() bool { // ListenPacketContext implements C.ProxyAdapter func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { - c, err := dialer.DialContext(ctx, "tcp", ss.addr, ss.Base.DialOptions(opts...)...) + var cDialer C.Dialer = dialer.NewDialer(ss.Base.DialOptions(opts...)...) + if len(ss.option.DialerProxy) > 0 { + cDialer, err = proxydialer.NewByName(ss.option.DialerProxy, cDialer) + if err != nil { + return nil, err + } + } + c, err := cDialer.DialContext(ctx, "tcp", ss.addr) if err != nil { err = fmt.Errorf("%s connect error: %w", ss.addr, err) return @@ -187,6 +202,7 @@ func NewSocks5(option Socks5Option) (*Socks5, error) { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, + option: &option, user: option.UserName, pass: option.Password, tls: option.TLS, diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 4a31538b..013164c4 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -9,6 +9,7 @@ import ( "strconv" "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/gun" @@ -134,6 +135,12 @@ func (t *Trojan) DialContext(ctx context.Context, metadata *C.Metadata, opts ... // DialContextWithDialer implements C.ProxyAdapter func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + if len(t.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", t.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) @@ -178,6 +185,12 @@ func (t *Trojan) ListenPacketContext(ctx context.Context, metadata *C.Metadata, // ListenPacketWithDialer implements C.ProxyAdapter func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { + if len(t.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", t.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) @@ -270,7 +283,15 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { if option.Network == "grpc" { dialFn := func(network, addr string) (net.Conn, error) { - c, err := dialer.DialContext(context.Background(), "tcp", t.addr, t.Base.DialOptions()...) + var err error + var cDialer C.Dialer = dialer.NewDialer(t.Base.DialOptions()...) + if len(t.option.DialerProxy) > 0 { + cDialer, err = proxydialer.NewByName(t.option.DialerProxy, cDialer) + if err != nil { + return nil, err + } + } + c, err := cDialer.DialContext(context.Background(), "tcp", t.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", t.addr, err.Error()) } diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index d2f2b5e9..6640c46a 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -16,6 +16,7 @@ import ( "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" @@ -23,6 +24,7 @@ import ( type Tuic struct { *Base + option *TuicOption client *tuic.PoolClient } @@ -93,6 +95,12 @@ func (t *Tuic) dial(ctx context.Context, opts ...dialer.Option) (pc net.PacketCo } func (t *Tuic) dialWithDialer(ctx context.Context, dialer C.Dialer) (pc net.PacketConn, addr net.Addr, err error) { + if len(t.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(t.option.DialerProxy, dialer) + if err != nil { + return nil, nil, err + } + } udpAddr, err := resolveUDPAddrWithPrefer(ctx, "udp", t.addr, t.prefer) if err != nil { return nil, nil, err @@ -230,6 +238,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, + option: &option, } clientMaxOpenStreams := int64(option.MaxOpenStreams) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 757661cc..b5ae66e1 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -14,6 +14,7 @@ import ( "github.com/Dreamacro/clash/common/convert" "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" @@ -238,6 +239,12 @@ func (v *Vless) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d // DialContextWithDialer implements C.ProxyAdapter func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + if len(v.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) @@ -297,6 +304,12 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o // ListenPacketWithDialer implements C.ProxyAdapter func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { + if len(v.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } // vless use stream-oriented udp with a special address, so we need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) @@ -538,7 +551,15 @@ func NewVless(option VlessOption) (*Vless, error) { } case "grpc": dialFn := func(network, addr string) (net.Conn, error) { - c, err := dialer.DialContext(context.Background(), "tcp", v.addr, v.Base.DialOptions()...) + var err error + var cDialer C.Dialer = dialer.NewDialer(v.Base.DialOptions()...) + if len(v.option.DialerProxy) > 0 { + cDialer, err = proxydialer.NewByName(v.option.DialerProxy, cDialer) + if err != nil { + return nil, err + } + } + c, err := cDialer.DialContext(context.Background(), "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 5bb46dad..048b381c 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -13,6 +13,7 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" @@ -263,6 +264,12 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d // DialContextWithDialer implements C.ProxyAdapter func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { + if len(v.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } c, err := dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) @@ -329,6 +336,12 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o // ListenPacketWithDialer implements C.ProxyAdapter func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { + if len(v.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(v.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) @@ -428,7 +441,15 @@ func NewVmess(option VmessOption) (*Vmess, error) { } case "grpc": dialFn := func(network, addr string) (net.Conn, error) { - c, err := dialer.DialContext(context.Background(), "tcp", v.addr, v.Base.DialOptions()...) + var err error + var cDialer C.Dialer = dialer.NewDialer(v.Base.DialOptions()...) + if len(v.option.DialerProxy) > 0 { + cDialer, err = proxydialer.NewByName(v.option.DialerProxy, cDialer) + if err != nil { + return nil, err + } + } + c, err := cDialer.DialContext(context.Background(), "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 2eb56210..9a302de5 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -49,7 +49,6 @@ type WireGuardOption struct { MTU int `proxy:"mtu,omitempty"` UDP bool `proxy:"udp,omitempty"` PersistentKeepalive int `proxy:"persistent-keepalive,omitempty"` - DialerProxy string `proxy:"dialer-proxy,omitempty"` Peers []WireGuardPeerOption `proxy:"peers,omitempty"` } From 4d12ed491cd23c99a56d61961640b6f2c40b9794 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 10 Apr 2023 12:22:12 +0800 Subject: [PATCH 183/530] fix: tuic pool client should only cache the system's UDPConn --- transport/tuic/pool_client.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/transport/tuic/pool_client.go b/transport/tuic/pool_client.go index fe06c2f3..04ada7c0 100644 --- a/transport/tuic/pool_client.go +++ b/transport/tuic/pool_client.go @@ -67,11 +67,14 @@ func (t *PoolClient) dial(ctx context.Context, dialer C.Dialer, dialFn DialFunc) return nil, nil, err } - dr.pc, dr.addr, dr.err = pc, addr, err + if _, ok := pc.(*net.UDPConn); ok { // only cache the system's UDPConn + dr.pc, dr.addr, dr.err = pc, addr, err + + t.dialResultMutex.Lock() + t.dialResultMap[dialer] = dr + t.dialResultMutex.Unlock() + } - t.dialResultMutex.Lock() - t.dialResultMap[dialer] = dr - t.dialResultMutex.Unlock() return pc, addr, err } From 304b4d9bcba30800a282894447fab4bf51c47d85 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:03:31 +0800 Subject: [PATCH 184/530] chore: download geoX use inner --- component/geodata/init.go | 18 +++++++++++++----- component/mmdb/mmdb.go | 10 ++++++++-- config/updateGeo.go | 17 ++++++++++++----- 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/component/geodata/init.go b/component/geodata/init.go index f7dd7a9e..acae1a34 100644 --- a/component/geodata/init.go +++ b/component/geodata/init.go @@ -1,13 +1,17 @@ package geodata import ( + "context" "fmt" - "github.com/Dreamacro/clash/component/mmdb" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" "io" "net/http" "os" + "time" + + clashHttp "github.com/Dreamacro/clash/component/http" + "github.com/Dreamacro/clash/component/mmdb" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" ) var initGeoSite bool @@ -38,7 +42,9 @@ func InitGeoSite() error { } func downloadGeoSite(path string) (err error) { - resp, err := http.Get(C.GeoSiteUrl) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) + defer cancel() + resp, err := clashHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) if err != nil { return } @@ -55,7 +61,9 @@ func downloadGeoSite(path string) (err error) { } func downloadGeoIP(path string) (err error) { - resp, err := http.Get(C.GeoIpUrl) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) + defer cancel() + resp, err := clashHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) if err != nil { return } diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go index 8f28d486..14f6f997 100644 --- a/component/mmdb/mmdb.go +++ b/component/mmdb/mmdb.go @@ -1,14 +1,18 @@ package mmdb import ( - "github.com/oschwald/geoip2-golang" + "context" "io" "net/http" "os" "sync" + "time" + clashHttp "github.com/Dreamacro/clash/component/http" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" + + "github.com/oschwald/geoip2-golang" ) var ( @@ -47,7 +51,9 @@ func Instance() *geoip2.Reader { } func DownloadMMDB(path string) (err error) { - resp, err := http.Get(C.MmdbUrl) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) + defer cancel() + resp, err := clashHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) if err != nil { return } diff --git a/config/updateGeo.go b/config/updateGeo.go index 698bd52d..e76301ba 100644 --- a/config/updateGeo.go +++ b/config/updateGeo.go @@ -1,15 +1,20 @@ package config import ( + "context" "fmt" - "github.com/Dreamacro/clash/component/geodata" - _ "github.com/Dreamacro/clash/component/geodata/standard" - C "github.com/Dreamacro/clash/constant" - "github.com/oschwald/geoip2-golang" "io" "net/http" "os" "runtime" + "time" + + "github.com/Dreamacro/clash/component/geodata" + _ "github.com/Dreamacro/clash/component/geodata/standard" + clashHttp "github.com/Dreamacro/clash/component/http" + C "github.com/Dreamacro/clash/constant" + + "github.com/oschwald/geoip2-golang" ) func UpdateGeoDatabases() error { @@ -69,7 +74,9 @@ func UpdateGeoDatabases() error { } func downloadForBytes(url string) ([]byte, error) { - resp, err := http.Get(url) + ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) + defer cancel() + resp, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) if err != nil { return nil, err } From ecdde647b176f702258abd7165747f771a0a1ed9 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:13:23 +0800 Subject: [PATCH 185/530] chore: cleanup listener before restart --- hub/route/restart.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hub/route/restart.go b/hub/route/restart.go index 69b4f5b8..6c3f27f3 100644 --- a/hub/route/restart.go +++ b/hub/route/restart.go @@ -8,6 +8,7 @@ import ( "runtime" "syscall" + "github.com/Dreamacro/clash/listener" "github.com/Dreamacro/clash/log" "github.com/go-chi/chi/v5" @@ -43,7 +44,7 @@ func restart(w http.ResponseWriter, r *http.Request) { func runRestart(execPath string) { var err error - + listener.Cleanup(false) if runtime.GOOS == "windows" { cmd := exec.Command(execPath, os.Args[1:]...) log.Infoln("restarting: %q %q", execPath, os.Args[1:]) From ab3fce29ab88ec113ce7a75f0937bf983c49f696 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 11 Apr 2023 10:29:55 +0800 Subject: [PATCH 186/530] feat: wireguard add `remote-dns-resolve` and `dns` settings --- adapter/outbound/wireguard.go | 44 ++++++++++++++++++++++++++++++--- config/config.go | 24 +++++++++++------- dns/client.go | 11 +++++---- dns/doh.go | 28 ++++++++++++--------- dns/doq.go | 15 +++++++----- dns/resolver.go | 7 ++++-- dns/util.go | 46 ++++++++++++++++++++--------------- docs/config.yaml | 2 ++ 8 files changed, 121 insertions(+), 56 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 9a302de5..0070ce46 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -18,6 +18,7 @@ import ( "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/dns" "github.com/Dreamacro/clash/log" wireguard "github.com/metacubex/sing-wireguard" @@ -38,6 +39,7 @@ type WireGuard struct { dialer *wgSingDialer startOnce sync.Once startErr error + resolver *dns.Resolver } type WireGuardOption struct { @@ -51,6 +53,9 @@ type WireGuardOption struct { PersistentKeepalive int `proxy:"persistent-keepalive,omitempty"` Peers []WireGuardPeerOption `proxy:"peers,omitempty"` + + RemoteDnsResolve bool `proxy:"remote-dns-resolve,omitempty"` + Dns []string `proxy:"dns,omitempty"` } type WireGuardPeerOption struct { @@ -298,6 +303,29 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { return nil, E.Cause(err, "setup wireguard") } //err = outbound.tunDevice.Start() + + var has6 bool + for _, address := range localPrefixes { + if !address.Addr().Unmap().Is4() { + has6 = true + break + } + } + + if option.RemoteDnsResolve && len(option.Dns) > 0 { + nss, err := dns.ParseNameServer(option.Dns) + if err != nil { + return nil, err + } + for i := range nss { + nss[i].ProxyAdapter = outbound + } + outbound.resolver = dns.NewResolver(dns.Config{ + Main: nss, + IPv6: has6, + }) + } + return outbound, nil } @@ -318,8 +346,12 @@ func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts if w.startErr != nil { return nil, w.startErr } - if !metadata.Resolved() { - options = append(options, dialer.WithResolver(resolver.DefaultResolver)) + if !metadata.Resolved() || w.resolver != nil { + r := resolver.DefaultResolver + if w.resolver != nil { + r = w.resolver + } + options = append(options, dialer.WithResolver(r)) options = append(options, dialer.WithNetDialer(wgNetDialer{tunDevice: w.tunDevice})) conn, err = dialer.NewDialer(options...).DialContext(ctx, "tcp", metadata.RemoteAddress()) } else { @@ -348,8 +380,12 @@ func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadat if err != nil { return nil, err } - if !metadata.Resolved() { - ip, err := resolver.ResolveIP(ctx, metadata.Host) + if (!metadata.Resolved() || w.resolver != nil) && metadata.Host != "" { + r := resolver.DefaultResolver + if w.resolver != nil { + r = w.resolver + } + ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r) if err != nil { return nil, errors.New("can't resolve ip") } diff --git a/config/config.go b/config/config.go index e7720c40..24594ee2 100644 --- a/config/config.go +++ b/config/config.go @@ -896,7 +896,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) return nil, fmt.Errorf("DNS NameServer[%d] format error: %s", idx, err.Error()) } - proxyAdapter := u.Fragment + proxyName := u.Fragment var addr, dnsNetType string params := map[string]string{} @@ -913,7 +913,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) case "https": addr, err = hostWithDefaultPort(u.Host, "443") if err == nil { - proxyAdapter = "" + proxyName = "" clearURL := url.URL{Scheme: "https", Host: addr, Path: u.Path} addr = clearURL.String() dnsNetType = "https" // DNS over HTTPS @@ -923,7 +923,7 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) if len(arr) == 0 { continue } else if len(arr) == 1 { - proxyAdapter = arr[0] + proxyName = arr[0] } else if len(arr) == 2 { params[arr[0]] = arr[1] } else { @@ -949,18 +949,24 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) nameservers = append( nameservers, dns.NameServer{ - Net: dnsNetType, - Addr: addr, - ProxyAdapter: proxyAdapter, - Interface: dialer.DefaultInterface, - Params: params, - PreferH3: preferH3, + Net: dnsNetType, + Addr: addr, + ProxyName: proxyName, + Interface: dialer.DefaultInterface, + Params: params, + PreferH3: preferH3, }, ) } return nameservers, nil } +func init() { + dns.ParseNameServer = func(servers []string) ([]dns.NameServer, error) { // using by wireguard + return parseNameServer(servers, false) + } +} + func parsePureDNSServer(server string) string { addPre := func(server string) string { return "udp://" + server diff --git a/dns/client.go b/dns/client.go index 936a5882..637207f3 100644 --- a/dns/client.go +++ b/dns/client.go @@ -8,14 +8,14 @@ import ( "net/netip" "strings" - tlsC "github.com/Dreamacro/clash/component/tls" - "go.uber.org/atomic" - "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" + tlsC "github.com/Dreamacro/clash/component/tls" + C "github.com/Dreamacro/clash/constant" D "github.com/miekg/dns" "github.com/zhangyunhao116/fastrand" + "go.uber.org/atomic" ) type client struct { @@ -24,7 +24,8 @@ type client struct { port string host string iface *atomic.String - proxyAdapter string + proxyAdapter C.ProxyAdapter + proxyName string addr string } @@ -81,7 +82,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) options = append(options, dialer.WithInterface(c.iface.Load())) } - conn, err := getDialHandler(c.r, c.proxyAdapter, options...)(ctx, network, net.JoinHostPort(ip.String(), c.port)) + conn, err := getDialHandler(c.r, c.proxyAdapter, c.proxyName, options...)(ctx, network, net.JoinHostPort(ip.String(), c.port)) if err != nil { return nil, err } diff --git a/dns/doh.go b/dns/doh.go index 1e6528d9..dd8ba435 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -21,6 +21,7 @@ import ( "github.com/metacubex/quic-go" "github.com/metacubex/quic-go/http3" D "github.com/miekg/dns" + "golang.org/x/exp/slices" "golang.org/x/net/http2" ) @@ -63,7 +64,8 @@ type dnsOverHTTPS struct { url *url.URL r *Resolver httpVersions []C.HTTPVersion - proxyAdapter string + proxyAdapter C.ProxyAdapter + proxyName string addr string } @@ -71,7 +73,7 @@ type dnsOverHTTPS struct { var _ dnsClient = (*dnsOverHTTPS)(nil) // newDoH returns the DNS-over-HTTPS Upstream. -func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[string]string, proxyAdapter string) dnsClient { +func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[string]string, proxyAdapter C.ProxyAdapter, proxyName string) dnsClient { u, _ := url.Parse(urlString) httpVersions := DefaultHTTPVersions if preferH3 { @@ -87,6 +89,7 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin addr: u.String(), r: r, proxyAdapter: proxyAdapter, + proxyName: proxyName, quicConfig: &quic.Config{ KeepAlivePeriod: QUICKeepAlivePeriod, TokenStore: newQUICTokenStore(), @@ -390,14 +393,17 @@ func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripp nextProtos = append(nextProtos, string(v)) } tlsConfig.NextProtos = nextProtos - dialContext := getDialHandler(doh.r, doh.proxyAdapter) - // First, we attempt to create an HTTP3 transport. If the probe QUIC - // connection is established successfully, we'll be using HTTP3 for this - // upstream. - transportH3, err := doh.createTransportH3(ctx, tlsConfig, dialContext) - if err == nil { - log.Debugln("[%s] using HTTP/3 for this upstream: QUIC was faster", doh.url.String()) - return transportH3, nil + dialContext := getDialHandler(doh.r, doh.proxyAdapter, doh.proxyName) + + if slices.Contains(doh.httpVersions, C.HTTPVersion3) { + // First, we attempt to create an HTTP3 transport. If the probe QUIC + // connection is established successfully, we'll be using HTTP3 for this + // upstream. + transportH3, err := doh.createTransportH3(ctx, tlsConfig, dialContext) + if err == nil { + log.Debugln("[%s] using HTTP/3 for this upstream: QUIC was faster", doh.url.String()) + return transportH3, nil + } } log.Debugln("[%s] using HTTP/2 for this upstream: %v", doh.url.String(), err) @@ -533,7 +539,7 @@ func (doh *dnsOverHTTPS) dialQuic(ctx context.Context, addr string, tlsCfg *tls. IP: net.ParseIP(ip), Port: portInt, } - conn, err := listenPacket(ctx, doh.proxyAdapter, "udp", addr, doh.r) + conn, err := listenPacket(ctx, doh.proxyAdapter, doh.proxyName, "udp", addr, doh.r) if err != nil { return nil, err } diff --git a/dns/doq.go b/dns/doq.go index 1354f177..73310340 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -13,9 +13,10 @@ import ( "time" tlsC "github.com/Dreamacro/clash/component/tls" + C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/log" "github.com/metacubex/quic-go" - "github.com/Dreamacro/clash/log" D "github.com/miekg/dns" ) @@ -60,7 +61,8 @@ type dnsOverQUIC struct { bytesPoolGuard sync.Mutex addr string - proxyAdapter string + proxyAdapter C.ProxyAdapter + proxyName string r *Resolver } @@ -68,10 +70,11 @@ type dnsOverQUIC struct { var _ dnsClient = (*dnsOverQUIC)(nil) // newDoQ returns the DNS-over-QUIC Upstream. -func newDoQ(resolver *Resolver, addr string, adapter string) (dnsClient, error) { +func newDoQ(resolver *Resolver, addr string, proxyAdapter C.ProxyAdapter, proxyName string) (dnsClient, error) { doq := &dnsOverQUIC{ addr: addr, - proxyAdapter: adapter, + proxyAdapter: proxyAdapter, + proxyName: proxyName, r: resolver, quicConfig: &quic.Config{ KeepAlivePeriod: QUICKeepAlivePeriod, @@ -310,7 +313,7 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connectio // 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). - rawConn, err := getDialHandler(doq.r, doq.proxyAdapter)(ctx, "udp", doq.addr) + rawConn, err := getDialHandler(doq.r, doq.proxyAdapter, doq.proxyName)(ctx, "udp", doq.addr) if err != nil { return nil, fmt.Errorf("failed to open a QUIC connection: %w", err) } @@ -325,7 +328,7 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connectio p, err := strconv.Atoi(port) udpAddr := net.UDPAddr{IP: net.ParseIP(ip), Port: p} - udp, err := listenPacket(ctx, doq.proxyAdapter, "udp", addr, doq.r) + udp, err := listenPacket(ctx, doq.proxyAdapter, doq.proxyName, "udp", addr, doq.r) if err != nil { return nil, err } diff --git a/dns/resolver.go b/dns/resolver.go index b5a09fd0..25bfedf0 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -100,7 +100,7 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ips []netip.Addr, ips, err = r.lookupIP(ctx, host, D.TypeA) var waitIPv6 *time.Timer - if r != nil { + if r != nil && r.ipv6Timeout > 0 { waitIPv6 = time.NewTimer(r.ipv6Timeout) } else { waitIPv6 = time.NewTimer(100 * time.Millisecond) @@ -421,7 +421,8 @@ type NameServer struct { Net string Addr string Interface *atomic.String - ProxyAdapter string + ProxyAdapter C.ProxyAdapter + ProxyName string Params map[string]string PreferH3 bool } @@ -544,3 +545,5 @@ func NewProxyServerHostResolver(old *Resolver) *Resolver { } return r } + +var ParseNameServer func(servers []string) ([]NameServer, error) // define in config/config.go diff --git a/dns/util.go b/dns/util.go index 4821195d..2fe85931 100644 --- a/dns/util.go +++ b/dns/util.go @@ -74,13 +74,13 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { for _, s := range servers { switch s.Net { case "https": - ret = append(ret, newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter)) + ret = append(ret, newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter, s.ProxyName)) continue case "dhcp": ret = append(ret, newDHCPClient(s.Addr)) continue case "quic": - if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter); err == nil { + if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil { ret = append(ret, doq) } else { log.Fatalln("DoQ format error: %v", err) @@ -103,6 +103,7 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { iface: s.Interface, r: resolver, proxyAdapter: s.ProxyAdapter, + proxyName: s.ProxyName, }) } return ret @@ -144,9 +145,9 @@ func msgToDomain(msg *D.Msg) string { type dialHandler func(ctx context.Context, network, addr string) (net.Conn, error) -func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dialHandler { +func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, opts ...dialer.Option) dialHandler { return func(ctx context.Context, network, addr string) (net.Conn, error) { - if len(proxyAdapter) == 0 { + if len(proxyName) == 0 && proxyAdapter == nil { opts = append(opts, dialer.WithResolver(r)) return dialer.DialContext(ctx, network, addr, opts...) } else { @@ -154,10 +155,14 @@ func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dia if err != nil { return nil, err } - adapter, ok := tunnel.Proxies()[proxyAdapter] - if !ok { - opts = append(opts, dialer.WithInterface(proxyAdapter)) + if proxyAdapter == nil { + var ok bool + proxyAdapter, ok = tunnel.Proxies()[proxyName] + if !ok { + opts = append(opts, dialer.WithInterface(proxyName)) + } } + if strings.Contains(network, "tcp") { // tcp can resolve host by remote metadata := &C.Metadata{ @@ -165,8 +170,8 @@ func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dia Host: host, DstPort: port, } - if ok { - return adapter.DialContext(ctx, metadata, opts...) + if proxyAdapter != nil { + return proxyAdapter.DialContext(ctx, metadata, opts...) } opts = append(opts, dialer.WithResolver(r)) return dialer.DialContext(ctx, network, addr, opts...) @@ -182,15 +187,15 @@ func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dia DstIP: dstIP, DstPort: port, } - if !ok { + if proxyAdapter == nil { return dialer.DialContext(ctx, network, addr, opts...) } - if !adapter.SupportUDP() { + if !proxyAdapter.SupportUDP() { return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter) } - packetConn, err := adapter.ListenPacketContext(ctx, metadata, opts...) + packetConn, err := proxyAdapter.ListenPacketContext(ctx, metadata, opts...) if err != nil { return nil, err } @@ -201,14 +206,17 @@ func getDialHandler(r *Resolver, proxyAdapter string, opts ...dialer.Option) dia } } -func listenPacket(ctx context.Context, proxyAdapter string, network string, addr string, r *Resolver, opts ...dialer.Option) (net.PacketConn, error) { +func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName string, network string, addr string, r *Resolver, opts ...dialer.Option) (net.PacketConn, error) { host, port, err := net.SplitHostPort(addr) if err != nil { return nil, err } - adapter, ok := tunnel.Proxies()[proxyAdapter] - if !ok && len(proxyAdapter) != 0 { - opts = append(opts, dialer.WithInterface(proxyAdapter)) + if proxyAdapter == nil { + var ok bool + proxyAdapter, ok = tunnel.Proxies()[proxyName] + if !ok { + opts = append(opts, dialer.WithInterface(proxyName)) + } } // udp must resolve host first @@ -222,15 +230,15 @@ func listenPacket(ctx context.Context, proxyAdapter string, network string, addr DstIP: dstIP, DstPort: port, } - if !ok { + if proxyAdapter == nil { return dialer.ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", opts...) } - if !adapter.SupportUDP() { + if !proxyAdapter.SupportUDP() { return nil, fmt.Errorf("proxy adapter [%s] UDP is not supported", proxyAdapter) } - return adapter.ListenPacketContext(ctx, metadata, opts...) + return proxyAdapter.ListenPacketContext(ctx, metadata, opts...) } func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.Msg, err error) { diff --git a/docs/config.yaml b/docs/config.yaml index 11891478..99f40ce7 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -631,6 +631,8 @@ proxies: # socks5 # reserved: [209,98,59] # 一个出站代理的标识。当值不为空时,将使用指定的 proxy 发出连接 # dialer-proxy: "ss1" + # remote-dns-resolve: true # 强制dns远程解析,默认值为false + # dns: [ 1.1.1.1, 8.8.8.8 ] # 仅在remote-dns-resolve为true时生效 # 如果peers不为空,该段落中的allowed_ips不可为空;前面段落的server,port,ip,ipv6,public-key,pre-shared-key均会被忽略,但private-key会被保留且只能在顶层指定 # peers: # - server: 162.159.192.1 From 92cc268209e29c5a14252d843580193dd308b220 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 11 Apr 2023 12:51:24 +0800 Subject: [PATCH 187/530] chore: proxyDialer can limited support old dial function --- adapter/outbound/base.go | 15 ++++++------ adapter/outbound/http.go | 4 ++-- adapter/outbound/shadowsocks.go | 6 ++--- adapter/outbound/shadowsocksr.go | 4 ++-- adapter/outbound/snell.go | 4 ++-- adapter/outbound/socks5.go | 4 ++-- adapter/outbound/trojan.go | 4 ++-- adapter/outbound/tuic.go | 4 ++-- adapter/outbound/vless.go | 4 ++-- adapter/outbound/vmess.go | 4 ++-- adapter/outboundgroup/relay.go | 5 +++- component/dialer/dialer.go | 8 +++---- component/proxydialer/proxydialer.go | 36 +++++++++++++++++++++++----- constant/adapters.go | 5 +++- constant/metadata.go | 13 +++++++--- 15 files changed, 78 insertions(+), 42 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 76f9bd39..5b6ef705 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -3,7 +3,6 @@ package outbound import ( "context" "encoding/json" - "errors" "net" "strings" @@ -47,31 +46,31 @@ func (b *Base) Type() C.AdapterType { // StreamConn implements C.ProxyAdapter func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { - return c, errors.New("no support") + return c, C.ErrNotSupport } func (b *Base) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // DialContextWithDialer implements C.ProxyAdapter func (b *Base) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.Conn, err error) { - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // ListenPacketContext implements C.ProxyAdapter func (b *Base) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // ListenPacketWithDialer implements C.ProxyAdapter func (b *Base) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // SupportWithDialer implements C.ProxyAdapter -func (b *Base) SupportWithDialer() bool { - return false +func (b *Base) SupportWithDialer() C.NetWork { + return C.InvalidNet } // SupportUOT implements C.ProxyAdapter diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 645177a4..2d5fd899 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -92,8 +92,8 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad } // SupportWithDialer implements C.ProxyAdapter -func (h *Http) SupportWithDialer() bool { - return true +func (h *Http) SupportWithDialer() C.NetWork { + return C.TCP } func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error { diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index ac4cc31e..14bd96b0 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -205,8 +205,8 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial } // SupportWithDialer implements C.ProxyAdapter -func (ss *ShadowSocks) SupportWithDialer() bool { - return true +func (ss *ShadowSocks) SupportWithDialer() C.NetWork { + return C.ALLNet } // ListenPacketOnStreamConn implements C.ProxyAdapter @@ -219,7 +219,7 @@ func (ss *ShadowSocks) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata return newPacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination}), ss), nil } } - return nil, errors.New("no support") + return nil, C.ErrNotSupport } // SupportUOT implements C.ProxyAdapter diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index e96116d4..2b94ab0c 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -116,8 +116,8 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di } // SupportWithDialer implements C.ProxyAdapter -func (ssr *ShadowSocksR) SupportWithDialer() bool { - return true +func (ssr *ShadowSocksR) SupportWithDialer() C.NetWork { + return C.ALLNet } func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index d6d0436d..1ec0a430 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -136,8 +136,8 @@ func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met } // SupportWithDialer implements C.ProxyAdapter -func (s *Snell) SupportWithDialer() bool { - return true +func (s *Snell) SupportWithDialer() C.NetWork { + return C.ALLNet } // SupportUOT implements C.ProxyAdapter diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index b328b634..26f5733b 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -97,8 +97,8 @@ func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, me } // SupportWithDialer implements C.ProxyAdapter -func (ss *Socks5) SupportWithDialer() bool { - return true +func (ss *Socks5) SupportWithDialer() C.NetWork { + return C.TCP } // ListenPacketContext implements C.ProxyAdapter diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 013164c4..b9bbc33f 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -214,8 +214,8 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me } // SupportWithDialer implements C.ProxyAdapter -func (t *Trojan) SupportWithDialer() bool { - return true +func (t *Trojan) SupportWithDialer() C.NetWork { + return C.ALLNet } // ListenPacketOnStreamConn implements C.ProxyAdapter diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 6640c46a..f2452ae2 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -86,8 +86,8 @@ func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, meta } // SupportWithDialer implements C.ProxyAdapter -func (t *Tuic) SupportWithDialer() bool { - return true +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) { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index b5ae66e1..b7a22245 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -345,8 +345,8 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met } // SupportWithDialer implements C.ProxyAdapter -func (v *Vless) SupportWithDialer() bool { - return true +func (v *Vless) SupportWithDialer() C.NetWork { + return C.ALLNet } // ListenPacketOnStreamConn implements C.ProxyAdapter diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 048b381c..c5212eef 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -368,8 +368,8 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met } // SupportWithDialer implements C.ProxyAdapter -func (v *Vmess) SupportWithDialer() bool { - return true +func (v *Vmess) SupportWithDialer() C.NetWork { + return C.ALLNet } // ListenPacketOnStreamConn implements C.ProxyAdapter diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go index 74c2f73b..c3fe8bd6 100644 --- a/adapter/outboundgroup/relay.go +++ b/adapter/outboundgroup/relay.go @@ -89,7 +89,10 @@ func (r *Relay) SupportUDP() bool { if proxy.SupportUOT() { return true } - if !proxy.SupportWithDialer() { + switch proxy.SupportWithDialer() { + case C.ALLNet: + case C.UDP: + default: // C.TCP and C.NONet return false } } diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index d70e9173..f6dfaf86 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -321,15 +321,15 @@ func sortationAddr(ips []netip.Addr) (ipv4s, ipv6s []netip.Addr) { } type Dialer struct { - opt option + Opt option } func (d Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { - return DialContext(ctx, network, address, WithOption(d.opt)) + return DialContext(ctx, network, address, WithOption(d.Opt)) } func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { - opt := WithOption(d.opt) + opt := WithOption(d.Opt) if rAddrPort.Addr().Unmap().IsLoopback() { // avoid "The requested address is not valid in its context." opt = WithInterface("") @@ -339,5 +339,5 @@ func (d Dialer) ListenPacket(ctx context.Context, network, address string, rAddr func NewDialer(options ...Option) Dialer { opt := applyOptions(options...) - return Dialer{opt: *opt} + return Dialer{Opt: *opt} } diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index 83428d59..fad3835d 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -8,16 +8,17 @@ import ( "strings" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/tunnel" ) type proxyDialer struct { - proxy C.Proxy + proxy C.ProxyAdapter dialer C.Dialer } -func New(proxy C.Proxy, dialer C.Dialer) C.Dialer { +func New(proxy C.ProxyAdapter, dialer C.Dialer) C.Dialer { return proxyDialer{proxy: proxy, dialer: dialer} } @@ -35,14 +36,23 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( return nil, err } if strings.Contains(network, "udp") { // using in wireguard outbound - currentMeta.NetWork = C.UDP - pc, err := p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + pc, err := p.listenPacket(ctx, currentMeta) if err != nil { return nil, err } return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil } - return p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) + switch p.proxy.SupportWithDialer() { + case C.ALLNet: + fallthrough + case C.TCP: + return p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) + default: // fallback to old function + if d, ok := p.dialer.(dialer.Dialer); ok { // fallback to old function + return p.proxy.DialContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + } + return nil, C.ErrNotSupport + } } func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { @@ -50,8 +60,22 @@ func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, if err != nil { return nil, err } + return p.listenPacket(ctx, currentMeta) +} + +func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) (net.PacketConn, error) { currentMeta.NetWork = C.UDP - return p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + switch p.proxy.SupportWithDialer() { + case C.ALLNet: + fallthrough + case C.UDP: + return p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + default: // fallback to old function + if d, ok := p.dialer.(dialer.Dialer); ok { // fallback to old function + return p.proxy.ListenPacketContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + } + return nil, C.ErrNotSupport + } } func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { diff --git a/constant/adapters.go b/constant/adapters.go index ce9f9911..3b401734 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -2,6 +2,7 @@ package constant import ( "context" + "errors" "fmt" "net" "net/netip" @@ -44,6 +45,8 @@ const ( DefaultTLSTimeout = DefaultTCPTimeout ) +var ErrNotSupport = errors.New("no support") + type Connection interface { Chains() Chain AppendToChains(adapter ProxyAdapter) @@ -117,7 +120,7 @@ type ProxyAdapter interface { // SupportUOT return UDP over TCP support SupportUOT() bool - SupportWithDialer() bool + SupportWithDialer() NetWork DialContextWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (Conn, error) ListenPacketWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (PacketConn, error) diff --git a/constant/metadata.go b/constant/metadata.go index 599a6055..4ff20305 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -15,7 +15,10 @@ const ( TCP NetWork = iota UDP ALLNet + InvalidNet = 0xff +) +const ( HTTP Type = iota HTTPS SOCKS4 @@ -33,12 +36,16 @@ const ( type NetWork int func (n NetWork) String() string { - if n == TCP { + switch n { + case TCP: return "tcp" - } else if n == UDP { + case UDP: return "udp" + case ALLNet: + return "all" + default: + return "invalid" } - return "all" } func (n NetWork) MarshalJSON() ([]byte, error) { From 90f95d7c78b4d622b33b3277723e6166cf3f9eec Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 11 Apr 2023 14:10:57 +0800 Subject: [PATCH 188/530] chore: wireguard dns can work with domain-based server --- adapter/outbound/base.go | 5 +++++ adapter/outbound/wireguard.go | 5 +++++ adapter/outboundgroup/fallback.go | 5 +++++ adapter/outboundgroup/loadbalance.go | 5 +++++ adapter/outboundgroup/selector.go | 5 +++++ adapter/outboundgroup/urltest.go | 5 +++++ component/resolver/resolver.go | 7 ++++--- constant/adapters.go | 3 +++ dns/resolver.go | 7 +++++-- dns/util.go | 8 ++++++++ hub/executor/executor.go | 2 +- 11 files changed, 51 insertions(+), 6 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 5b6ef705..0d6cdb8c 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -93,6 +93,11 @@ func (b *Base) SupportTFO() bool { return b.tfo } +// IsL3Protocol implements C.ProxyAdapter +func (b *Base) IsL3Protocol(metadata *C.Metadata) bool { + return false +} + // MarshalJSON implements C.ProxyAdapter func (b *Base) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]string{ diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 0070ce46..a2634be4 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -401,3 +401,8 @@ func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadat } return newPacketConn(CN.NewRefPacketConn(pc, w), w), nil } + +// IsL3Protocol implements C.ProxyAdapter +func (w *WireGuard) IsL3Protocol(metadata *C.Metadata) bool { + return true +} diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 02ba0ac6..c79d9871 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -70,6 +70,11 @@ func (f *Fallback) SupportUDP() bool { return proxy.SupportUDP() } +// IsL3Protocol implements C.ProxyAdapter +func (f *Fallback) IsL3Protocol(metadata *C.Metadata) bool { + return f.findAliveProxy(false).IsL3Protocol(metadata) +} + // MarshalJSON implements C.ProxyAdapter func (f *Fallback) MarshalJSON() ([]byte, error) { all := []string{} diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index 15e17a13..607d4f4f 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -124,6 +124,11 @@ func (lb *LoadBalance) SupportUDP() bool { return !lb.disableUDP } +// IsL3Protocol implements C.ProxyAdapter +func (lb *LoadBalance) IsL3Protocol(metadata *C.Metadata) bool { + return lb.Unwrap(metadata, false).IsL3Protocol(metadata) +} + func strategyRoundRobin() strategyFn { idx := 0 idxMutex := sync.Mutex{} diff --git a/adapter/outboundgroup/selector.go b/adapter/outboundgroup/selector.go index 6356d10e..b5b1cfa3 100644 --- a/adapter/outboundgroup/selector.go +++ b/adapter/outboundgroup/selector.go @@ -44,6 +44,11 @@ func (s *Selector) SupportUDP() bool { return s.selectedProxy(false).SupportUDP() } +// IsL3Protocol implements C.ProxyAdapter +func (s *Selector) IsL3Protocol(metadata *C.Metadata) bool { + return s.selectedProxy(false).IsL3Protocol(metadata) +} + // MarshalJSON implements C.ProxyAdapter func (s *Selector) MarshalJSON() ([]byte, error) { all := []string{} diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index f3426a3e..6f10f78b 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -147,6 +147,11 @@ func (u *URLTest) SupportUDP() bool { return u.fast(false).SupportUDP() } +// IsL3Protocol implements C.ProxyAdapter +func (u *URLTest) IsL3Protocol(metadata *C.Metadata) bool { + return u.fast(false).IsL3Protocol(metadata) +} + // MarshalJSON implements C.ProxyAdapter func (u *URLTest) MarshalJSON() ([]byte, error) { all := []string{} diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index f5872ad7..3b5426d8 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -48,6 +48,7 @@ type Resolver interface { ResolveIPv4(ctx context.Context, host string) (ip netip.Addr, err error) ResolveIPv6(ctx context.Context, host string) (ip netip.Addr, err error) ExchangeContext(ctx context.Context, m *dns.Msg) (msg *dns.Msg, err error) + Invalid() bool } // LookupIPv4WithResolver same as LookupIPv4, but with a resolver @@ -68,7 +69,7 @@ func LookupIPv4WithResolver(ctx context.Context, host string, r Resolver) ([]net return []netip.Addr{}, ErrIPVersion } - if r != nil { + if r != nil && r.Invalid() { return r.LookupIPv4(ctx, host) } @@ -124,7 +125,7 @@ func LookupIPv6WithResolver(ctx context.Context, host string, r Resolver) ([]net return nil, ErrIPVersion } - if r != nil { + if r != nil && r.Invalid() { return r.LookupIPv6(ctx, host) } @@ -164,7 +165,7 @@ func LookupIPWithResolver(ctx context.Context, host string, r Resolver) ([]netip return node.IPs, nil } - if r != nil { + if r != nil && r.Invalid() { if DisableIPv6 { return r.LookupIPv4(ctx, host) } diff --git a/constant/adapters.go b/constant/adapters.go index 3b401734..2a2c68c1 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -124,6 +124,9 @@ type ProxyAdapter interface { DialContextWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (Conn, error) ListenPacketWithDialer(ctx context.Context, dialer Dialer, metadata *Metadata) (PacketConn, error) + // IsL3Protocol return ProxyAdapter working in L3 (tell dns module not pass the domain to avoid loopback) + IsL3Protocol(metadata *Metadata) bool + // Unwrap extracts the proxy from a proxy-group. It returns nil when nothing to extract. Unwrap(metadata *Metadata, touch bool) Proxy } diff --git a/dns/resolver.go b/dns/resolver.go index 25bfedf0..467e9f14 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -412,8 +412,11 @@ func (r *Resolver) asyncExchange(ctx context.Context, client []dnsClient, msg *D return ch } -// HasProxyServer has proxy server dns client -func (r *Resolver) HasProxyServer() bool { +// Invalid return this resolver can or can't be used +func (r *Resolver) Invalid() bool { + if r == nil { + return false + } return len(r.main) > 0 } diff --git a/dns/util.go b/dns/util.go index 2fe85931..9df4482b 100644 --- a/dns/util.go +++ b/dns/util.go @@ -170,6 +170,14 @@ func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, Host: host, DstPort: port, } + if proxyAdapter.IsL3Protocol(metadata) { + dstIP, err := resolver.ResolveIPWithResolver(ctx, host, r) + if err != nil { + return nil, err + } + metadata.Host = "" + metadata.DstIP = dstIP + } if proxyAdapter != nil { return proxyAdapter.DialContext(ctx, metadata, opts...) } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 8ca844d2..3598d873 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -239,7 +239,7 @@ func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, gen resolver.DefaultHostMapper = m resolver.DefaultLocalServer = dns.NewLocalServer(r, m) - if pr.HasProxyServer() { + if pr.Invalid() { resolver.ProxyServerHostResolver = pr } From 7beb09153eb1b213cc9a5b3f3d8762e66c0c5245 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 11 Apr 2023 21:42:16 +0800 Subject: [PATCH 189/530] chore: proxyDialer can add inner conn to statistic --- adapter/outboundgroup/relay.go | 4 +-- component/proxydialer/proxydialer.go | 52 +++++++++++++++++++++------- 2 files changed, 42 insertions(+), 14 deletions(-) diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go index c3fe8bd6..a596454f 100644 --- a/adapter/outboundgroup/relay.go +++ b/adapter/outboundgroup/relay.go @@ -27,7 +27,7 @@ func (r *Relay) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d var d C.Dialer d = dialer.NewDialer(r.Base.DialOptions(opts...)...) for _, proxy := range proxies[:len(proxies)-1] { - d = proxydialer.New(proxy, d) + d = proxydialer.New(proxy, d, false) } last := proxies[len(proxies)-1] conn, err := last.DialContextWithDialer(ctx, d, metadata) @@ -58,7 +58,7 @@ func (r *Relay) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o var d C.Dialer d = dialer.NewDialer(r.Base.DialOptions(opts...)...) for _, proxy := range proxies[:len(proxies)-1] { - d = proxydialer.New(proxy, d) + d = proxydialer.New(proxy, d, false) } last := proxies[len(proxies)-1] pc, err := last.ListenPacketWithDialer(ctx, d, metadata) diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index fad3835d..6c1b3cf2 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -11,21 +11,23 @@ import ( "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/tunnel" + "github.com/Dreamacro/clash/tunnel/statistic" ) type proxyDialer struct { - proxy C.ProxyAdapter - dialer C.Dialer + proxy C.ProxyAdapter + dialer C.Dialer + statistic bool } -func New(proxy C.ProxyAdapter, dialer C.Dialer) C.Dialer { - return proxyDialer{proxy: proxy, dialer: dialer} +func New(proxy C.ProxyAdapter, dialer C.Dialer, statistic bool) C.Dialer { + return proxyDialer{proxy: proxy, dialer: dialer, statistic: statistic} } func NewByName(proxyName string, dialer C.Dialer) (C.Dialer, error) { proxies := tunnel.Proxies() if proxy, ok := proxies[proxyName]; ok { - return New(proxy, dialer), nil + return New(proxy, dialer, true), nil } return nil, fmt.Errorf("proxyName[%s] not found", proxyName) } @@ -42,17 +44,29 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( } return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil } + var conn C.Conn switch p.proxy.SupportWithDialer() { case C.ALLNet: fallthrough case C.TCP: - return p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) + conn, err = p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) + if err != nil { + return nil, err + } default: // fallback to old function if d, ok := p.dialer.(dialer.Dialer); ok { // fallback to old function - return p.proxy.DialContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + conn, err = p.proxy.DialContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + if err != nil { + return nil, err + } + } else { + return nil, C.ErrNotSupport } - return nil, C.ErrNotSupport } + if p.statistic { + conn = statistic.NewTCPTracker(conn, statistic.DefaultManager, currentMeta, nil, 0, 0) + } + return conn, err } func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { @@ -63,19 +77,32 @@ func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, return p.listenPacket(ctx, currentMeta) } -func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) (net.PacketConn, error) { +func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) (C.PacketConn, error) { + var pc C.PacketConn + var err error currentMeta.NetWork = C.UDP switch p.proxy.SupportWithDialer() { case C.ALLNet: fallthrough case C.UDP: - return p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + pc, err = p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) + if err != nil { + return nil, err + } default: // fallback to old function if d, ok := p.dialer.(dialer.Dialer); ok { // fallback to old function - return p.proxy.ListenPacketContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + pc, err = p.proxy.ListenPacketContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + if err != nil { + return nil, err + } + } else { + return nil, C.ErrNotSupport } - return nil, C.ErrNotSupport } + if p.statistic { + pc = statistic.NewUDPTracker(pc, statistic.DefaultManager, currentMeta, nil, 0, 0) + } + return pc, nil } func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { @@ -97,6 +124,7 @@ func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { DstPort: port, } } + addr.Type = C.INNER return } From bad7340a4e94214f4e932493fe79e6c97d6c7146 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 11 Apr 2023 23:58:56 +0800 Subject: [PATCH 190/530] chore: proxyDialer don't push flow to manager in statistic --- component/proxydialer/proxydialer.go | 4 +-- tunnel/statistic/tracker.go | 52 +++++++++++++++++++++++----- tunnel/tunnel.go | 4 +-- 3 files changed, 48 insertions(+), 12 deletions(-) diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index 6c1b3cf2..7fac628f 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -64,7 +64,7 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( } } if p.statistic { - conn = statistic.NewTCPTracker(conn, statistic.DefaultManager, currentMeta, nil, 0, 0) + conn = statistic.NewTCPTracker(conn, statistic.DefaultManager, currentMeta, nil, 0, 0, false) } return conn, err } @@ -100,7 +100,7 @@ func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) } } if p.statistic { - pc = statistic.NewUDPTracker(pc, statistic.DefaultManager, currentMeta, nil, 0, 0) + pc = statistic.NewUDPTracker(pc, statistic.DefaultManager, currentMeta, nil, 0, 0, false) } return pc, nil } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index b5f65338..3678a19d 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -32,6 +32,8 @@ type tcpTracker struct { C.Conn `json:"-"` *trackerInfo manager *Manager + + pushToManager bool `json:"-"` } func (tt *tcpTracker) ID() string { @@ -41,7 +43,9 @@ func (tt *tcpTracker) ID() string { func (tt *tcpTracker) Read(b []byte) (int, error) { n, err := tt.Conn.Read(b) download := int64(n) - tt.manager.PushDownloaded(download) + if tt.pushToManager { + tt.manager.PushDownloaded(download) + } tt.DownloadTotal.Add(download) return n, err } @@ -49,7 +53,9 @@ func (tt *tcpTracker) Read(b []byte) (int, error) { func (tt *tcpTracker) ReadBuffer(buffer *buf.Buffer) (err error) { err = tt.Conn.ReadBuffer(buffer) download := int64(buffer.Len()) - tt.manager.PushDownloaded(download) + if tt.pushToManager { + tt.manager.PushDownloaded(download) + } tt.DownloadTotal.Add(download) return } @@ -57,7 +63,9 @@ func (tt *tcpTracker) ReadBuffer(buffer *buf.Buffer) (err error) { func (tt *tcpTracker) Write(b []byte) (int, error) { n, err := tt.Conn.Write(b) upload := int64(n) - tt.manager.PushUploaded(upload) + if tt.pushToManager { + tt.manager.PushUploaded(upload) + } tt.UploadTotal.Add(upload) return n, err } @@ -65,7 +73,9 @@ func (tt *tcpTracker) Write(b []byte) (int, error) { func (tt *tcpTracker) WriteBuffer(buffer *buf.Buffer) (err error) { upload := int64(buffer.Len()) err = tt.Conn.WriteBuffer(buffer) - tt.manager.PushUploaded(upload) + if tt.pushToManager { + tt.manager.PushUploaded(upload) + } tt.UploadTotal.Add(upload) return } @@ -79,7 +89,7 @@ func (tt *tcpTracker) Upstream() any { return tt.Conn } -func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64) *tcpTracker { +func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *tcpTracker { if conn != nil { if tcpAddr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { metadata.RemoteDst = tcpAddr.IP.String() @@ -100,6 +110,16 @@ func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.R UploadTotal: atomic.NewInt64(uploadTotal), DownloadTotal: atomic.NewInt64(downloadTotal), }, + pushToManager: pushToManager, + } + + if pushToManager { + if uploadTotal > 0 { + manager.PushUploaded(uploadTotal) + } + if downloadTotal > 0 { + manager.PushDownloaded(downloadTotal) + } } if rule != nil { @@ -115,6 +135,8 @@ type udpTracker struct { C.PacketConn `json:"-"` *trackerInfo manager *Manager + + pushToManager bool `json:"-"` } func (ut *udpTracker) ID() string { @@ -124,7 +146,9 @@ func (ut *udpTracker) ID() string { func (ut *udpTracker) ReadFrom(b []byte) (int, net.Addr, error) { n, addr, err := ut.PacketConn.ReadFrom(b) download := int64(n) - ut.manager.PushDownloaded(download) + if ut.pushToManager { + ut.manager.PushDownloaded(download) + } ut.DownloadTotal.Add(download) return n, addr, err } @@ -132,7 +156,9 @@ func (ut *udpTracker) ReadFrom(b []byte) (int, net.Addr, error) { func (ut *udpTracker) WriteTo(b []byte, addr net.Addr) (int, error) { n, err := ut.PacketConn.WriteTo(b, addr) upload := int64(n) - ut.manager.PushUploaded(upload) + if ut.pushToManager { + ut.manager.PushUploaded(upload) + } ut.UploadTotal.Add(upload) return n, err } @@ -142,7 +168,7 @@ func (ut *udpTracker) Close() error { return ut.PacketConn.Close() } -func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64) *udpTracker { +func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker { metadata.RemoteDst = conn.RemoteDestination() ut := &udpTracker{ @@ -157,6 +183,16 @@ func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, ru UploadTotal: atomic.NewInt64(uploadTotal), DownloadTotal: atomic.NewInt64(downloadTotal), }, + pushToManager: pushToManager, + } + + if pushToManager { + if uploadTotal > 0 { + manager.PushUploaded(uploadTotal) + } + if downloadTotal > 0 { + manager.PushDownloaded(downloadTotal) + } } if rule != nil { diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index e982afa6..a4a473e9 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -364,7 +364,7 @@ func handleUDPConn(packet C.PacketAdapter) { } pCtx.InjectPacketConn(rawPc) - pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0) + pc := statistic.NewUDPTracker(rawPc, statistic.DefaultManager, metadata, rule, 0, 0, true) switch true { case metadata.SpecialProxy != "": @@ -494,7 +494,7 @@ func handleTCPConn(connCtx C.ConnContext) { return } - remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule, 0, int64(peekLen)) + remoteConn = statistic.NewTCPTracker(remoteConn, statistic.DefaultManager, metadata, rule, 0, int64(peekLen), true) defer func(remoteConn C.Conn) { _ = remoteConn.Close() }(remoteConn) From fda8857ec8158e1721d7af1089340051572e5f72 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 10:39:24 +0800 Subject: [PATCH 191/530] feat: proxy-provider can set `dialer-proxy` too it will apply `dialer-proxy` to all proxy in this provider --- adapter/provider/parser.go | 4 +++- adapter/provider/provider.go | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index fc5ed936..1df7f320 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -28,6 +28,7 @@ type proxyProviderSchema struct { Filter string `provider:"filter,omitempty"` ExcludeFilter string `provider:"exclude-filter,omitempty"` ExcludeType string `provider:"exclude-type,omitempty"` + DialerProxy string `provider:"dialer-proxy,omitempty"` HealthCheck healthCheckSchema `provider:"health-check,omitempty"` } @@ -65,6 +66,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide filter := schema.Filter excludeFilter := schema.ExcludeFilter excludeType := schema.ExcludeType + dialerProxy := schema.DialerProxy - return NewProxySetProvider(name, interval, filter, excludeFilter, excludeType, vehicle, hc) + return NewProxySetProvider(name, interval, filter, excludeFilter, excludeType, dialerProxy, vehicle, hc) } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 4a2cf7b8..96852c4b 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -143,7 +143,7 @@ func stopProxyProvider(pd *ProxySetProvider) { _ = pd.Fetcher.Destroy() } -func NewProxySetProvider(name string, interval time.Duration, filter string, excludeFilter string, excludeType string, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) { +func NewProxySetProvider(name string, interval time.Duration, filter string, excludeFilter string, excludeType string, dialerProxy string, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) { excludeFilterReg, err := regexp2.Compile(excludeFilter, 0) if err != nil { return nil, fmt.Errorf("invalid excludeFilter regex: %w", err) @@ -171,7 +171,7 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, exc healthCheck: hc, } - fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg), proxiesOnUpdate(pd)) + fetcher := resource.NewFetcher[[]C.Proxy](name, interval, vehicle, proxiesParseAndFilter(filter, excludeFilter, excludeTypeArray, filterRegs, excludeFilterReg, dialerProxy), proxiesOnUpdate(pd)) pd.Fetcher = fetcher wrapper := &ProxySetProvider{pd} runtime.SetFinalizer(wrapper, stopProxyProvider) @@ -267,7 +267,7 @@ func proxiesOnUpdate(pd *proxySetProvider) func([]C.Proxy) { } } -func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray []string, filterRegs []*regexp2.Regexp, excludeFilterReg *regexp2.Regexp) resource.Parser[[]C.Proxy] { +func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray []string, filterRegs []*regexp2.Regexp, excludeFilterReg *regexp2.Regexp, dialerProxy string) resource.Parser[[]C.Proxy] { return func(buf []byte) ([]C.Proxy, error) { schema := &ProxySchema{} @@ -330,6 +330,9 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray if _, ok := proxiesSet[name]; ok { continue } + if len(dialerProxy) > 0 { + mapping["dialer-proxy"] = dialerProxy + } proxy, err := adapter.ParseProxy(mapping) if err != nil { return nil, fmt.Errorf("proxy %d error: %w", idx, err) From 17922dc85798b30d7e478f939cf60848f4f506bb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 11:09:31 +0800 Subject: [PATCH 192/530] chore: proxyDialer first using old function to let mux work --- component/proxydialer/proxydialer.go | 44 ++++++++-------------------- dns/util.go | 16 +++++----- 2 files changed, 20 insertions(+), 40 deletions(-) diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index 7fac628f..a32e54d1 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -45,23 +45,13 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil } var conn C.Conn - switch p.proxy.SupportWithDialer() { - case C.ALLNet: - fallthrough - case C.TCP: + if d, ok := p.dialer.(dialer.Dialer); ok { // first using old function to let mux work + conn, err = p.proxy.DialContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + } else { conn, err = p.proxy.DialContextWithDialer(ctx, p.dialer, currentMeta) - if err != nil { - return nil, err - } - default: // fallback to old function - if d, ok := p.dialer.(dialer.Dialer); ok { // fallback to old function - conn, err = p.proxy.DialContext(ctx, currentMeta, dialer.WithOption(d.Opt)) - if err != nil { - return nil, err - } - } else { - return nil, C.ErrNotSupport - } + } + if err != nil { + return nil, err } if p.statistic { conn = statistic.NewTCPTracker(conn, statistic.DefaultManager, currentMeta, nil, 0, 0, false) @@ -81,23 +71,13 @@ func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) var pc C.PacketConn var err error currentMeta.NetWork = C.UDP - switch p.proxy.SupportWithDialer() { - case C.ALLNet: - fallthrough - case C.UDP: + if d, ok := p.dialer.(dialer.Dialer); ok { // first using old function to let mux work + pc, err = p.proxy.ListenPacketContext(ctx, currentMeta, dialer.WithOption(d.Opt)) + } else { pc, err = p.proxy.ListenPacketWithDialer(ctx, p.dialer, currentMeta) - if err != nil { - return nil, err - } - default: // fallback to old function - if d, ok := p.dialer.(dialer.Dialer); ok { // fallback to old function - pc, err = p.proxy.ListenPacketContext(ctx, currentMeta, dialer.WithOption(d.Opt)) - if err != nil { - return nil, err - } - } else { - return nil, C.ErrNotSupport - } + } + if err != nil { + return nil, err } if p.statistic { pc = statistic.NewUDPTracker(pc, statistic.DefaultManager, currentMeta, nil, 0, 0, false) diff --git a/dns/util.go b/dns/util.go index 9df4482b..bfd2e9ed 100644 --- a/dns/util.go +++ b/dns/util.go @@ -170,15 +170,15 @@ func getDialHandler(r *Resolver, proxyAdapter C.ProxyAdapter, proxyName string, Host: host, DstPort: port, } - if proxyAdapter.IsL3Protocol(metadata) { - dstIP, err := resolver.ResolveIPWithResolver(ctx, host, r) - if err != nil { - return nil, err - } - metadata.Host = "" - metadata.DstIP = dstIP - } if proxyAdapter != nil { + if proxyAdapter.IsL3Protocol(metadata) { // L3 proxy should resolve domain before to avoid loopback + dstIP, err := resolver.ResolveIPWithResolver(ctx, host, r) + if err != nil { + return nil, err + } + metadata.Host = "" + metadata.DstIP = dstIP + } return proxyAdapter.DialContext(ctx, metadata, opts...) } opts = append(opts, dialer.WithResolver(r)) From 20eb168315f9012508baef9d1a9e93d9e018498b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 12:49:53 +0800 Subject: [PATCH 193/530] fix: proxyDialer panic when domain name was not resolved --- adapter/outbound/vmess.go | 6 ++--- component/proxydialer/proxydialer.go | 39 +++++++--------------------- constant/metadata.go | 18 +++++++++++++ transport/tuic/conn.go | 5 ++-- transport/tuic/protocol.go | 12 +++++++++ 5 files changed, 45 insertions(+), 35 deletions(-) diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index c5212eef..710e19bb 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -507,9 +507,9 @@ type vmessPacketConn struct { // WriteTo implments C.PacketConn.WriteTo // Since VMess doesn't support full cone NAT by design, we verify if addr matches uc.rAddr, and drop the packet if not. func (uc *vmessPacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { - allowedAddr := uc.rAddr.(*net.UDPAddr) - destAddr := addr.(*net.UDPAddr) - if !(allowedAddr.IP.Equal(destAddr.IP) && allowedAddr.Port == destAddr.Port) { + allowedAddr := uc.rAddr + destAddr := addr + if allowedAddr.String() != destAddr.String() { return 0, ErrUDPRemoteAddrMismatch } uc.access.Lock() diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index a32e54d1..8a3ab263 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -33,8 +33,8 @@ func NewByName(proxyName string, dialer C.Dialer) (C.Dialer, error) { } func (p proxyDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { - currentMeta, err := addrToMetadata(address) - if err != nil { + currentMeta := &C.Metadata{Type: C.INNER} + if err := currentMeta.SetRemoteAddress(address); err != nil { return nil, err } if strings.Contains(network, "udp") { // using in wireguard outbound @@ -42,9 +42,14 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( if err != nil { return nil, err } - return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil + var rAddr net.Addr = currentMeta.UDPAddr() + if rAddr == nil { // the domain name was not resolved, will appear in not stream-oriented udp like Shadowsocks/Tuic + rAddr = N.NewCustomAddr("udp", currentMeta.RemoteAddress(), nil) + } + return N.NewBindPacketConn(pc, rAddr), nil } var conn C.Conn + var err error if d, ok := p.dialer.(dialer.Dialer); ok { // first using old function to let mux work conn, err = p.proxy.DialContext(ctx, currentMeta, dialer.WithOption(d.Opt)) } else { @@ -60,8 +65,8 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( } func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { - currentMeta, err := addrToMetadata(rAddrPort.String()) - if err != nil { + currentMeta := &C.Metadata{Type: C.INNER} + if err := currentMeta.SetRemoteAddress(address); err != nil { return nil, err } return p.listenPacket(ctx, currentMeta) @@ -84,27 +89,3 @@ func (p proxyDialer) listenPacket(ctx context.Context, currentMeta *C.Metadata) } return pc, nil } - -func addrToMetadata(rawAddress string) (addr *C.Metadata, err error) { - host, port, err := net.SplitHostPort(rawAddress) - if err != nil { - err = fmt.Errorf("addrToMetadata failed: %w", err) - return - } - - if ip, err := netip.ParseAddr(host); err != nil { - addr = &C.Metadata{ - Host: host, - DstPort: port, - } - } else { - addr = &C.Metadata{ - Host: "", - DstIP: ip.Unmap(), - DstPort: port, - } - } - addr.Type = C.INNER - - return -} diff --git a/constant/metadata.go b/constant/metadata.go index 4ff20305..1c344d5d 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -229,3 +229,21 @@ func (m *Metadata) String() string { func (m *Metadata) Valid() bool { return m.Host != "" || m.DstIP.IsValid() } + +func (m *Metadata) SetRemoteAddress(rawAddress string) error { + host, port, err := net.SplitHostPort(rawAddress) + if err != nil { + return err + } + + if ip, err := netip.ParseAddr(host); err != nil { + m.Host = host + m.DstIP = netip.Addr{} + } else { + m.Host = "" + m.DstIP = ip.Unmap() + } + m.DstPort = port + + return nil +} diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index 8f63da75..567f6ce5 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -2,7 +2,6 @@ package tuic import ( "net" - "net/netip" "sync" "sync/atomic" "time" @@ -216,11 +215,11 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro } buf := pool.GetBuffer() defer pool.PutBuffer(buf) - addrPort, err := netip.ParseAddrPort(addr.String()) + address, err := NewAddressNetAddr(addr) if err != nil { return } - err = NewPacket(q.connId, uint16(len(p)), NewAddressAddrPort(addrPort), p).WriteTo(buf) + err = NewPacket(q.connId, uint16(len(p)), address, p).WriteTo(buf) if err != nil { return } diff --git a/transport/tuic/protocol.go b/transport/tuic/protocol.go index 570b6e54..a460eecc 100644 --- a/transport/tuic/protocol.go +++ b/transport/tuic/protocol.go @@ -464,6 +464,18 @@ func NewAddress(metadata *C.Metadata) Address { } } +func NewAddressNetAddr(addr net.Addr) (Address, error) { + 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() From e745755a4601098973efc846d66110b11abccbde Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 12:57:59 +0800 Subject: [PATCH 194/530] fix: direct outbound not ensure ip was resolved --- adapter/outbound/direct.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index cf1b2648..eae37d7a 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -2,6 +2,7 @@ package outbound import ( "context" + "errors" "net" "github.com/Dreamacro/clash/component/dialer" @@ -26,7 +27,14 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ... // ListenPacketContext implements C.ProxyAdapter func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { - opts = append(opts, dialer.WithResolver(resolver.DefaultResolver)) + // net.UDPConn.WriteTo only working with *net.UDPAddr, so we need a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, resolver.DefaultResolver) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", metadata.DstIP), "", d.Base.DialOptions(opts...)...) if err != nil { return nil, err From 836615aac9643bdf5a0368217caf62d7fc88f6a9 Mon Sep 17 00:00:00 2001 From: H1JK Date: Wed, 12 Apr 2023 14:40:38 +0800 Subject: [PATCH 195/530] fix: Converter panic on bad VMess share links --- common/buf/sing.go | 16 ++++++++++------ common/convert/converter.go | 15 ++++++++++----- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/common/buf/sing.go b/common/buf/sing.go index f86b5755..c176ecb1 100644 --- a/common/buf/sing.go +++ b/common/buf/sing.go @@ -9,10 +9,12 @@ const BufferSize = buf.BufferSize type Buffer = buf.Buffer -var New = buf.New -var StackNew = buf.StackNew -var StackNewSize = buf.StackNewSize -var With = buf.With +var ( + New = buf.New + StackNew = buf.StackNew + StackNewSize = buf.StackNewSize + With = buf.With +) var KeepAlive = common.KeepAlive @@ -21,5 +23,7 @@ func Dup[T any](obj T) T { return common.Dup(obj) } -var Must = common.Must -var Error = common.Error +var ( + Must = common.Must + Error = common.Error +) diff --git a/common/convert/converter.go b/common/convert/converter.go index abd07a94..b67918db 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -5,10 +5,11 @@ import ( "encoding/base64" "encoding/json" "fmt" - "github.com/Dreamacro/clash/log" "net/url" "strconv" "strings" + + "github.com/Dreamacro/clash/log" ) // ConvertsV2Ray convert V2Ray subscribe proxies data to clash proxies config @@ -201,7 +202,8 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { vmess["servername"] = sni } - network := strings.ToLower(values["net"].(string)) + network, _ := values["net"].(string) + network = strings.ToLower(network) if values["type"] == "http" { network = "http" } else if network == "http" { @@ -209,9 +211,12 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { } vmess["network"] = network - tls := strings.ToLower(values["tls"].(string)) - if strings.HasSuffix(tls, "tls") { - vmess["tls"] = true + tls, ok := values["tls"].(string) + if ok { + tls = strings.ToLower(tls) + if strings.HasSuffix(tls, "tls") { + vmess["tls"] = true + } } switch network { From 42721f3b758b411ca22dec4e1e022374813c5b88 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 18:19:59 +0800 Subject: [PATCH 196/530] fix: proxyDialer has a non-nil interface containing nil pointer judgment --- component/proxydialer/proxydialer.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index 8a3ab263..e215ff0f 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -42,8 +42,10 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( if err != nil { return nil, err } - var rAddr net.Addr = currentMeta.UDPAddr() - if rAddr == nil { // the domain name was not resolved, will appear in not stream-oriented udp like Shadowsocks/Tuic + var rAddr net.Addr + if udpAddr := currentMeta.UDPAddr(); udpAddr != nil { + rAddr = udpAddr + } else { // the domain name was not resolved, will appear in not stream-oriented udp like Shadowsocks/Tuic rAddr = N.NewCustomAddr("udp", currentMeta.RemoteAddress(), nil) } return N.NewBindPacketConn(pc, rAddr), nil From 5d7fd47cf9e314f3ac3efd9f64a6b51cc0e2f434 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 18:27:22 +0800 Subject: [PATCH 197/530] fix: CGO build failed on darwin-10.16 --- go.mod | 2 +- go.sum | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/go.mod b/go.mod index e7ceadf9..d6479643 100644 --- a/go.mod +++ b/go.mod @@ -87,7 +87,7 @@ require ( github.com/quic-go/qtls-go1-19 v0.2.1 // indirect github.com/quic-go/qtls-go1-20 v0.1.1 // indirect github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61 // indirect - github.com/shoenig/go-m1cpu v0.1.4 // indirect + github.com/shoenig/go-m1cpu v0.1.5 // 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 diff --git a/go.sum b/go.sum index 38a2e16c..7b4d8379 100644 --- a/go.sum +++ b/go.sum @@ -160,8 +160,9 @@ github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA= github.com/shirou/gopsutil/v3 v3.23.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE= github.com/shirou/gopsutil/v3 v3.23.3/go.mod h1:lSBNN6t3+D6W5e5nXTxc8KIMMVxAcS+6IJlffjRRlMU= -github.com/shoenig/go-m1cpu v0.1.4 h1:SZPIgRM2sEF9NJy50mRHu9PKGwxyyTTJIWvCtgVbozs= github.com/shoenig/go-m1cpu v0.1.4/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= +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/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b h1:rXHg9GrUEtWZhEkrykicdND3VPjlVbYiLdX9J7gimS8= From aaf534427eac7470999878d6e3e7b267a37b0b0c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 18:50:51 +0800 Subject: [PATCH 198/530] chore: close all connections after proxySet initial --- adapter/provider/provider.go | 14 ++++++++++++++ tunnel/statistic/tracker.go | 1 + 2 files changed, 15 insertions(+) diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index 96852c4b..4138c0de 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -17,6 +17,7 @@ import ( C "github.com/Dreamacro/clash/constant" types "github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/log" + "github.com/Dreamacro/clash/tunnel/statistic" "github.com/dlclark/regexp2" "gopkg.in/yaml.v3" @@ -81,6 +82,7 @@ func (pp *proxySetProvider) Initial() error { } pp.OnUpdate(elm) pp.getSubscriptionInfo() + pp.closeAllConnections() return nil } @@ -138,6 +140,18 @@ func (pp *proxySetProvider) getSubscriptionInfo() { }() } +func (pp *proxySetProvider) closeAllConnections() { + snapshot := statistic.DefaultManager.Snapshot() + for _, c := range snapshot.Connections { + for _, chain := range c.Chains() { + if chain == pp.Name() { + _ = c.Close() + break + } + } + } +} + func stopProxyProvider(pd *ProxySetProvider) { pd.healthCheck.close() _ = pd.Fetcher.Destroy() diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 3678a19d..96376eb4 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -15,6 +15,7 @@ import ( type tracker interface { ID() string Close() error + C.Connection } type trackerInfo struct { From cb0c9e5caff31eab24943734dd4c34e7de28260d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 21:49:22 +0800 Subject: [PATCH 199/530] chore: udp always direct pass ip to remote without domain --- adapter/outbound/shadowsocks.go | 21 ++++---- adapter/outbound/vless.go | 72 ++++++++++++++++++---------- adapter/outbound/vmess.go | 70 ++++++++++++++------------- component/proxydialer/proxydialer.go | 17 ++++--- 4 files changed, 106 insertions(+), 74 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 14bd96b0..e2ed24c2 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -12,6 +12,7 @@ import ( "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" + "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/restls" obfs "github.com/Dreamacro/clash/transport/simple-obfs" @@ -184,12 +185,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - destination := M.ParseSocksaddr(metadata.RemoteAddress()) - if ss.option.UDPOverTCPVersion == 1 { - return newPacketConn(uot.NewConn(tcpConn, uot.Request{Destination: destination}), ss), nil - } else { - return newPacketConn(uot.NewLazyConn(tcpConn, uot.Request{Destination: destination}), ss), nil - } + return ss.ListenPacketOnStreamConn(ctx, tcpConn, metadata) } addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer) if err != nil { @@ -210,9 +206,18 @@ func (ss *ShadowSocks) SupportWithDialer() C.NetWork { } // ListenPacketOnStreamConn implements C.ProxyAdapter -func (ss *ShadowSocks) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { +func (ss *ShadowSocks) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { if ss.option.UDPOverTCP { - destination := M.ParseSocksaddr(metadata.RemoteAddress()) + // ss uot use stream-oriented udp with a special address, so we need a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } + + destination := M.SocksaddrFromNet(metadata.UDPAddr()) if ss.option.UDPOverTCPVersion == uot.LegacyVersion { return newPacketConn(uot.NewConn(c, uot.Request{Destination: destination}), ss), nil } else { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index b7a22245..ecfa1a13 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -169,7 +169,34 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { return nil, err } - return v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP)) + return v.streamConn(c, metadata) +} + +func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err error) { + metadata = &C.Metadata{ // a clear metadata only contains ip + NetWork: metadata.NetWork, + DstIP: metadata.DstIP, + DstPort: metadata.DstPort, + } + if metadata.NetWork == C.UDP { + if v.option.PacketAddr { + metadata = &C.Metadata{ + NetWork: C.UDP, + Host: packetaddr.SeqPacketMagicAddress, + DstPort: "443", + } + } + conn, err = v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP)) + if v.option.PacketAddr { + conn = packetaddr.NewBindConn(conn) + } + } else { + conn, err = v.client.StreamConn(c, parseVlessAddr(metadata, false)) + } + if err != nil { + conn = nil + } + return } func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) { @@ -271,7 +298,6 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o } metadata.DstIP = ip } - var c net.Conn // gun transport if v.transport != nil && len(opts) == 0 { @@ -283,21 +309,12 @@ func (v *Vless) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o safeConnClose(c, err) }(c) - if v.option.PacketAddr { - packetAddrMetadata := *metadata // make a copy - packetAddrMetadata.Host = packetaddr.SeqPacketMagicAddress - packetAddrMetadata.DstPort = "443" - - c, err = v.client.StreamConn(c, parseVlessAddr(&packetAddrMetadata, false)) - } else { - c, err = v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP)) - } - + c, err = v.streamConn(c, metadata) if err != nil { return nil, fmt.Errorf("new vless client error: %v", err) } - return v.ListenPacketOnStreamConn(c, metadata) + return v.ListenPacketOnStreamConn(ctx, c, metadata) } return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.Base.DialOptions(opts...)...), metadata) } @@ -310,6 +327,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met return nil, err } } + // vless use stream-oriented udp with a special address, so we need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) @@ -318,6 +336,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met } metadata.DstIP = ip } + c, err := dialer.DialContext(ctx, "tcp", v.addr) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) @@ -327,21 +346,12 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met safeConnClose(c, err) }(c) - if v.option.PacketAddr { - packetAddrMetadata := *metadata // make a copy - packetAddrMetadata.Host = packetaddr.SeqPacketMagicAddress - packetAddrMetadata.DstPort = "443" - - c, err = v.StreamConn(c, &packetAddrMetadata) - } else { - c, err = v.StreamConn(c, metadata) - } - + c, err = v.streamConn(c, metadata) if err != nil { return nil, fmt.Errorf("new vless client error: %v", err) } - return v.ListenPacketOnStreamConn(c, metadata) + return v.ListenPacketOnStreamConn(ctx, c, metadata) } // SupportWithDialer implements C.ProxyAdapter @@ -350,7 +360,16 @@ func (v *Vless) SupportWithDialer() C.NetWork { } // ListenPacketOnStreamConn implements C.ProxyAdapter -func (v *Vless) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { +func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { + // vless use stream-oriented udp with a special address, so we need a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } + if v.option.XUDP { return newPacketConn(&threadSafePacketConn{ PacketConn: vmessSing.NewXUDPConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), @@ -517,6 +536,9 @@ func NewVless(option VlessOption) (*Vless, error) { option.XUDP = true } } + if option.XUDP { + option.PacketAddr = false + } client, err := vless.NewClient(option.UUID, addons, option.FlowShow) if err != nil { diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 710e19bb..8901f3d5 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -217,27 +217,42 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { if err != nil { return nil, err } + return v.streamConn(c, metadata) +} + +func (v *Vmess) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err error) { if metadata.NetWork == C.UDP { if v.option.XUDP { if N.NeedHandshake(c) { - return v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + conn = v.client.DialEarlyXUDPPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) } else { - return v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + conn, err = v.client.DialXUDPPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) } + } else if v.option.PacketAddr { + if N.NeedHandshake(c) { + conn = v.client.DialEarlyPacketConn(c, M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443)) + } else { + conn, err = v.client.DialPacketConn(c, M.ParseSocksaddrHostPort(packetaddr.SeqPacketMagicAddress, 443)) + } + conn = packetaddr.NewBindConn(conn) } else { if N.NeedHandshake(c) { - return v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + conn = v.client.DialEarlyPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) } else { - return v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + conn, err = v.client.DialPacketConn(c, M.SocksaddrFromNet(metadata.UDPAddr())) } } } else { if N.NeedHandshake(c) { - return v.client.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + conn = v.client.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) } else { - return v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + conn, err = v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) } } + if err != nil { + conn = nil + } + return } // DialContext implements C.ProxyAdapter @@ -293,14 +308,6 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o } metadata.DstIP = ip } - - if v.option.PacketAddr { - _metadata := *metadata // make a copy - metadata = &_metadata - metadata.Host = packetaddr.SeqPacketMagicAddress - metadata.DstPort = "443" - } - var c net.Conn // gun transport if v.transport != nil && len(opts) == 0 { @@ -312,24 +319,11 @@ func (v *Vmess) ListenPacketContext(ctx context.Context, metadata *C.Metadata, o safeConnClose(c, err) }(c) - if v.option.XUDP { - if N.NeedHandshake(c) { - c = v.client.DialEarlyXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) - } else { - c, err = v.client.DialXUDPPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) - } - } else { - if N.NeedHandshake(c) { - c = v.client.DialEarlyPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) - } else { - c, err = v.client.DialPacketConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) - } - } - + c, err = v.streamConn(c, metadata) if err != nil { return nil, fmt.Errorf("new vmess client error: %v", err) } - return v.ListenPacketOnStreamConn(c, metadata) + return v.ListenPacketOnStreamConn(ctx, c, metadata) } return v.ListenPacketWithDialer(ctx, dialer.NewDialer(v.Base.DialOptions(opts...)...), metadata) } @@ -342,6 +336,7 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met return nil, err } } + // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr if !metadata.Resolved() { ip, err := resolver.ResolveIP(ctx, metadata.Host) @@ -364,7 +359,7 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met if err != nil { return nil, fmt.Errorf("new vmess client error: %v", err) } - return v.ListenPacketOnStreamConn(c, metadata) + return v.ListenPacketOnStreamConn(ctx, c, metadata) } // SupportWithDialer implements C.ProxyAdapter @@ -373,10 +368,17 @@ func (v *Vmess) SupportWithDialer() C.NetWork { } // ListenPacketOnStreamConn implements C.ProxyAdapter -func (v *Vmess) ListenPacketOnStreamConn(c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { - if v.option.PacketAddr { - return newPacketConn(&threadSafePacketConn{PacketConn: packetaddr.NewBindConn(c)}, v), nil - } else if pc, ok := c.(net.PacketConn); ok { +func (v *Vmess) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metadata *C.Metadata) (_ C.PacketConn, err error) { + // vmess use stream-oriented udp with a special address, so we need a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } + + if pc, ok := c.(net.PacketConn); ok { return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil } return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index e215ff0f..fc5cb294 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -2,6 +2,7 @@ package proxydialer import ( "context" + "errors" "fmt" "net" "net/netip" @@ -9,6 +10,7 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/tunnel" "github.com/Dreamacro/clash/tunnel/statistic" @@ -38,17 +40,18 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( return nil, err } if strings.Contains(network, "udp") { // using in wireguard outbound + if !currentMeta.Resolved() { + ip, err := resolver.ResolveIP(ctx, currentMeta.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + currentMeta.DstIP = ip + } pc, err := p.listenPacket(ctx, currentMeta) if err != nil { return nil, err } - var rAddr net.Addr - if udpAddr := currentMeta.UDPAddr(); udpAddr != nil { - rAddr = udpAddr - } else { // the domain name was not resolved, will appear in not stream-oriented udp like Shadowsocks/Tuic - rAddr = N.NewCustomAddr("udp", currentMeta.RemoteAddress(), nil) - } - return N.NewBindPacketConn(pc, rAddr), nil + return N.NewBindPacketConn(pc, currentMeta.UDPAddr()), nil } var conn C.Conn var err error From cd42e9832c4caae5824a76f93325210667049329 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 22:06:21 +0800 Subject: [PATCH 200/530] chore: resolver priority return TypeA in ResolveIP (not effected LookupIP) --- component/dialer/dialer.go | 13 +------------ component/resolver/resolver.go | 22 ++++++++++++++++----- dns/resolver.go | 35 ---------------------------------- 3 files changed, 18 insertions(+), 52 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index f6dfaf86..5a55cd22 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -157,7 +157,7 @@ func concurrentDualStackDialContext(ctx context.Context, network string, ips []n } func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { - ipv4s, ipv6s := sortationAddr(ips) + ipv4s, ipv6s := resolver.SortationAddr(ips) preferIPVersion := opt.prefer fallbackTicker := time.NewTicker(fallbackTimeout) @@ -309,17 +309,6 @@ func parseAddr(ctx context.Context, network, address string, preferResolver reso return ips, port, nil } -func sortationAddr(ips []netip.Addr) (ipv4s, ipv6s []netip.Addr) { - for _, v := range ips { - if v.Is4() { // 4in6 parse was in parseAddr - ipv4s = append(ipv4s, v) - } else { - ipv6s = append(ipv6s, v) - } - } - return -} - type Dialer struct { Opt option } diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index 3b5426d8..6be6a95f 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -44,9 +44,6 @@ type Resolver interface { LookupIP(ctx context.Context, host string) (ips []netip.Addr, err error) LookupIPv4(ctx context.Context, host string) (ips []netip.Addr, err error) LookupIPv6(ctx context.Context, host string) (ips []netip.Addr, err error) - ResolveIP(ctx context.Context, host string) (ip netip.Addr, err error) - ResolveIPv4(ctx context.Context, host string) (ip netip.Addr, err error) - ResolveIPv6(ctx context.Context, host string) (ip netip.Addr, err error) ExchangeContext(ctx context.Context, m *dns.Msg) (msg *dns.Msg, err error) Invalid() bool } @@ -201,10 +198,14 @@ func ResolveIPWithResolver(ctx context.Context, host string, r Resolver) (netip. } else if len(ips) == 0 { return netip.Addr{}, fmt.Errorf("%w: %s", ErrIPNotFound, host) } - return ips[fastrand.Intn(len(ips))], nil + ipv4s, ipv6s := SortationAddr(ips) + if len(ipv4s) > 0 { + return ipv4s[fastrand.Intn(len(ipv4s))], nil + } + return ipv6s[fastrand.Intn(len(ipv6s))], nil } -// ResolveIP with a host, return ip +// ResolveIP with a host, return ip and priority return TypeA func ResolveIP(ctx context.Context, host string) (netip.Addr, error) { return ResolveIPWithResolver(ctx, host, DefaultResolver) } @@ -265,3 +266,14 @@ func LookupIPProxyServerHost(ctx context.Context, host string) ([]netip.Addr, er } return LookupIP(ctx, host) } + +func SortationAddr(ips []netip.Addr) (ipv4s, ipv6s []netip.Addr) { + for _, v := range ips { + if v.Unmap().Is4() { + ipv4s = append(ipv4s, v) + } else { + ipv6s = append(ipv6s, v) + } + } + return +} diff --git a/dns/resolver.go b/dns/resolver.go index 467e9f14..df8ed3d1 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -3,7 +3,6 @@ package dns import ( "context" "errors" - "fmt" "net/netip" "strings" "time" @@ -20,7 +19,6 @@ import ( "github.com/Dreamacro/clash/log" D "github.com/miekg/dns" - "github.com/zhangyunhao116/fastrand" "golang.org/x/sync/singleflight" ) @@ -119,49 +117,16 @@ func (r *Resolver) LookupIP(ctx context.Context, host string) (ips []netip.Addr, return ips, nil } -// ResolveIP request with TypeA and TypeAAAA, priority return TypeA -func (r *Resolver) ResolveIP(ctx context.Context, host string) (ip netip.Addr, err error) { - ips, err := r.LookupIPPrimaryIPv4(ctx, host) - if err != nil { - return netip.Addr{}, err - } else if len(ips) == 0 { - return netip.Addr{}, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host) - } - return ips[fastrand.Intn(len(ips))], nil -} - // LookupIPv4 request with TypeA func (r *Resolver) LookupIPv4(ctx context.Context, host string) ([]netip.Addr, error) { return r.lookupIP(ctx, host, D.TypeA) } -// ResolveIPv4 request with TypeA -func (r *Resolver) ResolveIPv4(ctx context.Context, host string) (ip netip.Addr, err error) { - ips, err := r.lookupIP(ctx, host, D.TypeA) - if err != nil { - return netip.Addr{}, err - } else if len(ips) == 0 { - return netip.Addr{}, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host) - } - return ips[fastrand.Intn(len(ips))], nil -} - // LookupIPv6 request with TypeAAAA func (r *Resolver) LookupIPv6(ctx context.Context, host string) ([]netip.Addr, error) { return r.lookupIP(ctx, host, D.TypeAAAA) } -// ResolveIPv6 request with TypeAAAA -func (r *Resolver) ResolveIPv6(ctx context.Context, host string) (ip netip.Addr, err error) { - ips, err := r.lookupIP(ctx, host, D.TypeAAAA) - if err != nil { - return netip.Addr{}, err - } else if len(ips) == 0 { - return netip.Addr{}, fmt.Errorf("%w: %s", resolver.ErrIPNotFound, host) - } - return ips[fastrand.Intn(len(ips))], nil -} - func (r *Resolver) shouldIPFallback(ip netip.Addr) bool { for _, filter := range r.fallbackIPFilters { if filter.Match(ip) { From dbffbca6f5c26d3e5ab61d340f51928af6013e3a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 12 Apr 2023 23:55:51 +0800 Subject: [PATCH 201/530] doc: update config.yaml --- docs/config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index 99f40ce7..922d4895 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -686,7 +686,7 @@ proxies: # socks5 proxy-groups: # 代理链,目前relay可以支持udp的只有vmess/vless/trojan/ss/ssr/tuic - # wireguard目前不支持在relay中使用,请使用tunnels功能模拟 + # wireguard目前不支持在relay中使用,请使用proxy中的dialer-proxy配置项 # Traffic: clash <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet - name: "relay" type: relay From 38a85272c26658b1e5c5ea5fd8f5b75ddbc7ed7b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 13 Apr 2023 11:10:35 +0800 Subject: [PATCH 202/530] fix: vless tcp not working --- adapter/outbound/vless.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index ecfa1a13..5f7c2087 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -173,12 +173,12 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { } func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err error) { - metadata = &C.Metadata{ // a clear metadata only contains ip - NetWork: metadata.NetWork, - DstIP: metadata.DstIP, - DstPort: metadata.DstPort, - } if metadata.NetWork == C.UDP { + metadata = &C.Metadata{ // a clear metadata only contains ip + NetWork: metadata.NetWork, + DstIP: metadata.DstIP, + DstPort: metadata.DstPort, + } if v.option.PacketAddr { metadata = &C.Metadata{ NetWork: C.UDP, From 394889258cf2a0023369494f0f5a3e164fd41fe1 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 13 Apr 2023 17:01:01 +0800 Subject: [PATCH 203/530] fix: wireguard reconnect failed --- adapter/outbound/wireguard.go | 10 +++++++++- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index a2634be4..f96f2d6f 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -174,7 +174,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { connectAddr = option.Addr() } } - outbound.bind = wireguard.NewClientBind(context.Background(), outbound.dialer, isConnect, connectAddr, reserved) + outbound.bind = wireguard.NewClientBind(context.Background(), outbound, outbound.dialer, isConnect, connectAddr, reserved) var localPrefixes []netip.Prefix @@ -329,6 +329,14 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { return outbound, nil } +func (w *WireGuard) NewError(ctx context.Context, err error) { + if E.IsClosedOrCanceled(err) { + log.SingLogger.Debug(fmt.Sprintf("[WG](%s) connection closed: %s", w.Name(), err)) + return + } + log.SingLogger.Error(fmt.Sprintf("[WG](%s) %s", w.Name(), err)) +} + func closeWireGuard(w *WireGuard) { if w.device != nil { w.device.Close() diff --git a/go.mod b/go.mod index d6479643..180b0307 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230409073201-1ce3505114ae github.com/metacubex/sing-tun v0.1.3 - github.com/metacubex/sing-wireguard v0.0.0-20230402083957-d134f603ac98 + github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 github.com/miekg/dns v1.1.52 github.com/mroth/weightedrand/v2 v2.0.0 github.com/openacid/low v0.1.21 diff --git a/go.sum b/go.sum index 7b4d8379..8d4f564e 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,8 @@ github.com/metacubex/sing-shadowsocks v0.2.2-0.20230409073201-1ce3505114ae h1:SN github.com/metacubex/sing-shadowsocks v0.2.2-0.20230409073201-1ce3505114ae/go.mod h1:JefDbbkQHCn8w+IcjFqMOMV2VmN9wvbYX4RaeBUkPwM= github.com/metacubex/sing-tun v0.1.3 h1:LCz8TlAZUWwnBYZxs1PEE04PyfLA9xdsye6CjHZlZGQ= github.com/metacubex/sing-tun v0.1.3/go.mod h1:kHkYHoRlYA4I12QPTt/ADyRGqy5YweLUfye1E1hC/q4= -github.com/metacubex/sing-wireguard v0.0.0-20230402083957-d134f603ac98 h1:Dr6A4drhVkjPaJ5lIf3DwhH2HSo+Qmf8fCQmJoDG5YU= -github.com/metacubex/sing-wireguard v0.0.0-20230402083957-d134f603ac98/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= +github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 h1:itjCqEeem+BKZFiBEhQmWHDHKK4FgTGvnYCFS0JOb3A= +github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c= From b3794ffdd8a401faec927ca307725fd4eac75060 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 13 Apr 2023 19:37:33 +0800 Subject: [PATCH 204/530] fix: deadline pipeReadBuffer, pipeReadFrom and panic when alloc empty buffer --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 180b0307..18d3fb3e 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( 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.3-0.20230409094616-7f8eaee1b6c8 + github.com/sagernet/sing v0.2.3-0.20230413112320-59e662e6e2ed github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index 8d4f564e..aea0ce98 100644 --- a/go.sum +++ b/go.sum @@ -144,8 +144,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.3-0.20230409094616-7f8eaee1b6c8 h1:BWQjek8tNzDzCeHh/8yvjfZ8Id0tl+6pJ+gcPI8tjl8= -github.com/sagernet/sing v0.2.3-0.20230409094616-7f8eaee1b6c8/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.3-0.20230413112320-59e662e6e2ed h1:7Vg+lQanPwjxdYaln/EpKK7OcClvoUNm7Tt9V0FPnpY= +github.com/sagernet/sing v0.2.3-0.20230413112320-59e662e6e2ed/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 h1:QnV79JbJbJGT0MJJfd8o7QMEfRu3eUVKsmahxFMonrc= github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661/go.mod h1:xCeSRP8cV32aPsY+6BbRdJjyD6q8ufdKwhgqxEbU/3U= github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 h1:ZArINfN+zcHMdZCeRFOm4rO3SWyvYuLg3VhWcA5zonc= From e4926c8364b6f5f25e33e306b417755cbbbbe847 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 14 Apr 2023 13:51:26 +0800 Subject: [PATCH 205/530] feat: ruleset support text `format` --- constant/provider/interface.go | 44 ++++++++++++------ rules/provider/parse.go | 16 ++++++- rules/provider/provider.go | 82 +++++++++++++++++++++------------- 3 files changed, 97 insertions(+), 45 deletions(-) diff --git a/constant/provider/interface.go b/constant/provider/interface.go index b42bbe71..fb5efd87 100644 --- a/constant/provider/interface.go +++ b/constant/provider/interface.go @@ -73,17 +73,27 @@ type ProxyProvider interface { Version() uint32 } -// Rule Type +// RuleProvider interface +type RuleProvider interface { + Provider + Behavior() RuleBehavior + Match(*constant.Metadata) bool + ShouldResolveIP() bool + ShouldFindProcess() bool + AsRule(adaptor string) constant.Rule +} + +// Rule Behavior const ( - Domain RuleType = iota + Domain RuleBehavior = iota IPCIDR Classical ) -// RuleType defined -type RuleType int +// RuleBehavior defined +type RuleBehavior int -func (rt RuleType) String() string { +func (rt RuleBehavior) String() string { switch rt { case Domain: return "Domain" @@ -96,12 +106,20 @@ func (rt RuleType) String() string { } } -// RuleProvider interface -type RuleProvider interface { - Provider - Behavior() RuleType - Match(*constant.Metadata) bool - ShouldResolveIP() bool - ShouldFindProcess() bool - AsRule(adaptor string) constant.Rule +const ( + YamlRule RuleFormat = iota + TextRule +) + +type RuleFormat int + +func (rf RuleFormat) String() string { + switch rf { + case YamlRule: + return "YamlRule" + case TextRule: + return "TextRule" + default: + return "Unknown" + } } diff --git a/rules/provider/parse.go b/rules/provider/parse.go index 206bef10..6a001b50 100644 --- a/rules/provider/parse.go +++ b/rules/provider/parse.go @@ -14,6 +14,7 @@ type ruleProviderSchema struct { Behavior string `provider:"behavior"` Path string `provider:"path"` URL string `provider:"url,omitempty"` + Format string `provider:"format,omitempty"` Interval int `provider:"interval,omitempty"` } @@ -23,7 +24,7 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t if err := decoder.Decode(mapping, schema); err != nil { return nil, err } - var behavior P.RuleType + var behavior P.RuleBehavior switch schema.Behavior { case "domain": @@ -36,6 +37,17 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t return nil, fmt.Errorf("unsupported behavior type: %s", schema.Behavior) } + var format P.RuleFormat + + switch schema.Format { + case "", "yaml": + format = P.YamlRule + case "text": + format = P.TextRule + default: + return nil, fmt.Errorf("unsupported format type: %s", schema.Format) + } + path := C.Path.Resolve(schema.Path) var vehicle P.Vehicle switch schema.Type { @@ -47,5 +59,5 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t return nil, fmt.Errorf("unsupported vehicle type: %s", schema.Type) } - return NewRuleSetProvider(name, behavior, time.Duration(uint(schema.Interval))*time.Second, vehicle, parse), nil + return NewRuleSetProvider(name, behavior, format, time.Duration(uint(schema.Interval))*time.Second, vehicle, parse), nil } diff --git a/rules/provider/provider.go b/rules/provider/provider.go index 6b3c0290..a4271655 100644 --- a/rules/provider/provider.go +++ b/rules/provider/provider.go @@ -6,6 +6,7 @@ import ( "errors" "gopkg.in/yaml.v3" "runtime" + "strings" "time" "github.com/Dreamacro/clash/common/pool" @@ -20,7 +21,8 @@ var ( type ruleSetProvider struct { *resource.Fetcher[any] - behavior P.RuleType + behavior P.RuleBehavior + format P.RuleFormat strategy ruleStrategy } @@ -81,7 +83,7 @@ func (rp *ruleSetProvider) Update() error { return err } -func (rp *ruleSetProvider) Behavior() P.RuleType { +func (rp *ruleSetProvider) Behavior() P.RuleBehavior { return rp.behavior } @@ -105,6 +107,7 @@ func (rp *ruleSetProvider) MarshalJSON() ([]byte, error) { return json.Marshal( map[string]interface{}{ "behavior": rp.behavior.String(), + "format": rp.format.String(), "name": rp.Name(), "ruleCount": rp.strategy.Count(), "type": rp.Type().String(), @@ -113,10 +116,11 @@ func (rp *ruleSetProvider) MarshalJSON() ([]byte, error) { }) } -func NewRuleSetProvider(name string, behavior P.RuleType, interval time.Duration, vehicle P.Vehicle, +func NewRuleSetProvider(name string, behavior P.RuleBehavior, format P.RuleFormat, interval time.Duration, vehicle P.Vehicle, parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) P.RuleProvider { rp := &ruleSetProvider{ behavior: behavior, + format: format, } onUpdate := func(elm interface{}) { @@ -125,7 +129,7 @@ func NewRuleSetProvider(name string, behavior P.RuleType, interval time.Duration } rp.strategy = newStrategy(behavior, parse) - rp.Fetcher = resource.NewFetcher(name, interval, vehicle, func(bytes []byte) (any, error) { return rulesParse(bytes, newStrategy(behavior, parse)) }, onUpdate) + rp.Fetcher = resource.NewFetcher(name, interval, vehicle, func(bytes []byte) (any, error) { return rulesParse(bytes, newStrategy(behavior, parse), format) }, onUpdate) wrapper := &RuleSetProvider{ rp, @@ -136,7 +140,7 @@ func NewRuleSetProvider(name string, behavior P.RuleType, interval time.Duration return wrapper } -func newStrategy(behavior P.RuleType, parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) ruleStrategy { +func newStrategy(behavior P.RuleBehavior, parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) ruleStrategy { switch behavior { case P.Domain: strategy := NewDomainStrategy() @@ -154,7 +158,7 @@ func newStrategy(behavior P.RuleType, parse func(tp, payload, target string, par var ErrNoPayload = errors.New("file must have a `payload` field") -func rulesParse(buf []byte, strategy ruleStrategy) (any, error) { +func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (any, error) { strategy.Reset() schema := &RulePayload{} @@ -177,36 +181,54 @@ func rulesParse(buf []byte, strategy ruleStrategy) (any, error) { return nil, ErrNoPayload } } - firstLineBuffer.Write(line) - if firstLineLength == 0 { // find payload head - firstLineLength = firstLineBuffer.Len() - firstLineBuffer.WriteString(" - ''") // a test line + var str string + switch format { + case P.TextRule: + firstLineLength = -1 // don't return ErrNoPayload when read last line + str = string(line) + str = strings.TrimSpace(str) + if str[0] == '#' { // comment + continue + } + if strings.HasPrefix(str, "//") { // comment in Premium core + continue + } + case P.YamlRule: + if bytes.TrimSpace(line)[0] == '#' { // comment + continue + } + firstLineBuffer.Write(line) + if firstLineLength == 0 { // find payload head + firstLineLength = firstLineBuffer.Len() + firstLineBuffer.WriteString(" - ''") // a test line - err := yaml.Unmarshal(firstLineBuffer.Bytes(), schema) - firstLineBuffer.Truncate(firstLineLength) - if err == nil && (len(schema.Rules) > 0 || len(schema.Payload) > 0) { // found + err := yaml.Unmarshal(firstLineBuffer.Bytes(), schema) + firstLineBuffer.Truncate(firstLineLength) + if err == nil && (len(schema.Rules) > 0 || len(schema.Payload) > 0) { // found + continue + } + + // not found or err!=nil + firstLineBuffer.Truncate(0) + firstLineLength = 0 continue } - // not found or err!=nil - firstLineBuffer.Truncate(0) - firstLineLength = 0 - continue + // parse payload body + err := yaml.Unmarshal(firstLineBuffer.Bytes(), schema) + firstLineBuffer.Truncate(firstLineLength) + if err != nil { + continue + } + + if len(schema.Rules) > 0 { + str = schema.Rules[0] + } + if len(schema.Payload) > 0 { + str = schema.Payload[0] + } } - // parse payload body - err := yaml.Unmarshal(firstLineBuffer.Bytes(), schema) - firstLineBuffer.Truncate(firstLineLength) - if err != nil { - continue - } - var str string - if len(schema.Rules) > 0 { - str = schema.Rules[0] - } - if len(schema.Payload) > 0 { - str = schema.Payload[0] - } if str == "" { continue } From 81bef30ae0a152484db3aa3d5cbc75388c3f60b4 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 14 Apr 2023 10:04:39 +0000 Subject: [PATCH 206/530] chore: clean up docs --- docs/allocs.svg | 2387 ----------------------------------------------- docs/heap.svg | 2182 ------------------------------------------- 2 files changed, 4569 deletions(-) delete mode 100644 docs/allocs.svg delete mode 100644 docs/heap.svg diff --git a/docs/allocs.svg b/docs/allocs.svg deleted file mode 100644 index 57deec50..00000000 --- a/docs/allocs.svg +++ /dev/null @@ -1,2387 +0,0 @@ - - - - - - -unnamed - - -cluster_L - - - - -Type: alloc_space - -Type: alloc_space -Time: Jan 30, 2023 at 9:18pm (CST) -Showing nodes accounting for 1777.16MB, 96.71% of 1837.65MB total -Dropped 188 nodes (cum <= 9.19MB) -Dropped 2 edges (freq <= 1.84MB) -Showing top 55 nodes out of 117 -See https://git.io/JfYMW for how to read the graph - - - -N1 - - -quic-go -(*client) -dial -func1 -0 of 1648.40MB (89.70%) - - - - - -N3 - - -quic-go -(*connection) -run -0 of 1648.40MB (89.70%) - - - - - -N1->N3 - - - - - - - 1648.40MB - - - - - -N2 - - -quic-go -(*connection) -sendPacket -0 of 1412.44MB (76.86%) - - - - - -N4 - - -quic-go -(*packetPacker) -PackPacket -30MB (1.63%) -of 956.14MB (52.03%) - - - - - -N2->N4 - - - - - - - 956.14MB - - - - - -N10 - - -quic-go -(*connection) -sendPackedPacket -0 of 456.30MB (24.83%) - - - - - -N2->N10 - - - - - - - 456.30MB - - - - - -N3->N2 - - - - - - - 1412.44MB - - - - - -N36 - - -quic-go -(*connection) -handleUnpackedShortHeaderPacket -0 of 235.46MB (12.81%) - - - - - -N3->N36 - - - - - - - 235.46MB - - - - - -NN4_0 - - - - - -16B..64B - - - - - -N4->NN4_0 - - - - - - - 30MB - - - - - -N6 - - -quic-go -(*packetPacker) -maybeGetShortHeaderPacket -0 of 722.12MB (39.30%) - - - - - -N4->N6 - - - - - - - 722.12MB - - - - - -N13 - - -quic-go -(*packetPacker) -appendPacket -118.51MB (6.45%) -of 204.01MB (11.10%) - - - - - -N4->N13 - - - - - - - 204.01MB - - - - - -N5 - - -quic-go -(*packetPacker) -composeNextPacket -162.51MB (8.84%) -of 446.09MB (24.28%) - - - - - -NN5_0 - - - - - -48B..64B - - - - - -N5->NN5_0 - - - - - - - 93.50MB - - - - - -NN5_1 - - - - - -16B..32B - - - - - -N5->NN5_1 - - - - - - - 69MB - - - - - -N25 - - -quic-go -(*framerI) -AppendStreamFrames -15.50MB (0.84%) -of 157.55MB (8.57%) - - - - - -N5->N25 - - - - - - - 157.55MB - - - - - -N34 - - -ackhandler -(*receivedPacketTracker) -GetAckFrame -0 of 126.04MB (6.86%) - - - - - -N5->N34 - - - - - - - 126.04MB - - - - - -N6->N5 - - - - - - - 446.09MB - - - - - -N8 - - -quic-go -(*packetPacker) -getShortHeader -276.03MB (15.02%) - - - - - -N6->N8 - - - - - - - 276.03MB - - - - - -N7 - - -sync -(*Pool) -Get -0 of 248.65MB (13.53%) - - - - - -N12 - - -ackhandler -glob -func1 -160.01MB (8.71%) - - - - - -N7->N12 - - - - - - - 160.01MB - - - - - -N19 - - -wire -init -0 -func1 -70.60MB (3.84%) - - - - - -N7->N19 - - - - - - - 70.60MB - - - - - -N44 - - -wire -glob -func1 -15MB (0.82%) - - - - - -N7->N44 - - - - - - - 15MB - - - - - -NN8_0 - - - - - -128B - - - - - -N8->NN8_0 - - - - - - - 276.03MB - - - - - -N9 - - -congestion -NewConnectionStateOnSentPacket -236.03MB (12.84%) - - - - - -NN9_0 - - - - - -128B - - - - - -N9->NN9_0 - - - - - - - 236.03MB - - - - - -N10->N7 - - - - - - - 160.01MB - - - - - -N17 - - -ackhandler -(*sentPacketHandler) -SentPacket -0 of 296.29MB (16.12%) - - - - - -N10->N17 - - - - - - - 296.29MB - - - - - -N11 - - -linkedlist -(*List[…]) -insertValue -120MB (6.53%) - - - - - -NN11_0 - - - - - -32B - - - - - -N11->NN11_0 - - - - - - - 113.50MB - - - - - -NN12_0 - - - - - -96B - - - - - -N12->NN12_0 - - - - - - - 160.01MB - - - - - -NN13_0 - - - - - -64B - - - - - -N13->NN13_0 - - - - - - - 118.51MB - - - - - -N18 - - -bytes -NewBuffer -85.50MB (4.65%) - - - - - -N13->N18 - - - - - - - 85.50MB - (inline) - - - - - -N14 - - -ackhandler -(*receivedPacketHistory) -AppendAckRanges -115.54MB (6.29%) - - - - - -NN14_0 - - - - - -512B - - - - - -N14->NN14_0 - - - - - - - 51.53MB - - - - - -NN14_1 - - - - - -256B - - - - - -N14->NN14_1 - - - - - - - 29.51MB - - - - - -NN14_2 - - - - - -128B - - - - - -N14->NN14_2 - - - - - - - 20MB - - - - - -N15 - - -quic-go -(*connection) -handleFrames -0 of 228.96MB (12.46%) - - - - - -N21 - - -wire -(*frameParser) -parseFrame -0 of 109.58MB (5.96%) - - - - - -N15->N21 - - - - - - - 109.58MB - - - - - -N23 - - -quic-go -(*connection) -handleFrame -0 of 119.38MB (6.50%) - - - - - -N15->N23 - - - - - - - 119.38MB - - - - - -N16 - - -quic-go -(*sendStream) -popStreamFrame -111.50MB (6.07%) -of 142.05MB (7.73%) - - - - - -NN16_0 - - - - - -16B - - - - - -N16->NN16_0 - - - - - - - 57MB - - - - - -NN16_1 - - - - - -32B - - - - - -N16->NN16_1 - - - - - - - 54.50MB - - - - - -N29 - - -wire -GetStreamFrame -0 of 70.60MB (3.84%) - - - - - -N16->N29 - - - - - - - 30.54MB - (inline) - - - - - -N17->N9 - - - - - - - 236.03MB - (inline) - - - - - -N17->N11 - - - - - - - 57.50MB - (inline) - - - - - -NN18_0 - - - - - -48B - - - - - -N18->NN18_0 - - - - - - - 85.50MB - - - - - -NN19_0 - - - - - -1.50kB - - - - - -N19->NN19_0 - - - - - - - 70.60MB - - - - - -N20 - - -geodata -LoadGeoSiteMatcher -0 of 74.20MB (4.04%) - - - - - -N33 - - -router -NewMphMatcherGroup -0 of 57.15MB (3.11%) - - - - - -N20->N33 - - - - - - - 57.15MB - - - - - -N40 - - -reflect -New -13MB (0.71%) - - - - - -N20->N40 - - - - - - - 11.50MB - - - - - -N24 - - -wire -parseAckFrame -65.02MB (3.54%) -of 69.52MB (3.78%) - - - - - -N21->N24 - - - - - - - 69.52MB - - - - - -N21->N29 - - - - - - - 40.06MB - (inline) - - - - - -N22 - - -quic-go -(*basicConn) -ReadPacket -35.50MB (1.93%) -of 59.01MB (3.21%) - - - - - -N22->N7 - - - - - - - 2MB - - - - - -NN22_0 - - - - - -96B - - - - - -N22->NN22_0 - - - - - - - 35.50MB - - - - - -N37 - - -net -(*UDPConn) -ReadFrom -18.50MB (1.01%) -of 22MB (1.20%) - - - - - -N22->N37 - - - - - - - 21.50MB - - - - - -N41 - - -ackhandler -(*sentPacketHandler) -ReceivedAck -0 of 90.10MB (4.90%) - - - - - -N23->N41 - - - - - - - 90.10MB - - - - - -N42 - - -quic-go -(*receiveStream) -handleStreamFrameImpl -7MB (0.38%) -of 29.28MB (1.59%) - - - - - -N23->N42 - - - - - - - 29.28MB - - - - - -N24->N7 - - - - - - - 4.50MB - - - - - -NN24_0 - - - - - -512B - - - - - -N24->NN24_0 - - - - - - - 32.52MB - - - - - -NN24_1 - - - - - -256B - - - - - -N24->NN24_1 - - - - - - - 18MB - - - - - -N25->N16 - - - - - - - 142.05MB - - - - - -NN25_0 - - - - - -16B - - - - - -N25->NN25_0 - - - - - - - 15.50MB - - - - - -N26 - - -runtime -main -0 of 79.85MB (4.35%) - - - - - -N52 - - -main -main -0 of 78.85MB (4.29%) - - - - - -N26->N52 - - - - - - - 78.85MB - - - - - -N27 - - -strmatcher -(*MphMatcherGroup) -Build -37.85MB (2.06%) - - - - - -N28 - - -ackhandler -(*sentPacketHandler) -detectLostPackets -func1 -0 of 79.59MB (4.33%) - - - - - -N35 - - -quic-go -(*sendStream) -queueRetransmission -23.59MB (1.28%) - - - - - -N28->N35 - - - - - - - 23.59MB - - - - - -N43 - - -linkedlist -(*List[…]) -InsertAfter -0 of 62.50MB (3.40%) - - - - - -N28->N43 - - - - - - - 56MB - - - - - -N29->N7 - - - - - - - 70.60MB - - - - - -N30 - - -common -NewGEOSITE -0 of 74.20MB (4.04%) - - - - - -N30->N20 - - - - - - - 25.91MB - - - - - -N46 - - -geodata -Verify -0 of 51.44MB (2.80%) - - - - - -N30->N46 - - - - - - - 48.29MB - - - - - -N31 - - -quic-go -(*packetHandlerMap) -listen -0 of 59.01MB (3.21%) - - - - - -N31->N22 - - - - - - - 59.01MB - - - - - -N32 - - -http -HandlerFunc -ServeHTTP -0 of 26.60MB (1.45%) - - - - - -N47 - - -chi -(*Mux) -routeHTTP -0 of 26.60MB (1.45%) - - - - - -N32->N47 - - - - - - - 26.10MB - - - - - -N48 - - -chi -(*Mux) -ServeHTTP -0 of 26.10MB (1.42%) - - - - - -N32->N48 - - - - - - - 25.59MB - - - - - -N33->N27 - - - - - - - 37.85MB - - - - - -N38 - - -strmatcher -(*MphMatcherGroup) -AddFullOrDomainPattern -18.80MB (1.02%) - - - - - -N33->N38 - - - - - - - 18.80MB - (inline) - - - - - -N34->N7 - - - - - - - 10.50MB - - - - - -N34->N14 - - - - - - - 115.54MB - - - - - -N36->N15 - - - - - - - 228.96MB - - - - - -NN37_0 - - - - - -48B - - - - - -N37->NN37_0 - - - - - - - 18.50MB - - - - - -N39 - - -sync -(*poolChain) -pushHead -14.30MB (0.78%) - - - - - -NN40_0 - - - - - -96B - - - - - -N40->NN40_0 - - - - - - - 11.50MB - - - - - -N41->N28 - - - - - - - 79.59MB - - - - - -N41->N39 - - - - - - - 5.51MB - - - - - -NN42_0 - - - - - -16B - - - - - -N42->NN42_0 - - - - - - - 7MB - - - - - -N49 - - -quic-go -(*frameSorter) -push -5.28MB (0.29%) -of 22.28MB (1.21%) - - - - - -N42->N49 - - - - - - - 22.28MB - - - - - -N43->N11 - - - - - - - 62.50MB - (inline) - - - - - -NN44_0 - - - - - -64B - - - - - -N44->NN44_0 - - - - - - - 15MB - - - - - -N45 - - -flate -NewWriter -10.58MB (0.58%) -of 17.16MB (0.93%) - - - - - -NN45_0 - - - - - -648kB - - - - - -N45->NN45_0 - - - - - - - 10.58MB - - - - - -N46->N20 - - - - - - - 48.29MB - - - - - -N47->N32 - - - - - - - 26.60MB - - - - - -N53 - - -pprof -(*Profile) -WriteTo -0 of 22.36MB (1.22%) - - - - - -N47->N53 - - - - - - - 22.36MB - - - - - -N48->N32 - - - - - - - 26.10MB - - - - - -N51 - - -tree -insert[…] -11MB (0.6%) - - - - - -N49->N51 - - - - - - - 11MB - - - - - -N50 - - -http -(*conn) -serve -0 of 24.10MB (1.31%) - - - - - -N50->N48 - - - - - - - 24.10MB - - - - - -NN51_0 - - - - - -48B - - - - - -N51->NN51_0 - - - - - - - 11MB - - - - - -N52->N30 - - - - - - - 74.20MB - - - - - -N54 - - -pprof -writeHeapInternal -0 of 22.36MB (1.22%) - - - - - -N53->N54 - - - - - - - 22.36MB - - - - - -N55 - - -pprof -writeHeapProto -0 of 22.36MB (1.22%) - - - - - -N54->N55 - - - - - - - 22.36MB - - - - - -N55->N45 - - - - - - - 16.28MB - - - - - diff --git a/docs/heap.svg b/docs/heap.svg deleted file mode 100644 index 0795977f..00000000 --- a/docs/heap.svg +++ /dev/null @@ -1,2182 +0,0 @@ - - - - - - -unnamed - - -cluster_L - - - - -Type: inuse_space - -Type: inuse_space -Time: Jan 30, 2023 at 9:18pm (CST) -Showing nodes accounting for 12146.04kB, 100% of 12146.04kB total -Showing top 69 nodes out of 71 -See https://git.io/JfYMW for how to read the graph - - - -N1 - - -runtime -allocm -5637.50kB (46.41%) - - - - - -NN1_0 - - - - - -1kB - - - - - -N1->NN1_0 - - - - - - - 5637.50kB - - - - - -N2 - - -runtime -schedule -0 of 5637.50kB (46.41%) - - - - - -N68 - - -runtime -resetspinning -0 of 5637.50kB (46.41%) - - - - - -N2->N68 - - - - - - - 5637.50kB - - - - - -N3 - - -runtime -mstart -0 of 3587.50kB (29.54%) - - - - - -N62 - - -runtime -mstart0 -0 of 3587.50kB (29.54%) - - - - - -N3->N62 - - - - - - - 3587.50kB - - - - - -N4 - - -runtime -main -0 of 2836.92kB (23.36%) - - - - - -N61 - - -main -main -0 of 2836.92kB (23.36%) - - - - - -N4->N61 - - - - - - - 2836.92kB - - - - - -N5 - - -geodata -LoadGeoSiteMatcher -0 of 2836.92kB (23.36%) - - - - - -N10 - - -router -NewMphMatcherGroup -0 of 1812.91kB (14.93%) - - - - - -N5->N10 - - - - - - - 1812.91kB - - - - - -N27 - - -geodata -(*loader) -LoadGeoSite -0 of 1024.02kB (8.43%) - - - - - -N5->N27 - - - - - - - 1024.02kB - - - - - -N6 - - -strmatcher -(*MphMatcherGroup) -Build -1300.89kB (10.71%) - - - - - -NN6_0 - - - - - -1.14MB - - - - - -N6->NN6_0 - - - - - - - 1300.89kB - - - - - -N7 - - -runtime -mcall -0 of 2050kB (16.88%) - - - - - -N67 - - -runtime -park_m -0 of 2050kB (16.88%) - - - - - -N7->N67 - - - - - - - 2050kB - - - - - -N8 - - -impl -(*MessageInfo) -unmarshalPointer -0 of 1024.02kB (8.43%) - - - - - -N9 - - -impl -consumeStringValidateUTF8 -1024.02kB (8.43%) - - - - - -N8->N9 - - - - - - - 1024.02kB - - - - - -N58 - - -impl -consumeMessageSliceInfo -0 of 1024.02kB (8.43%) - - - - - -N8->N58 - - - - - - - 1024.02kB - - - - - -NN9_0 - - - - - -16B - - - - - -N9->NN9_0 - - - - - - - 1024.02kB - - - - - -N10->N6 - - - - - - - 1300.89kB - - - - - -N31 - - -strmatcher -(*MphMatcherGroup) -AddPattern -0 of 512.01kB (4.22%) - - - - - -N10->N31 - - - - - - - 512.01kB - - - - - -N11 - - -runtime -gcBgMarkWorker -512.02kB (4.22%) - - - - - -NN11_0 - - - - - -32B - - - - - -N11->NN11_0 - - - - - - - 512.02kB - - - - - -N12 - - -congestion -(*ConnectionStates) -Insert -596.16kB (4.91%) - - - - - -NN12_0 - - - - - -160kB - - - - - -N12->NN12_0 - - - - - - - 596.16kB - - - - - -N13 - - -bufio -NewReaderSize -514kB (4.23%) - - - - - -NN13_0 - - - - - -4kB - - - - - -N13->NN13_0 - - - - - - - 514kB - - - - - -N14 - - -quic-go -init -0 -func1 -512.75kB (4.22%) - - - - - -NN14_0 - - - - - -1.50kB - - - - - -N14->NN14_0 - - - - - - - 512.75kB - - - - - -N15 - - -trie -(*Node[…]) -optimize -512.44kB (4.22%) - - - - - -NN15_0 - - - - - -896B - - - - - -N15->NN15_0 - - - - - - - 512.44kB - - - - - -N16 - - -runtime -malg -512.20kB (4.22%) - - - - - -NN16_0 - - - - - -416B - - - - - -N16->NN16_0 - - - - - - - 512.20kB - - - - - -N17 - - -time -NewTicker -512.05kB (4.22%) - - - - - -NN17_0 - - - - - -96B - - - - - -N17->NN17_0 - - - - - - - 512.05kB - - - - - -N18 - - -strmatcher -(*MphMatcherGroup) -AddFullOrDomainPattern -512.01kB (4.22%) - - - - - -NN18_0 - - - - - -24B - - - - - -N18->NN18_0 - - - - - - - 512.01kB - - - - - -N19 - - -quic-go -(*client) -dial -func1 -0 of 596.16kB (4.91%) - - - - - -N49 - - -quic-go -(*connection) -run -0 of 596.16kB (4.91%) - - - - - -N19->N49 - - - - - - - 596.16kB - - - - - -N20 - - -mixed -handleConn -0 of 514kB (4.23%) - - - - - -N26 - - -net -NewBufferedConn -0 of 514kB (4.23%) - - - - - -N20->N26 - - - - - - - 514kB - - - - - -N21 - - -quic-go -(*packetHandlerMap) -listen -0 of 512.75kB (4.22%) - - - - - -N48 - - -quic-go -(*basicConn) -ReadPacket -0 of 512.75kB (4.22%) - - - - - -N21->N48 - - - - - - - 512.75kB - - - - - -N22 - - -executor -loadRuleProvider -func1 -0 of 512.44kB (4.22%) - - - - - -N40 - - -executor -loadProvider -0 of 512.44kB (4.22%) - - - - - -N22->N40 - - - - - - - 512.44kB - - - - - -N23 - - -runtime -systemstack -0 of 512.20kB (4.22%) - - - - - -N65 - - -runtime -newproc -func1 -0 of 512.20kB (4.22%) - - - - - -N23->N65 - - - - - - - 512.20kB - - - - - -N24 - - -statistic -(*Manager) -handle -0 of 512.05kB (4.22%) - - - - - -N24->N17 - - - - - - - 512.05kB - - - - - -N25 - - -bufio -NewReader -0 of 514kB (4.23%) - - - - - -N25->N13 - - - - - - - 514kB - (inline) - - - - - -N26->N25 - - - - - - - 514kB - (inline) - - - - - -N28 - - -geodata -(*loader) -LoadGeoSiteWithAttr -0 of 1024.02kB (8.43%) - - - - - -N27->N28 - - - - - - - 1024.02kB - - - - - -N29 - - -memconservative -(*memConservativeLoader) -LoadSiteByPath -0 of 1024.02kB (8.43%) - - - - - -N28->N29 - - - - - - - 1024.02kB - - - - - -N30 - - -memconservative -GeoSiteCache -Unmarshal -0 of 1024.02kB (8.43%) - - - - - -N29->N30 - - - - - - - 1024.02kB - - - - - -N59 - - -proto -Unmarshal -0 of 1024.02kB (8.43%) - - - - - -N30->N59 - - - - - - - 1024.02kB - - - - - -N31->N18 - - - - - - - 512.01kB - (inline) - - - - - -N32 - - -trie -(*DomainTrie[…]) -Optimize -0 of 512.44kB (4.22%) - - - - - -N32->N15 - - - - - - - 512.44kB - - - - - -N33 - - -config -Parse -0 of 2836.92kB (23.36%) - - - - - -N34 - - -config -ParseRawConfig -0 of 2836.92kB (23.36%) - - - - - -N33->N34 - - - - - - - 2836.92kB - - - - - -N35 - - -config -parseRules -0 of 2836.92kB (23.36%) - - - - - -N34->N35 - - - - - - - 2836.92kB - - - - - -N41 - - -rules -ParseRule -0 of 2836.92kB (23.36%) - - - - - -N35->N41 - - - - - - - 2836.92kB - - - - - -N36 - - -hub -Parse -0 of 2836.92kB (23.36%) - - - - - -N37 - - -executor -Parse -0 of 2836.92kB (23.36%) - - - - - -N36->N37 - - - - - - - 2836.92kB - (inline) - - - - - -N39 - - -executor -ParseWithPath -0 of 2836.92kB (23.36%) - - - - - -N37->N39 - - - - - - - 2836.92kB - - - - - -N38 - - -executor -ParseWithBytes -0 of 2836.92kB (23.36%) - - - - - -N38->N33 - - - - - - - 2836.92kB - - - - - -N39->N38 - - - - - - - 2836.92kB - (inline) - - - - - -N44 - - -provider -(*ruleSetProvider) -Initial -0 of 512.44kB (4.22%) - - - - - -N40->N44 - - - - - - - 512.44kB - - - - - -N42 - - -common -NewGEOSITE -0 of 2836.92kB (23.36%) - - - - - -N41->N42 - - - - - - - 2836.92kB - - - - - -N42->N5 - - - - - - - 2836.92kB - - - - - -N43 - - -provider -(*domainStrategy) -OnUpdate -0 of 512.44kB (4.22%) - - - - - -N43->N32 - - - - - - - 512.44kB - - - - - -N45 - - -provider -NewRuleSetProvider -func1 -0 of 512.44kB (4.22%) - - - - - -N44->N45 - - - - - - - 512.44kB - - - - - -N45->N43 - - - - - - - 512.44kB - - - - - -N46 - - -congestion -(*BandwidthSampler) -OnPacketSent -0 of 596.16kB (4.91%) - - - - - -N46->N12 - - - - - - - 596.16kB - (inline) - - - - - -N47 - - -congestion -(*bbrSender) -OnPacketSent -0 of 596.16kB (4.91%) - - - - - -N47->N46 - - - - - - - 596.16kB - - - - - -N53 - - -quic-go -getPacketBuffer -0 of 512.75kB (4.22%) - - - - - -N48->N53 - - - - - - - 512.75kB - (inline) - - - - - -N52 - - -quic-go -(*connection) -sendPackets -0 of 596.16kB (4.91%) - - - - - -N49->N52 - - - - - - - 596.16kB - - - - - -N50 - - -quic-go -(*connection) -sendPackedPacket -0 of 596.16kB (4.91%) - - - - - -N55 - - -ackhandler -(*sentPacketHandler) -SentPacket -0 of 596.16kB (4.91%) - - - - - -N50->N55 - - - - - - - 596.16kB - - - - - -N51 - - -quic-go -(*connection) -sendPacket -0 of 596.16kB (4.91%) - - - - - -N51->N50 - - - - - - - 596.16kB - - - - - -N52->N51 - - - - - - - 596.16kB - - - - - -N53->N14 - - - - - - - 512.75kB - - - - - -N54 - - -ackhandler -(*ccAdapter) -OnPacketSent -0 of 596.16kB (4.91%) - - - - - -N54->N47 - - - - - - - 596.16kB - - - - - -N56 - - -ackhandler -(*sentPacketHandler) -sentPacketImpl -0 of 596.16kB (4.91%) - - - - - -N55->N56 - - - - - - - 596.16kB - - - - - -N56->N54 - - - - - - - 596.16kB - - - - - -N57 - - -impl -(*MessageInfo) -unmarshal -0 of 1024.02kB (8.43%) - - - - - -N57->N8 - - - - - - - 1024.02kB - - - - - -N58->N8 - - - - - - - 1024.02kB - - - - - -N60 - - -proto -UnmarshalOptions -unmarshal -0 of 1024.02kB (8.43%) - - - - - -N59->N60 - - - - - - - 1024.02kB - - - - - -N60->N57 - - - - - - - 1024.02kB - - - - - -N61->N36 - - - - - - - 2836.92kB - - - - - -N63 - - -runtime -mstart1 -0 of 3587.50kB (29.54%) - - - - - -N62->N63 - - - - - - - 3587.50kB - - - - - -N63->N2 - - - - - - - 3587.50kB - - - - - -N64 - - -runtime -newm -0 of 5637.50kB (46.41%) - - - - - -N64->N1 - - - - - - - 5637.50kB - - - - - -N66 - - -runtime -newproc1 -0 of 512.20kB (4.22%) - - - - - -N65->N66 - - - - - - - 512.20kB - - - - - -N66->N16 - - - - - - - 512.20kB - - - - - -N67->N2 - - - - - - - 2050kB - - - - - -N69 - - -runtime -startm -0 of 5637.50kB (46.41%) - - - - - -N68->N69 - - - - - - - 5637.50kB - - - - - -N69->N64 - - - - - - - 5637.50kB - - - - - From c2d1f713059f8483ed4ff76242d666bbc61123b3 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 14 Apr 2023 19:06:25 +0800 Subject: [PATCH 207/530] fix: ruleProvider panic --- rules/provider/provider.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/rules/provider/provider.go b/rules/provider/provider.go index a4271655..65d21d2f 100644 --- a/rules/provider/provider.go +++ b/rules/provider/provider.go @@ -187,6 +187,9 @@ func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (any, er firstLineLength = -1 // don't return ErrNoPayload when read last line str = string(line) str = strings.TrimSpace(str) + if len(str) == 0 { + continue + } if str[0] == '#' { // comment continue } @@ -194,7 +197,11 @@ func rulesParse(buf []byte, strategy ruleStrategy, format P.RuleFormat) (any, er continue } case P.YamlRule: - if bytes.TrimSpace(line)[0] == '#' { // comment + trimLine := bytes.TrimSpace(line) + if len(trimLine) == 0 { + continue + } + if trimLine[0] == '#' { // comment continue } firstLineBuffer.Write(line) From 8e5dbc738291e96e87ad42705a80776fe43c6500 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 15 Apr 2023 16:56:43 +0800 Subject: [PATCH 208/530] chore: Update dependencies --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 18d3fb3e..971d4291 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-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 - github.com/metacubex/sing-shadowsocks v0.2.2-0.20230409073201-1ce3505114ae + github.com/metacubex/sing-shadowsocks v0.2.2-0.20230414151724-274b69df9875 github.com/metacubex/sing-tun v0.1.3 github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 github.com/miekg/dns v1.1.52 @@ -28,9 +28,9 @@ require ( 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.3-0.20230413112320-59e662e6e2ed - github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 - github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 + github.com/sagernet/sing v0.2.3 + github.com/sagernet/sing-shadowtls v0.1.1 + github.com/sagernet/sing-vmess 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-20221116151939-c99467f53f2c diff --git a/go.sum b/go.sum index aea0ce98..c45880a9 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 h1:gREIdurac9fpyB github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03/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.20230409073201-1ce3505114ae h1:SNnvqnJrqVErz1Qoo3thxa4lgdTPgBSQpJKQJcQjz9Y= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230409073201-1ce3505114ae/go.mod h1:JefDbbkQHCn8w+IcjFqMOMV2VmN9wvbYX4RaeBUkPwM= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230414151724-274b69df9875 h1:TrTg8JY//QOu4JZuXjKzB35Gppz4B4Us9EIvtdno6vo= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230414151724-274b69df9875/go.mod h1:0ebzwmiUVa4wAmjhzaEx5BgeuhJFT5QYO0oxwolKlYE= github.com/metacubex/sing-tun v0.1.3 h1:LCz8TlAZUWwnBYZxs1PEE04PyfLA9xdsye6CjHZlZGQ= github.com/metacubex/sing-tun v0.1.3/go.mod h1:kHkYHoRlYA4I12QPTt/ADyRGqy5YweLUfye1E1hC/q4= github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 h1:itjCqEeem+BKZFiBEhQmWHDHKK4FgTGvnYCFS0JOb3A= @@ -144,12 +144,12 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.3-0.20230413112320-59e662e6e2ed h1:7Vg+lQanPwjxdYaln/EpKK7OcClvoUNm7Tt9V0FPnpY= -github.com/sagernet/sing v0.2.3-0.20230413112320-59e662e6e2ed/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661 h1:QnV79JbJbJGT0MJJfd8o7QMEfRu3eUVKsmahxFMonrc= -github.com/sagernet/sing-shadowtls v0.1.1-0.20230408141548-81d74d2a8661/go.mod h1:xCeSRP8cV32aPsY+6BbRdJjyD6q8ufdKwhgqxEbU/3U= -github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7 h1:ZArINfN+zcHMdZCeRFOm4rO3SWyvYuLg3VhWcA5zonc= -github.com/sagernet/sing-vmess v0.1.4-0.20230409073451-6921c3dd77c7/go.mod h1:A9iGfwYmAEmVg8bavkqQ7Hx7nr9Pc2oWMYDwbLIBDjY= +github.com/sagernet/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk= +github.com/sagernet/sing v0.2.3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing-shadowtls v0.1.1 h1:Gf8YD/4zCjfM9xxVzI0QVYAnjMCtsDHcIp84CUdY3VA= +github.com/sagernet/sing-shadowtls v0.1.1/go.mod h1:espnHDPRQeG95ZoU3xfHDFnc6Nt4GvbbuPV2okN+x/E= +github.com/sagernet/sing-vmess v0.1.4 h1:aZ03KgmR9COPitVqo8NTPHeaHmbJYDZ8mkumnUV4oGQ= +github.com/sagernet/sing-vmess v0.1.4/go.mod h1:NensKZJDgfPsUf3TzFD8kTuzI3CQfN1Tj3Eygti5Isg= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= From 4a0d097fe9f1b8fe352267040658331168e8abd8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 17 Apr 2023 00:23:12 +0800 Subject: [PATCH 209/530] fix: ensure StreamWebsocketConn call N.NewDeadlineConn --- common/net/bufconn.go | 4 ++++ transport/vmess/websocket.go | 14 +++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/common/net/bufconn.go b/common/net/bufconn.go index 8087608c..f01a3dda 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -79,3 +79,7 @@ func (c *BufferedConn) ReaderReplaceable() bool { } return true } + +func (c *BufferedConn) WriterReplaceable() bool { + return true +} diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 179da886..e7335d84 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -334,7 +334,10 @@ func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Co underlay: conn, config: c, } - return conn, nil + // websocketWithEarlyDataConn can't correct handle Deadline + // it will not apply the already set Deadline after Dial() + // so call N.NewDeadlineConn to add a safe wrapper + return N.NewDeadlineConn(conn), nil } func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { @@ -402,11 +405,16 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf return nil, fmt.Errorf("dial %s error: %s", uri.Host, reason) } - return &websocketConn{ + conn = &websocketConn{ conn: wsConn, rawWriter: N.NewExtendedWriter(wsConn.UnderlyingConn()), remoteAddr: conn.RemoteAddr(), - }, nil + } + // websocketConn can't correct handle ReadDeadline + // gorilla/websocket will cache the os.ErrDeadlineExceeded from conn.Read() + // it will cause read fail and event panic in *websocket.Conn.NextReader() + // so call N.NewDeadlineConn to add a safe wrapper + return N.NewDeadlineConn(conn), nil } func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) { From 495033270cc1d7ce2f9350ad46eb0363c5ffdaf0 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 17 Apr 2023 19:29:07 +0800 Subject: [PATCH 210/530] chore: using new chan based deadline reader --- adapter/outbound/base.go | 11 +++++++++-- common/net/sing.go | 10 ++-------- component/dialer/tfo.go | 4 ++++ go.mod | 8 ++++---- go.sum | 16 ++++++++-------- listener/shadowsocks/tcp.go | 3 ++- listener/shadowsocks/udp.go | 3 +-- listener/sing/sing.go | 4 ++++ 8 files changed, 34 insertions(+), 25 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 0d6cdb8c..04eec966 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -5,6 +5,7 @@ import ( "encoding/json" "net" "strings" + "syscall" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/utils" @@ -204,7 +205,10 @@ func (c *conn) Upstream() any { } func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { - return &conn{N.NewDeadlineConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())} + if _, ok := c.(syscall.Conn); !ok { // exclusion system conn like *net.TCPConn + c = N.NewDeadlineConn(c) // most conn from outbound can't handle readDeadline correctly + } + return &conn{N.NewExtendedConn(c), []string{a.Name()}, parseRemoteDestination(a.Addr())} } type packetConn struct { @@ -235,7 +239,10 @@ func (c *packetConn) LocalAddr() net.Addr { } func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn { - return &packetConn{N.NewDeadlinePacketConn(pc), []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} + if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn + pc = N.NewDeadlinePacketConn(pc) // most conn from outbound can't handle readDeadline correctly + } + return &packetConn{pc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} } func parseRemoteDestination(addr string) string { diff --git a/common/net/sing.go b/common/net/sing.go index 4aad5523..89517326 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -19,17 +19,11 @@ type ExtendedWriter = network.ExtendedWriter type ExtendedReader = network.ExtendedReader func NewDeadlineConn(conn net.Conn) ExtendedConn { - if dc, ok := conn.(*deadline.Conn); ok { - return dc - } - return deadline.NewConn(conn) + return deadline.NewFallbackConn(conn) } func NewDeadlinePacketConn(pc net.PacketConn) net.PacketConn { - if dpc, ok := pc.(*deadline.PacketConn); ok { - return dpc - } - return deadline.NewPacketConn(bufio.NewPacketConn(pc)) + return deadline.NewFallbackPacketConn(bufio.NewPacketConn(pc)) } func NeedHandshake(conn any) bool { diff --git a/component/dialer/tfo.go b/component/dialer/tfo.go index 0041a976..d5337bdb 100644 --- a/component/dialer/tfo.go +++ b/component/dialer/tfo.go @@ -105,6 +105,10 @@ func (c *tfoConn) Upstream() any { return c.Conn } +func (c *tfoConn) NeedAdditionalReadDeadline() bool { + return c.Conn == nil +} + func (c *tfoConn) NeedHandshake() bool { return c.Conn == nil } diff --git a/go.mod b/go.mod index 971d4291..eb2957a7 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-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 - github.com/metacubex/sing-shadowsocks v0.2.2-0.20230414151724-274b69df9875 + github.com/metacubex/sing-shadowsocks v0.2.2-0.20230417103204-e2bcd32a73cc github.com/metacubex/sing-tun v0.1.3 github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 github.com/miekg/dns v1.1.52 @@ -28,9 +28,9 @@ require ( 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.3 - github.com/sagernet/sing-shadowtls v0.1.1 - github.com/sagernet/sing-vmess v0.1.4 + github.com/sagernet/sing v0.2.4-0.20230417103520-0b4d134fe945 + github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b + 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-20221116151939-c99467f53f2c diff --git a/go.sum b/go.sum index c45880a9..45cdfeff 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 h1:gREIdurac9fpyB github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03/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.20230414151724-274b69df9875 h1:TrTg8JY//QOu4JZuXjKzB35Gppz4B4Us9EIvtdno6vo= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230414151724-274b69df9875/go.mod h1:0ebzwmiUVa4wAmjhzaEx5BgeuhJFT5QYO0oxwolKlYE= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230417103204-e2bcd32a73cc h1:ctwahnHNAgoicCUJqKrHNVcyjEeNIoK4Dqyjh5uIkEE= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230417103204-e2bcd32a73cc/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= github.com/metacubex/sing-tun v0.1.3 h1:LCz8TlAZUWwnBYZxs1PEE04PyfLA9xdsye6CjHZlZGQ= github.com/metacubex/sing-tun v0.1.3/go.mod h1:kHkYHoRlYA4I12QPTt/ADyRGqy5YweLUfye1E1hC/q4= github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 h1:itjCqEeem+BKZFiBEhQmWHDHKK4FgTGvnYCFS0JOb3A= @@ -144,12 +144,12 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.3 h1:V50MvZ4c3Iij2lYFWPlzL1PyipwSzjGeN9x+Ox89vpk= -github.com/sagernet/sing v0.2.3/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-shadowtls v0.1.1 h1:Gf8YD/4zCjfM9xxVzI0QVYAnjMCtsDHcIp84CUdY3VA= -github.com/sagernet/sing-shadowtls v0.1.1/go.mod h1:espnHDPRQeG95ZoU3xfHDFnc6Nt4GvbbuPV2okN+x/E= -github.com/sagernet/sing-vmess v0.1.4 h1:aZ03KgmR9COPitVqo8NTPHeaHmbJYDZ8mkumnUV4oGQ= -github.com/sagernet/sing-vmess v0.1.4/go.mod h1:NensKZJDgfPsUf3TzFD8kTuzI3CQfN1Tj3Eygti5Isg= +github.com/sagernet/sing v0.2.4-0.20230417103520-0b4d134fe945 h1:mh7/K6IU1ZJ2CKRyfnyq3G/zKQVoBSVw8oWtaR1Hj6M= +github.com/sagernet/sing v0.2.4-0.20230417103520-0b4d134fe945/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +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-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/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBTxV0/eClCklHrFSQMnUGcpUmJxVeE= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index 4e25a7b9..6884b960 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -100,7 +100,8 @@ func (l *Listener) AddrList() (addrList []net.Addr) { } func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { - conn = N.NewDeadlineConn(l.pickCipher.StreamConn(conn)) + conn = l.pickCipher.StreamConn(conn) + conn = N.NewDeadlineConn(conn) // embed ss can't handle readDeadline correctly target, err := socks5.ReadAddr(conn, make([]byte, socks5.MaxAddrLen)) if err != nil { diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index d884c2b8..3f058406 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -4,7 +4,6 @@ import ( "net" "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/common/sockopt" C "github.com/Dreamacro/clash/constant" @@ -30,7 +29,7 @@ func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UD } sl := &UDPListener{l, false} - conn := N.NewDeadlinePacketConn(pickCipher.PacketConn(l)) + conn := pickCipher.PacketConn(l) go func() { for { buf := pool.Get(pool.RelayBufferSize) diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 7421a4f1..2941f6ca 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -17,6 +17,7 @@ import ( vmess "github.com/sagernet/sing-vmess" "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio/deadline" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/network" @@ -80,6 +81,9 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta defer wg.Wait() // this goroutine must exit after conn.Close() wg.Add(1) + if deadline.NeedAdditionalReadDeadline(conn) { + conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline + } h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, additions...) return nil } From cae9cf44cfd0cba017ebb5486b7aef3a58fda6ac Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 17 Apr 2023 19:46:57 +0800 Subject: [PATCH 211/530] 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 eb2957a7..1cf8d35a 100644 --- a/go.mod +++ b/go.mod @@ -15,15 +15,15 @@ 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-20230307103557-e252950ab961 + github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230417103204-e2bcd32a73cc - github.com/metacubex/sing-tun v0.1.3 + github.com/metacubex/sing-tun v0.1.4-0.20230417114323-ef78a871e13f github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 - github.com/miekg/dns v1.1.52 + github.com/miekg/dns v1.1.53 github.com/mroth/weightedrand/v2 v2.0.0 github.com/openacid/low v0.1.21 github.com/oschwald/geoip2-golang v1.8.0 @@ -34,7 +34,7 @@ require ( 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-20221116151939-c99467f53f2c - github.com/samber/lo v1.37.0 + github.com/samber/lo v1.38.1 github.com/shirou/gopsutil/v3 v3.23.3 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.2 @@ -75,7 +75,7 @@ require ( github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/mdlayher/socket v0.4.0 // indirect - github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 // indirect + github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c // indirect github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.2.0 // indirect diff --git a/go.sum b/go.sum index 45cdfeff..553498a8 100644 --- a/go.sum +++ b/go.sum @@ -68,8 +68,8 @@ github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad 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/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/insomniacslk/dhcp v0.0.0-20230307103557-e252950ab961 h1:x/YtdDlmypenG1te/FfH6LVM+3krhXk5CFV8VYNNX5M= -github.com/insomniacslk/dhcp v0.0.0-20230307103557-e252950ab961/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI= +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/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= @@ -92,20 +92,20 @@ github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 h1:HSkXG1bE/qcR 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/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03 h1:gREIdurac9fpyBMBRPPMF/Sk3gKfPfdNCa4GQyR9FoA= -github.com/metacubex/gvisor v0.0.0-20230323114922-412956fb6a03/go.mod h1:wqEuzdImyqD2MCGE8CYRJXbB77oSEJeoSSXXdwKjnsE= +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.20230417103204-e2bcd32a73cc h1:ctwahnHNAgoicCUJqKrHNVcyjEeNIoK4Dqyjh5uIkEE= github.com/metacubex/sing-shadowsocks v0.2.2-0.20230417103204-e2bcd32a73cc/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= -github.com/metacubex/sing-tun v0.1.3 h1:LCz8TlAZUWwnBYZxs1PEE04PyfLA9xdsye6CjHZlZGQ= -github.com/metacubex/sing-tun v0.1.3/go.mod h1:kHkYHoRlYA4I12QPTt/ADyRGqy5YweLUfye1E1hC/q4= +github.com/metacubex/sing-tun v0.1.4-0.20230417114323-ef78a871e13f h1:vS2bII9IjwpNaf311kWn9hi7p6WSzHM4dFdvmYECvEs= +github.com/metacubex/sing-tun v0.1.4-0.20230417114323-ef78a871e13f/go.mod h1:ifLPYzRpV/u8bLE39zGb4nuX1NuUqzzLZmF8iZvxjIA= github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 h1:itjCqEeem+BKZFiBEhQmWHDHKK4FgTGvnYCFS0JOb3A= github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= -github.com/miekg/dns v1.1.52 h1:Bmlc/qsNNULOe6bpXcUTsuOajd0DzRHwup6D9k1An0c= -github.com/miekg/dns v1.1.52/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= +github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= 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= @@ -156,8 +156,8 @@ github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfI github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= -github.com/samber/lo v1.37.0 h1:XjVcB8g6tgUp8rsPsJ2CvhClfImrpL04YpQHXeHPhRw= -github.com/samber/lo v1.37.0/go.mod h1:9vaz2O4o8oOnK23pd2TrXufcbdbJIa3b6cstBWKpopA= +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.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE= github.com/shirou/gopsutil/v3 v3.23.3/go.mod h1:lSBNN6t3+D6W5e5nXTxc8KIMMVxAcS+6IJlffjRRlMU= github.com/shoenig/go-m1cpu v0.1.4/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= From f100ce6a04818e1aad53b7854c93bb85d2442353 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 17 Apr 2023 20:38:37 +0800 Subject: [PATCH 212/530] chore: Adopt sing-tun's update --- go.mod | 2 +- go.sum | 4 ++-- listener/sing_tun/server.go | 15 ++++++++++++--- listener/sing_tun/tun_name_darwin.go | 11 +++++++++++ listener/sing_tun/tun_name_linux.go | 25 +++++++++++++++++++++++++ listener/sing_tun/tun_name_other.go | 9 +++++++++ 6 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 listener/sing_tun/tun_name_darwin.go create mode 100644 listener/sing_tun/tun_name_linux.go create mode 100644 listener/sing_tun/tun_name_other.go diff --git a/go.mod b/go.mod index 1cf8d35a..fc2783f7 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230417103204-e2bcd32a73cc - github.com/metacubex/sing-tun v0.1.4-0.20230417114323-ef78a871e13f + github.com/metacubex/sing-tun v0.1.4-0.20230417120711-05d852989e84 github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 github.com/miekg/dns v1.1.53 github.com/mroth/weightedrand/v2 v2.0.0 diff --git a/go.sum b/go.sum index 553498a8..f42dba4c 100644 --- a/go.sum +++ b/go.sum @@ -98,8 +98,8 @@ github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 h1:KD96JPdTIa 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.20230417103204-e2bcd32a73cc h1:ctwahnHNAgoicCUJqKrHNVcyjEeNIoK4Dqyjh5uIkEE= github.com/metacubex/sing-shadowsocks v0.2.2-0.20230417103204-e2bcd32a73cc/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= -github.com/metacubex/sing-tun v0.1.4-0.20230417114323-ef78a871e13f h1:vS2bII9IjwpNaf311kWn9hi7p6WSzHM4dFdvmYECvEs= -github.com/metacubex/sing-tun v0.1.4-0.20230417114323-ef78a871e13f/go.mod h1:ifLPYzRpV/u8bLE39zGb4nuX1NuUqzzLZmF8iZvxjIA= +github.com/metacubex/sing-tun v0.1.4-0.20230417120711-05d852989e84 h1:3L4glttGciACRBYV1Z1eglcYFYWiXmTExWjTySgaGdM= +github.com/metacubex/sing-tun v0.1.4-0.20230417120711-05d852989e84/go.mod h1:kHkYHoRlYA4I12QPTt/ADyRGqy5YweLUfye1E1hC/q4= github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 h1:itjCqEeem+BKZFiBEhQmWHDHKK4FgTGvnYCFS0JOb3A= github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index ada9d1c2..5f691b44 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -229,8 +229,8 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte err = E.Cause(err, "configure tun interface") return } - l.tunIf = tunIf - l.tunStack, err = tun.NewStack(strings.ToLower(options.Stack.String()), tun.StackOptions{ + + stackOptions := tun.StackOptions{ Context: context.TODO(), Tun: tunIf, MTU: tunOptions.MTU, @@ -241,7 +241,16 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte UDPTimeout: udpTimeout, Handler: handler, Logger: log.SingLogger, - }) + } + + if options.FileDescriptor > 0 { + if tunName, err := getTunnelName(int32(options.FileDescriptor)); err != nil { + stackOptions.Name = tunName + stackOptions.UnderPlatform = true + } + } + l.tunIf = tunIf + l.tunStack, err = tun.NewStack(strings.ToLower(options.Stack.String()), stackOptions) if err != nil { return } diff --git a/listener/sing_tun/tun_name_darwin.go b/listener/sing_tun/tun_name_darwin.go new file mode 100644 index 00000000..5b4686ea --- /dev/null +++ b/listener/sing_tun/tun_name_darwin.go @@ -0,0 +1,11 @@ +package sing_tun + +import "golang.org/x/sys/unix" + +func getTunnelName(fd int32) (string, error) { + return unix.GetsockoptString( + int(fd), + 2, /* #define SYSPROTO_CONTROL 2 */ + 2, /* #define UTUN_OPT_IFNAME 2 */ + ) +} diff --git a/listener/sing_tun/tun_name_linux.go b/listener/sing_tun/tun_name_linux.go new file mode 100644 index 00000000..9ae9800b --- /dev/null +++ b/listener/sing_tun/tun_name_linux.go @@ -0,0 +1,25 @@ +package sing_tun + +import ( + "fmt" + "golang.org/x/sys/unix" + "syscall" + "unsafe" +) + +const ifReqSize = unix.IFNAMSIZ + 64 + +func getTunnelName(fd int32) (string, error) { + var ifr [ifReqSize]byte + var errno syscall.Errno + _, _, errno = unix.Syscall( + unix.SYS_IOCTL, + uintptr(fd), + uintptr(unix.TUNGETIFF), + uintptr(unsafe.Pointer(&ifr[0])), + ) + if errno != 0 { + return "", fmt.Errorf("failed to get name of TUN device: %w", errno) + } + return unix.ByteSliceToString(ifr[:]), nil +} diff --git a/listener/sing_tun/tun_name_other.go b/listener/sing_tun/tun_name_other.go new file mode 100644 index 00000000..c47c8cbe --- /dev/null +++ b/listener/sing_tun/tun_name_other.go @@ -0,0 +1,9 @@ +//go:build !(darwin || linux) + +package sing_tun + +import "os" + +func getTunnelName(fd int32) (string, error) { + return "", os.ErrInvalid +} From 47df97322db5e4dc28a4c39441c27b401bf53ca6 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 17 Apr 2023 23:42:15 +0800 Subject: [PATCH 213/530] fix: h2 close panic --- transport/vmess/h2.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/transport/vmess/h2.go b/transport/vmess/h2.go index 6901f61e..f91c2766 100644 --- a/transport/vmess/h2.go +++ b/transport/vmess/h2.go @@ -1,6 +1,7 @@ package vmess import ( + "context" "io" "net" "net/http" @@ -84,10 +85,16 @@ func (hc *h2Conn) Write(b []byte) (int, error) { } func (hc *h2Conn) Close() error { - if err := hc.pwriter.Close(); err != nil { - return err + if hc.pwriter != nil { + if err := hc.pwriter.Close(); err != nil { + return err + } } - if err := hc.ClientConn.Shutdown(hc.res.Request.Context()); err != nil { + ctx := context.Background() + if hc.res != nil { + ctx = hc.res.Request.Context() + } + if err := hc.ClientConn.Shutdown(ctx); err != nil { return err } return hc.Conn.Close() From 4ef99294e7441fdf1242744684b003a3f75840c9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 19 Apr 2023 19:25:21 +0800 Subject: [PATCH 214/530] chore: rewrite verifyIP6 --- config/utils.go | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/config/utils.go b/config/utils.go index 2c470618..799082c4 100644 --- a/config/utils.go +++ b/config/utils.go @@ -3,6 +3,7 @@ package config import ( "fmt" "net" + "net/netip" "strings" "github.com/Dreamacro/clash/adapter/outboundgroup" @@ -149,20 +150,11 @@ func proxyGroupsDagSort(groupsConfig []map[string]any) error { } func verifyIP6() bool { - addrs, err := net.InterfaceAddrs() - if err != nil { - return false - } - for _, addr := range addrs { - ipNet, isIpNet := addr.(*net.IPNet) - if isIpNet && !ipNet.IP.IsLoopback() { - if ipNet.IP.To16() != nil { - s := ipNet.IP.String() - for i := 0; i < len(s); i++ { - switch s[i] { - case ':': - return true - } + if iAddrs, err := net.InterfaceAddrs(); err == nil { + for _, addr := range iAddrs { + if prefix, err := netip.ParsePrefix(addr.String()); err == nil { + if addr := prefix.Addr().Unmap(); addr.Is6() && addr.IsGlobalUnicast() { + return true } } } From dd60baf9d4c417f5e3733a2dad28f7443da62874 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 19 Apr 2023 23:50:57 +0800 Subject: [PATCH 215/530] fix: revert LRU cache changes --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index fc2783f7..fe3940e4 100644 --- a/go.mod +++ b/go.mod @@ -20,15 +20,15 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 - github.com/metacubex/sing-shadowsocks v0.2.2-0.20230417103204-e2bcd32a73cc - github.com/metacubex/sing-tun v0.1.4-0.20230417120711-05d852989e84 + github.com/metacubex/sing-shadowsocks v0.2.2-0.20230419154412-11ec6808f588 + github.com/metacubex/sing-tun v0.1.4-0.20230419154912-049c66801ff8 github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 github.com/miekg/dns v1.1.53 github.com/mroth/weightedrand/v2 v2.0.0 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.4-0.20230417103520-0b4d134fe945 + github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index f42dba4c..9dcbe783 100644 --- a/go.sum +++ b/go.sum @@ -96,10 +96,10 @@ github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+ 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.20230417103204-e2bcd32a73cc h1:ctwahnHNAgoicCUJqKrHNVcyjEeNIoK4Dqyjh5uIkEE= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230417103204-e2bcd32a73cc/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= -github.com/metacubex/sing-tun v0.1.4-0.20230417120711-05d852989e84 h1:3L4glttGciACRBYV1Z1eglcYFYWiXmTExWjTySgaGdM= -github.com/metacubex/sing-tun v0.1.4-0.20230417120711-05d852989e84/go.mod h1:kHkYHoRlYA4I12QPTt/ADyRGqy5YweLUfye1E1hC/q4= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230419154412-11ec6808f588 h1:bOuVbeG5iwYyiDB2am3xIrt7GwbZC8cZIoJqLtvkcfY= +github.com/metacubex/sing-shadowsocks v0.2.2-0.20230419154412-11ec6808f588/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= +github.com/metacubex/sing-tun v0.1.4-0.20230419154912-049c66801ff8 h1:BQFEnZUnPvmER8JIQPsfaaWzMXOvY5o+2ToDcRfAh58= +github.com/metacubex/sing-tun v0.1.4-0.20230419154912-049c66801ff8/go.mod h1:5CR2e0WQQiLSPd46Qaz3uhDRRik3QvvXiyMvlT3bXoc= github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 h1:itjCqEeem+BKZFiBEhQmWHDHKK4FgTGvnYCFS0JOb3A= github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= @@ -144,8 +144,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.4-0.20230417103520-0b4d134fe945 h1:mh7/K6IU1ZJ2CKRyfnyq3G/zKQVoBSVw8oWtaR1Hj6M= -github.com/sagernet/sing v0.2.4-0.20230417103520-0b4d134fe945/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1 h1:CdzNL25lzfVo0NMeghPqsupNsWvkzrbrUt5t8DoDPcQ= +github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= 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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= From 31095e4a8cf72d7f3b7c822d03b37e1cab702d46 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 20 Apr 2023 09:38:08 +0800 Subject: [PATCH 216/530] fix: vless udp not working --- adapter/outbound/vless.go | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 5f7c2087..d7db27d5 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -174,17 +174,18 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err error) { if metadata.NetWork == C.UDP { - metadata = &C.Metadata{ // a clear metadata only contains ip - NetWork: metadata.NetWork, - DstIP: metadata.DstIP, - DstPort: metadata.DstPort, - } if v.option.PacketAddr { metadata = &C.Metadata{ NetWork: C.UDP, Host: packetaddr.SeqPacketMagicAddress, DstPort: "443", } + } else { + metadata = &C.Metadata{ // a clear metadata only contains ip + NetWork: C.UDP, + DstIP: metadata.DstIP, + DstPort: metadata.DstPort, + } } conn, err = v.client.StreamConn(c, parseVlessAddr(metadata, v.option.XUDP)) if v.option.PacketAddr { @@ -346,7 +347,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met safeConnClose(c, err) }(c) - c, err = v.streamConn(c, metadata) + c, err = v.StreamConn(c, metadata) if err != nil { return nil, fmt.Errorf("new vless client error: %v", err) } @@ -372,13 +373,13 @@ func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada if v.option.XUDP { return newPacketConn(&threadSafePacketConn{ - PacketConn: vmessSing.NewXUDPConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), + PacketConn: vmessSing.NewXUDPConn(c, M.SocksaddrFromNet(metadata.UDPAddr())), }, v), nil } else if v.option.PacketAddr { return newPacketConn(&threadSafePacketConn{ PacketConn: packetaddr.NewConn(&vlessPacketConn{ Conn: c, rAddr: metadata.UDPAddr(), - }, M.ParseSocksaddr(metadata.RemoteAddress())), + }, M.SocksaddrFromNet(metadata.UDPAddr())), }, v), nil } return newPacketConn(&vlessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil From ec234ac0a88a16d24bbffc7e8a80f243d41dd7dd Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 20 Apr 2023 10:22:51 +0800 Subject: [PATCH 217/530] chore: clear windows bind error --- component/dialer/bind_windows.go | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/component/dialer/bind_windows.go b/component/dialer/bind_windows.go index 4a099169..0d38d1c5 100644 --- a/component/dialer/bind_windows.go +++ b/component/dialer/bind_windows.go @@ -3,6 +3,7 @@ package dialer import ( "context" "encoding/binary" + "fmt" "net" "net/netip" "syscall" @@ -20,11 +21,19 @@ func bind4(handle syscall.Handle, ifaceIdx int) error { var bytes [4]byte binary.BigEndian.PutUint32(bytes[:], uint32(ifaceIdx)) idx := *(*uint32)(unsafe.Pointer(&bytes[0])) - return syscall.SetsockoptInt(handle, syscall.IPPROTO_IP, IP_UNICAST_IF, int(idx)) + err := syscall.SetsockoptInt(handle, syscall.IPPROTO_IP, IP_UNICAST_IF, int(idx)) + if err != nil { + err = fmt.Errorf("bind4: %w", err) + } + return err } func bind6(handle syscall.Handle, ifaceIdx int) error { - return syscall.SetsockoptInt(handle, syscall.IPPROTO_IPV6, IPV6_UNICAST_IF, ifaceIdx) + err := syscall.SetsockoptInt(handle, syscall.IPPROTO_IPV6, IPV6_UNICAST_IF, ifaceIdx) + if err != nil { + err = fmt.Errorf("bind6: %w", err) + } + return err } func bindControl(ifaceIdx int) controlFn { @@ -49,9 +58,9 @@ func bindControl(ifaceIdx int) controlFn { if (!addrPort.Addr().IsValid() || addrPort.Addr().IsUnspecified()) && bind6err != nil { // try bind ipv6, if failed, ignore. it's a workaround for windows disable interface ipv6 if bind4err != nil { - innerErr = bind6err + innerErr = fmt.Errorf("%w (%s)", bind6err, bind4err) } else { - innerErr = bind4err + innerErr = nil } } else { innerErr = bind6err From 75137615406a134924c3457c9315d24b96445ce4 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 20 Apr 2023 05:45:22 +0000 Subject: [PATCH 218/530] fix: not match top domain --- component/sniffer/dispatcher.go | 16 ++++++++-------- component/trie/domain.go | 5 ++++- component/trie/domain_set_test.go | 8 ++++++++ 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index bf0b1bb3..fa1c6827 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -26,14 +26,14 @@ 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) { diff --git a/component/trie/domain.go b/component/trie/domain.go index 86e5245a..3decbb02 100644 --- a/component/trie/domain.go +++ b/component/trie/domain.go @@ -25,7 +25,7 @@ func ValidAndSplitDomain(domain string) ([]string, bool) { if domain != "" && domain[len(domain)-1] == '.' { return nil, false } - domain=strings.ToLower(domain) + domain = strings.ToLower(domain) parts := strings.Split(domain, domainStep) if len(parts) == 1 { if parts[0] == "" { @@ -126,6 +126,9 @@ func (t *DomainTrie[T]) Optimize() { func (t *DomainTrie[T]) Foreach(print func(domain string, data T)) { for key, data := range t.root.getChildren() { recursion([]string{key}, data, print) + if data != nil && data.inited { + print(joinDomain([]string{key}), data.data) + } } } diff --git a/component/trie/domain_set_test.go b/component/trie/domain_set_test.go index 090bd495..c4160f6c 100644 --- a/component/trie/domain_set_test.go +++ b/component/trie/domain_set_test.go @@ -15,6 +15,9 @@ func TestDomainSet(t *testing.T) { "www.google.com", "test.a.net", "test.a.oc", + "Mijia Cloud", + ".qq.com", + "+.cn", } for _, domain := range domainSet { @@ -22,8 +25,13 @@ func TestDomainSet(t *testing.T) { } set := tree.NewDomainSet() assert.NotNil(t, set) + assert.True(t, set.Has("test.cn")) + assert.True(t, set.Has("cn")) + assert.True(t, set.Has("Mijia Cloud")) assert.True(t, set.Has("test.a.net")) + assert.True(t, set.Has("www.qq.com")) assert.True(t, set.Has("google.com")) + assert.False(t, set.Has("qq.com")) assert.False(t, set.Has("www.baidu.com")) } From 00939da40f1b2467a426bc8cc608a1da06f55923 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 20 Apr 2023 13:41:55 +0800 Subject: [PATCH 219/530] chore: update wireguard-go --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- listener/sing_tun/server.go | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index fe3940e4..ecc269df 100644 --- a/go.mod +++ b/go.mod @@ -21,19 +21,19 @@ require ( github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230419154412-11ec6808f588 - github.com/metacubex/sing-tun v0.1.4-0.20230419154912-049c66801ff8 - github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 + github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990 + github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb github.com/miekg/dns v1.1.53 github.com/mroth/weightedrand/v2 v2.0.0 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.4-0.20230419153323-5fae6fa434c1 + github.com/sagernet/sing v0.2.4-0.20230420044236-72471d9b35b5 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b 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-20221116151939-c99467f53f2c + github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 github.com/samber/lo v1.38.1 github.com/shirou/gopsutil/v3 v3.23.3 github.com/sirupsen/logrus v1.9.0 diff --git a/go.sum b/go.sum index 9dcbe783..a6a61afd 100644 --- a/go.sum +++ b/go.sum @@ -98,10 +98,10 @@ github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 h1:KD96JPdTIa 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.20230419154412-11ec6808f588 h1:bOuVbeG5iwYyiDB2am3xIrt7GwbZC8cZIoJqLtvkcfY= github.com/metacubex/sing-shadowsocks v0.2.2-0.20230419154412-11ec6808f588/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= -github.com/metacubex/sing-tun v0.1.4-0.20230419154912-049c66801ff8 h1:BQFEnZUnPvmER8JIQPsfaaWzMXOvY5o+2ToDcRfAh58= -github.com/metacubex/sing-tun v0.1.4-0.20230419154912-049c66801ff8/go.mod h1:5CR2e0WQQiLSPd46Qaz3uhDRRik3QvvXiyMvlT3bXoc= -github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025 h1:itjCqEeem+BKZFiBEhQmWHDHKK4FgTGvnYCFS0JOb3A= -github.com/metacubex/sing-wireguard v0.0.0-20230413082948-e51777dcf025/go.mod h1:7mPG9qYln+CLKBcDt7Dk4c7b3S53VzEfexMVPe6T6FM= +github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990 h1:VpC69WWsOyhwwRkMVop6ao30dh4ZtlqaroT5uK6EBYU= +github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990/go.mod h1:5CR2e0WQQiLSPd46Qaz3uhDRRik3QvvXiyMvlT3bXoc= +github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb h1:uoeOqHaQmNPev9RewQlff9Z55yuczEhRizcgDf4lSAw= +github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= @@ -144,8 +144,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1 h1:CdzNL25lzfVo0NMeghPqsupNsWvkzrbrUt5t8DoDPcQ= -github.com/sagernet/sing v0.2.4-0.20230419153323-5fae6fa434c1/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.4-0.20230420044236-72471d9b35b5 h1:UtihSORXefZYQrGIssu65bP18VEgMGCNHdy60VHc14M= +github.com/sagernet/sing v0.2.4-0.20230420044236-72471d9b35b5/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= 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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= @@ -154,8 +154,8 @@ github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 h1:2ItpW1nMNkPzmBT github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= -github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c h1:vK2wyt9aWYHHvNLWniwijBu/n4pySypiKRhN32u/JGo= -github.com/sagernet/wireguard-go v0.0.0-20221116151939-c99467f53f2c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= +github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo= +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.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE= diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 5f691b44..084c701b 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -246,7 +246,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte if options.FileDescriptor > 0 { if tunName, err := getTunnelName(int32(options.FileDescriptor)); err != nil { stackOptions.Name = tunName - stackOptions.UnderPlatform = true + stackOptions.ForwarderBindInterface = true } } l.tunIf = tunIf From c6ecbb25dcc0c588eced38029ee34d6d3948012c Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 21 Apr 2023 08:49:03 +0000 Subject: [PATCH 220/530] chore: update doc --- docs/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/config.yaml b/docs/config.yaml index 922d4895..fe4ee682 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -594,6 +594,7 @@ proxies: # socks5 type: hysteria server: server.com port: 443 + # ports: 1000,2000-3000,5000 # port 不可省略, auth_str: yourpassword # 将会在未来某个时候删除 # auth-str: yourpassword # obfs: obfs_str From 40da1911d902d923f19d2999562b820aba47d4de Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 22 Apr 2023 15:37:57 +0800 Subject: [PATCH 221/530] chore: using sync/atomic replace uber/atomic --- adapter/adapter.go | 8 +- adapter/outboundgroup/groupbase.go | 2 +- adapter/provider/healthcheck.go | 3 +- common/atomic/type.go | 205 +++++++++++++++++++++++++++ common/atomic/value.go | 58 ++++++++ common/observable/observable_test.go | 5 +- common/singledo/singledo_test.go | 5 +- component/dialer/options.go | 5 +- component/profile/profile.go | 2 +- dns/client.go | 4 +- dns/dhcp.go | 5 +- dns/resolver.go | 5 +- go.mod | 3 - go.sum | 2 - transport/gun/gun.go | 2 +- tunnel/statistic/manager.go | 3 +- tunnel/statistic/tracker.go | 2 +- 17 files changed, 288 insertions(+), 31 deletions(-) create mode 100644 common/atomic/type.go create mode 100644 common/atomic/value.go diff --git a/adapter/adapter.go b/adapter/adapter.go index ffb5ced0..538ba271 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -4,16 +4,16 @@ import ( "context" "encoding/json" "fmt" - "github.com/Dreamacro/clash/common/queue" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" "net" "net/http" "net/netip" "net/url" "time" - "go.uber.org/atomic" + "github.com/Dreamacro/clash/common/atomic" + "github.com/Dreamacro/clash/common/queue" + "github.com/Dreamacro/clash/component/dialer" + C "github.com/Dreamacro/clash/constant" ) var UnifiedDelay = atomic.NewBool(false) diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 0a421793..8e253e63 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -8,6 +8,7 @@ import ( "time" "github.com/Dreamacro/clash/adapter/outbound" + "github.com/Dreamacro/clash/common/atomic" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" types "github.com/Dreamacro/clash/constant/provider" @@ -15,7 +16,6 @@ import ( "github.com/Dreamacro/clash/tunnel" "github.com/dlclark/regexp2" - "go.uber.org/atomic" ) type GroupBase struct { diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 9deb7b82..fa13e32e 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -4,13 +4,12 @@ import ( "context" "time" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/batch" "github.com/Dreamacro/clash/common/singledo" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - - "go.uber.org/atomic" ) const ( diff --git a/common/atomic/type.go b/common/atomic/type.go new file mode 100644 index 00000000..f1549235 --- /dev/null +++ b/common/atomic/type.go @@ -0,0 +1,205 @@ +package atomic + +import ( + "encoding/json" + "fmt" + "strconv" + "sync/atomic" +) + +type Bool struct { + atomic.Bool +} + +func NewBool(val bool) *Bool { + i := &Bool{} + i.Store(val) + return i +} + +func (i *Bool) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Bool) UnmarshalJSON(b []byte) error { + var v bool + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Bool) String() string { + v := i.Load() + return strconv.FormatBool(v) +} + +type Pointer[T any] struct { + atomic.Pointer[T] +} + +func NewPointer[T any](v *T) *Pointer[T] { + var p Pointer[T] + if v != nil { + p.Store(v) + } + return &p +} + +func (p *Pointer[T]) MarshalJSON() ([]byte, error) { + return json.Marshal(p.Load()) +} + +func (p *Pointer[T]) UnmarshalJSON(b []byte) error { + var v *T + if err := json.Unmarshal(b, &v); err != nil { + return err + } + p.Store(v) + return nil +} + +func (p *Pointer[T]) String() string { + return fmt.Sprint(p.Load()) +} + +type Int32 struct { + atomic.Int32 +} + +func NewInt32(val int32) *Int32 { + i := &Int32{} + i.Store(val) + return i +} + +func (i *Int32) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Int32) UnmarshalJSON(b []byte) error { + var v int32 + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Int32) String() string { + v := i.Load() + return strconv.FormatInt(int64(v), 10) +} + +type Int64 struct { + atomic.Int64 +} + +func NewInt64(val int64) *Int64 { + i := &Int64{} + i.Store(val) + return i +} + +func (i *Int64) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Int64) UnmarshalJSON(b []byte) error { + var v int64 + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Int64) String() string { + v := i.Load() + return strconv.FormatInt(int64(v), 10) +} + +type Uint32 struct { + atomic.Uint32 +} + +func NewUint32(val uint32) *Uint32 { + i := &Uint32{} + i.Store(val) + return i +} + +func (i *Uint32) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Uint32) UnmarshalJSON(b []byte) error { + var v uint32 + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Uint32) String() string { + v := i.Load() + return strconv.FormatUint(uint64(v), 10) +} + +type Uint64 struct { + atomic.Uint64 +} + +func NewUint64(val uint64) *Uint64 { + i := &Uint64{} + i.Store(val) + return i +} + +func (i *Uint64) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Uint64) UnmarshalJSON(b []byte) error { + var v uint64 + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Uint64) String() string { + v := i.Load() + return strconv.FormatUint(uint64(v), 10) +} + +type Uintptr struct { + atomic.Uintptr +} + +func NewUintptr(val uintptr) *Uintptr { + i := &Uintptr{} + i.Store(val) + return i +} + +func (i *Uintptr) MarshalJSON() ([]byte, error) { + return json.Marshal(i.Load()) +} + +func (i *Uintptr) UnmarshalJSON(b []byte) error { + var v uintptr + if err := json.Unmarshal(b, &v); err != nil { + return err + } + i.Store(v) + return nil +} + +func (i *Uintptr) String() string { + v := i.Load() + return strconv.FormatUint(uint64(v), 10) +} diff --git a/common/atomic/value.go b/common/atomic/value.go new file mode 100644 index 00000000..ca0eb631 --- /dev/null +++ b/common/atomic/value.go @@ -0,0 +1,58 @@ +package atomic + +import ( + "encoding/json" + "sync/atomic" +) + +func DefaultValue[T any]() T { + var defaultValue T + return defaultValue +} + +type TypedValue[T any] struct { + value atomic.Value +} + +func (t *TypedValue[T]) Load() T { + value := t.value.Load() + if value == nil { + return DefaultValue[T]() + } + return value.(T) +} + +func (t *TypedValue[T]) Store(value T) { + t.value.Store(value) +} + +func (t *TypedValue[T]) Swap(new T) T { + old := t.value.Swap(new) + if old == nil { + return DefaultValue[T]() + } + return old.(T) +} + +func (t *TypedValue[T]) CompareAndSwap(old, new T) bool { + return t.value.CompareAndSwap(old, new) +} + +func (t *TypedValue[T]) MarshalJSON() ([]byte, error) { + return json.Marshal(t.Load()) +} + +func (t *TypedValue[T]) UnmarshalJSON(b []byte) error { + var v T + if err := json.Unmarshal(b, &v); err != nil { + return err + } + t.Store(v) + return nil +} + +func NewTypedValue[T any](t T) *TypedValue[T] { + v := &TypedValue[T]{} + v.Store(t) + return v +} diff --git a/common/observable/observable_test.go b/common/observable/observable_test.go index 5459e0e2..5a02273d 100644 --- a/common/observable/observable_test.go +++ b/common/observable/observable_test.go @@ -5,8 +5,9 @@ import ( "testing" "time" + "github.com/Dreamacro/clash/common/atomic" + "github.com/stretchr/testify/assert" - "go.uber.org/atomic" ) func iterator[T any](item []T) chan T { @@ -44,7 +45,7 @@ func TestObservable_MultiSubscribe(t *testing.T) { wg.Add(2) waitCh := func(ch <-chan int) { for range ch { - count.Inc() + count.Add(1) } wg.Done() } diff --git a/common/singledo/singledo_test.go b/common/singledo/singledo_test.go index 26e3d37d..9e114fb7 100644 --- a/common/singledo/singledo_test.go +++ b/common/singledo/singledo_test.go @@ -5,8 +5,9 @@ import ( "testing" "time" + "github.com/Dreamacro/clash/common/atomic" + "github.com/stretchr/testify/assert" - "go.uber.org/atomic" ) func TestBasic(t *testing.T) { @@ -26,7 +27,7 @@ func TestBasic(t *testing.T) { go func() { _, _, shard := single.Do(call) if shard { - shardCount.Inc() + shardCount.Add(1) } wg.Done() }() diff --git a/component/dialer/options.go b/component/dialer/options.go index 372a2e63..096c7a5c 100644 --- a/component/dialer/options.go +++ b/component/dialer/options.go @@ -4,14 +4,13 @@ import ( "context" "net" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/resolver" - - "go.uber.org/atomic" ) var ( DefaultOptions []Option - DefaultInterface = atomic.NewString("") + DefaultInterface = atomic.NewTypedValue[string]("") DefaultRoutingMark = atomic.NewInt32(0) ) diff --git a/component/profile/profile.go b/component/profile/profile.go index e3d9e78c..aa6df2f7 100644 --- a/component/profile/profile.go +++ b/component/profile/profile.go @@ -1,7 +1,7 @@ package profile import ( - "go.uber.org/atomic" + "github.com/Dreamacro/clash/common/atomic" ) // StoreSelected is a global switch for storing selected proxy to cache diff --git a/dns/client.go b/dns/client.go index 637207f3..ba83412b 100644 --- a/dns/client.go +++ b/dns/client.go @@ -8,6 +8,7 @@ import ( "net/netip" "strings" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" tlsC "github.com/Dreamacro/clash/component/tls" @@ -15,7 +16,6 @@ import ( D "github.com/miekg/dns" "github.com/zhangyunhao116/fastrand" - "go.uber.org/atomic" ) type client struct { @@ -23,7 +23,7 @@ type client struct { r *Resolver port string host string - iface *atomic.String + iface *atomic.TypedValue[string] proxyAdapter C.ProxyAdapter proxyName string addr string diff --git a/dns/dhcp.go b/dns/dhcp.go index 151e4421..a6c1df76 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -8,8 +8,7 @@ import ( "sync" "time" - "go.uber.org/atomic" - + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/dhcp" "github.com/Dreamacro/clash/component/iface" "github.com/Dreamacro/clash/component/resolver" @@ -86,7 +85,7 @@ func (d *dhcpClient) resolve(ctx context.Context) ([]dnsClient, error) { for _, item := range dns { nameserver = append(nameserver, NameServer{ Addr: net.JoinHostPort(item.String(), "53"), - Interface: atomic.NewString(d.ifaceName), + Interface: atomic.NewTypedValue(d.ifaceName), }) } diff --git a/dns/resolver.go b/dns/resolver.go index df8ed3d1..7e1b007d 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -7,8 +7,7 @@ import ( "strings" "time" - "go.uber.org/atomic" - + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/geodata/router" @@ -388,7 +387,7 @@ func (r *Resolver) Invalid() bool { type NameServer struct { Net string Addr string - Interface *atomic.String + Interface *atomic.TypedValue[string] ProxyAdapter C.ProxyAdapter ProxyName string Params map[string]string diff --git a/go.mod b/go.mod index ecc269df..1e3b7a1e 100644 --- a/go.mod +++ b/go.mod @@ -41,7 +41,6 @@ require ( github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 github.com/zhangyunhao116/fastrand v0.3.0 go.etcd.io/bbolt v1.3.6 - go.uber.org/atomic v1.10.0 go.uber.org/automaxprocs v1.5.2 golang.org/x/crypto v0.8.0 golang.org/x/exp v0.0.0-20230321023759-10a507213a29 @@ -103,5 +102,3 @@ require ( golang.org/x/tools v0.6.0 // indirect gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect ) - -replace go.uber.org/atomic v1.10.0 => github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 diff --git a/go.sum b/go.sum index a6a61afd..ec90cb29 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,6 @@ github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990 h1:VpC69WWsOy github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990/go.mod h1:5CR2e0WQQiLSPd46Qaz3uhDRRik3QvvXiyMvlT3bXoc= github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb h1:uoeOqHaQmNPev9RewQlff9Z55yuczEhRizcgDf4lSAw= github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY= -github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370 h1:UkViS4DCESAUEYgbIEQdD02hyMacFt6Dny+1MOJtNIo= -github.com/metacubex/uber-atomic v0.0.0-20230202125923-feb10b770370/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= github.com/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo= diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 0e5d2321..36cf68f8 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -17,11 +17,11 @@ import ( "sync" "time" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/pool" tlsC "github.com/Dreamacro/clash/component/tls" - "go.uber.org/atomic" "golang.org/x/net/http2" ) diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 66e3857d..381ea7e6 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -5,8 +5,9 @@ import ( "sync" "time" + "github.com/Dreamacro/clash/common/atomic" + "github.com/shirou/gopsutil/v3/process" - "go.uber.org/atomic" ) var DefaultManager *Manager diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 96376eb4..b9682c22 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -4,12 +4,12 @@ import ( "net" "time" + "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/gofrs/uuid/v5" - "go.uber.org/atomic" ) type tracker interface { From aa6fa7f1e3299c7a0a447dbba531ef0d771b0785 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 22 Apr 2023 19:17:45 +0800 Subject: [PATCH 222/530] chore: cleanup unneeded deadline --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index 1e3b7a1e..a8272799 100644 --- a/go.mod +++ b/go.mod @@ -20,15 +20,15 @@ require ( github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 - github.com/metacubex/sing-shadowsocks v0.2.2-0.20230419154412-11ec6808f588 - github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990 + github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba + github.com/metacubex/sing-tun v0.1.4 github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb github.com/miekg/dns v1.1.53 github.com/mroth/weightedrand/v2 v2.0.0 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.4-0.20230420044236-72471d9b35b5 + github.com/sagernet/sing v0.2.4 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index ec90cb29..476c8c3a 100644 --- a/go.sum +++ b/go.sum @@ -96,10 +96,10 @@ github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+ 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.20230419154412-11ec6808f588 h1:bOuVbeG5iwYyiDB2am3xIrt7GwbZC8cZIoJqLtvkcfY= -github.com/metacubex/sing-shadowsocks v0.2.2-0.20230419154412-11ec6808f588/go.mod h1:4uQQReKMTU7KTfOykVBe/oGJ00pl38d+BYJ99+mx26s= -github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990 h1:VpC69WWsOyhwwRkMVop6ao30dh4ZtlqaroT5uK6EBYU= -github.com/metacubex/sing-tun v0.1.4-0.20230420054006-376d37578990/go.mod h1:5CR2e0WQQiLSPd46Qaz3uhDRRik3QvvXiyMvlT3bXoc= +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/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb h1:uoeOqHaQmNPev9RewQlff9Z55yuczEhRizcgDf4lSAw= github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY= github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw= @@ -142,8 +142,8 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.4-0.20230420044236-72471d9b35b5 h1:UtihSORXefZYQrGIssu65bP18VEgMGCNHdy60VHc14M= -github.com/sagernet/sing v0.2.4-0.20230420044236-72471d9b35b5/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.4 h1:gC8BR5sglbJZX23RtMyFa8EETP9YEUADhfbEzU1yVbo= +github.com/sagernet/sing v0.2.4/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= 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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= From 7ca4b64a2b21b01eea04d2162b698080bb9c87b9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 23 Apr 2023 19:57:54 +0800 Subject: [PATCH 223/530] feat: add proxy and sing-based listener support sing-mux --- adapter/outbound/singmux.go | 97 +++++++++++++++++++++++++++++++++++++ adapter/parser.go | 14 ++++++ go.mod | 5 +- go.sum | 12 ++++- listener/sing/sing.go | 10 ++++ 5 files changed, 135 insertions(+), 3 deletions(-) create mode 100644 adapter/outbound/singmux.go diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go new file mode 100644 index 00000000..315b53c6 --- /dev/null +++ b/adapter/outbound/singmux.go @@ -0,0 +1,97 @@ +package outbound + +import ( + "context" + "net" + + "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/proxydialer" + C "github.com/Dreamacro/clash/constant" + + mux "github.com/sagernet/sing-mux" + E "github.com/sagernet/sing/common/exceptions" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type SingMux struct { + C.ProxyAdapter + base ProxyBase + client *mux.Client + dialer *muxSingDialer +} + +type SingMuxOption struct { + Enabled bool `proxy:"enabled,omitempty"` + Protocol string `proxy:"protocol,omitempty"` + MaxConnections int `proxy:"max-connections,omitempty"` + MinStreams int `proxy:"min-streams,omitempty"` + MaxStreams int `proxy:"max-streams,omitempty"` + Padding bool `proxy:"padding,omitempty"` +} + +type ProxyBase interface { + DialOptions(opts ...dialer.Option) []dialer.Option +} + +type muxSingDialer struct { + dialer dialer.Dialer + proxy C.ProxyAdapter +} + +var _ N.Dialer = (*muxSingDialer)(nil) + +func (d *muxSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + var cDialer C.Dialer = proxydialer.New(d.proxy, d.dialer, false) + return cDialer.DialContext(ctx, network, destination.String()) +} + +func (d *muxSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + var cDialer C.Dialer = proxydialer.New(d.proxy, d.dialer, false) + return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) +} + +func (s *SingMux) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { + options := s.base.DialOptions(opts...) + s.dialer.dialer = dialer.NewDialer(options...) + c, err := s.client.DialContext(ctx, "tcp", M.ParseSocksaddr(metadata.RemoteAddress())) + if err != nil { + return nil, err + } + return NewConn(c, s.ProxyAdapter), err +} + +func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { + options := s.base.DialOptions(opts...) + s.dialer.dialer = dialer.NewDialer(options...) + pc, err := s.client.ListenPacket(ctx, M.ParseSocksaddr(metadata.RemoteAddress())) + if err != nil { + return nil, err + } + if pc == nil { + return nil, E.New("packetConn is nil") + } + return newPacketConn(pc, s.ProxyAdapter), nil +} + +func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.ProxyAdapter, error) { + singDialer := &muxSingDialer{dialer: dialer.NewDialer(), proxy: proxy} + client, err := mux.NewClient(mux.Options{ + Context: context.TODO(), + Dialer: singDialer, + Protocol: option.Protocol, + MaxConnections: option.MaxConnections, + MinStreams: option.MinStreams, + MaxStreams: option.MaxStreams, + Padding: option.Padding, + }) + if err != nil { + return nil, err + } + return &SingMux{ + ProxyAdapter: proxy, + base: base, + client: client, + dialer: singDialer, + }, nil +} diff --git a/adapter/parser.go b/adapter/parser.go index 1f626f33..a561a1ed 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -114,5 +114,19 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { return nil, err } + if muxMapping, muxExist := mapping["smux"].(map[string]any); muxExist { + muxOption := &outbound.SingMuxOption{} + err = decoder.Decode(muxMapping, muxOption) + if err != nil { + return nil, err + } + if muxOption.Enabled { + proxy, err = outbound.NewSingMux(*muxOption, proxy, proxy.(outbound.ProxyBase)) + if err != nil { + return nil, err + } + } + } + return NewProxy(proxy), nil } diff --git a/go.mod b/go.mod index a8272799..4b2e0a43 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,8 @@ require ( 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.4 + github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207 + github.com/sagernet/sing-mux v0.0.0-20230423111236-a3ebc1453fd6 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 @@ -69,6 +70,7 @@ require ( 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 github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect @@ -86,6 +88,7 @@ require ( github.com/quic-go/qtls-go1-19 v0.2.1 // indirect github.com/quic-go/qtls-go1-20 v0.1.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/shoenig/go-m1cpu v0.1.5 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect diff --git a/go.sum b/go.sum index 476c8c3a..26aa3830 100644 --- a/go.sum +++ b/go.sum @@ -67,6 +67,8 @@ github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWm 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-20230407062729-974c6f05fe16 h1:+aAGyK41KRn8jbF2Q7PLL0Sxwg6dShGcQSeCC7nZQ8E= github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16/go.mod h1:IKrnDWs3/Mqq5n0lI+RxA2sB7MvN/vbMBP3ehXg65UI= @@ -142,12 +144,17 @@ github.com/sagernet/go-tun2socks v1.16.12-0.20220818015926-16cb67876a61/go.mod h github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 h1:iL5gZI3uFp0X6EslacyapiRz7LLSJyr4RajF/BhMVyE= github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.2.4 h1:gC8BR5sglbJZX23RtMyFa8EETP9YEUADhfbEzU1yVbo= -github.com/sagernet/sing v0.2.4/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207 h1:+dDVjW20IT+e8maKryaDeRY2+RFmTFdrQeIzqE2WOss= +github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing-mux v0.0.0-20230423111236-a3ebc1453fd6 h1:Ehndd61kh3NL2nL8xtDQMZ89YIbC1wCyFMK2PxEBnls= +github.com/sagernet/sing-mux v0.0.0-20230423111236-a3ebc1453fd6/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-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= +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= github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= @@ -239,6 +246,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.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= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 2941f6ca..2ccdfe2d 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -15,6 +15,7 @@ import ( "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" + mux "github.com/sagernet/sing-mux" vmess "github.com/sagernet/sing-vmess" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio/deadline" @@ -56,6 +57,13 @@ func (c *waitCloseConn) Upstream() any { return c.ExtendedConn } +func UpstreamMetadata(metadata M.Metadata) M.Metadata { + return M.Metadata{ + Source: metadata.Source, + Destination: metadata.Destination, + } +} + func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { additions := h.Additions if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { @@ -63,6 +71,8 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta additions = append(additions, ctxAdditions...) } switch metadata.Destination.Fqdn { + case mux.Destination.Fqdn: + return mux.HandleConnection(ctx, h, log.SingLogger, conn, UpstreamMetadata(metadata)) case vmess.MuxDestination.Fqdn: return vmess.HandleMuxConnection(ctx, conn, h) case uot.MagicAddress: From 0c146bd04cfa22ede8af9826dc5ba9677e46cf8f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 23 Apr 2023 20:10:58 +0800 Subject: [PATCH 224/530] doc: update smux --- docs/config.yaml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/config.yaml b/docs/config.yaml index fe4ee682..660976e7 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -302,6 +302,13 @@ proxies: # socks5 # UDP 则为双栈解析,获取结果中的第一个 IPv4 # ipv6-prefer 同 ipv4-prefer # 现有协议都支持此参数,TCP 效果仅在开启 tcp-concurrent 生效 + smux: + enabled: false + protocol: smux # smux/yamux/h2mux + # max-connections: 4 # Maximum connections. Conflict with max-streams. + # min-streams: 4 # Minimum multiplexed streams in a connection before opening a new connection. Conflict with max-streams. + # max-streams: 0 # Maximum multiplexed streams in a connection before opening a new connection. Conflict with max-connections and min-streams. + # padding: false # Enable padding. Requires sing-box server version 1.3-beta9 or later. - name: "ss2" type: ss From 0c61057551b567d463b60623ed0ab2d06a18260c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 23 Apr 2023 20:55:42 +0800 Subject: [PATCH 225/530] feat: add `statistic` and `only-tcp` options for smux --- adapter/outbound/singmux.go | 24 ++++++++++++++++-------- docs/config.yaml | 2 ++ 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index 315b53c6..4f3a531c 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -16,9 +16,10 @@ import ( type SingMux struct { C.ProxyAdapter - base ProxyBase - client *mux.Client - dialer *muxSingDialer + base ProxyBase + client *mux.Client + dialer *muxSingDialer + onlyTcp bool } type SingMuxOption struct { @@ -28,6 +29,8 @@ type SingMuxOption struct { MinStreams int `proxy:"min-streams,omitempty"` MaxStreams int `proxy:"max-streams,omitempty"` Padding bool `proxy:"padding,omitempty"` + Statistic bool `proxy:"statistic,omitempty"` + OnlyTcp bool `proxy:"only-tcp,omitempty"` } type ProxyBase interface { @@ -35,19 +38,20 @@ type ProxyBase interface { } type muxSingDialer struct { - dialer dialer.Dialer - proxy C.ProxyAdapter + dialer dialer.Dialer + proxy C.ProxyAdapter + statistic bool } var _ N.Dialer = (*muxSingDialer)(nil) func (d *muxSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - var cDialer C.Dialer = proxydialer.New(d.proxy, d.dialer, false) + var cDialer C.Dialer = proxydialer.New(d.proxy, d.dialer, d.statistic) return cDialer.DialContext(ctx, network, destination.String()) } func (d *muxSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - var cDialer C.Dialer = proxydialer.New(d.proxy, d.dialer, false) + var cDialer C.Dialer = proxydialer.New(d.proxy, d.dialer, d.statistic) return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) } @@ -62,6 +66,9 @@ func (s *SingMux) DialContext(ctx context.Context, metadata *C.Metadata, opts .. } func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { + if s.onlyTcp { + return s.ProxyAdapter.ListenPacketContext(ctx, metadata, opts...) + } options := s.base.DialOptions(opts...) s.dialer.dialer = dialer.NewDialer(options...) pc, err := s.client.ListenPacket(ctx, M.ParseSocksaddr(metadata.RemoteAddress())) @@ -75,7 +82,7 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, } func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.ProxyAdapter, error) { - singDialer := &muxSingDialer{dialer: dialer.NewDialer(), proxy: proxy} + singDialer := &muxSingDialer{dialer: dialer.NewDialer(), proxy: proxy, statistic: option.Statistic} client, err := mux.NewClient(mux.Options{ Context: context.TODO(), Dialer: singDialer, @@ -93,5 +100,6 @@ func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.P base: base, client: client, dialer: singDialer, + onlyTcp: option.OnlyTcp, }, nil } diff --git a/docs/config.yaml b/docs/config.yaml index 660976e7..e0fe5577 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -309,6 +309,8 @@ proxies: # socks5 # min-streams: 4 # Minimum multiplexed streams in a connection before opening a new connection. Conflict with max-streams. # max-streams: 0 # Maximum multiplexed streams in a connection before opening a new connection. Conflict with max-connections and min-streams. # 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 From 7f1b7e7521d3cdab5cc971466c36144d1c6e9b4c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 23 Apr 2023 21:50:42 +0800 Subject: [PATCH 226/530] fix: smux should show its support udp and uot --- adapter/outbound/singmux.go | 14 ++++++++++++++ adapter/outboundgroup/relay.go | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index 4f3a531c..b1a64d99 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -81,6 +81,20 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, return newPacketConn(pc, s.ProxyAdapter), nil } +func (s *SingMux) SupportUDP() bool { + if s.onlyTcp { + return s.ProxyAdapter.SupportUOT() + } + return true +} + +func (s *SingMux) SupportUOT() bool { + if s.onlyTcp { + return s.ProxyAdapter.SupportUOT() + } + return true +} + func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.ProxyAdapter, error) { singDialer := &muxSingDialer{dialer: dialer.NewDialer(), proxy: proxy, statistic: option.Statistic} client, err := mux.NewClient(mux.Options{ diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go index a596454f..ba733616 100644 --- a/adapter/outboundgroup/relay.go +++ b/adapter/outboundgroup/relay.go @@ -92,7 +92,7 @@ func (r *Relay) SupportUDP() bool { switch proxy.SupportWithDialer() { case C.ALLNet: case C.UDP: - default: // C.TCP and C.NONet + default: // C.TCP and C.InvalidNet return false } } From 72a67ac5349b5f15842948943a1ec11703ac1f62 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 24 Apr 2023 08:07:17 +0800 Subject: [PATCH 227/530] chore: force set SelectAble when start load cache --- adapter/outboundgroup/fallback.go | 4 ++++ adapter/outboundgroup/selector.go | 4 ++++ adapter/outboundgroup/urltest.go | 4 ++++ adapter/outboundgroup/util.go | 1 + hub/executor/executor.go | 2 +- 5 files changed, 14 insertions(+), 1 deletion(-) diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index c79d9871..1f4e1580 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -138,6 +138,10 @@ func (f *Fallback) Set(name string) error { return nil } +func (f *Fallback) ForceSet(name string) { + f.selected = name +} + func NewFallback(option *GroupCommonOption, providers []provider.ProxyProvider) *Fallback { return &Fallback{ GroupBase: NewGroupBase(GroupBaseOption{ diff --git a/adapter/outboundgroup/selector.go b/adapter/outboundgroup/selector.go index b5b1cfa3..96934f0c 100644 --- a/adapter/outboundgroup/selector.go +++ b/adapter/outboundgroup/selector.go @@ -78,6 +78,10 @@ func (s *Selector) Set(name string) error { return errors.New("proxy not exist") } +func (s *Selector) ForceSet(name string) { + s.selected = name +} + // Unwrap implements C.ProxyAdapter func (s *Selector) Unwrap(metadata *C.Metadata, touch bool) C.Proxy { return s.selectedProxy(touch) diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 6f10f78b..5b0d2a17 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -53,6 +53,10 @@ func (u *URLTest) Set(name string) error { return nil } +func (u *URLTest) ForceSet(name string) { + u.selected = name +} + // DialContext implements C.ProxyAdapter func (u *URLTest) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (c C.Conn, err error) { proxy := u.fast(true) diff --git a/adapter/outboundgroup/util.go b/adapter/outboundgroup/util.go index adcda1aa..85373a1f 100644 --- a/adapter/outboundgroup/util.go +++ b/adapter/outboundgroup/util.go @@ -14,4 +14,5 @@ func tcpKeepAlive(c net.Conn) { type SelectAble interface { Set(string) error + ForceSet(name string) } diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 3598d873..724150e7 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -413,7 +413,7 @@ func patchSelectGroup(proxies map[string]C.Proxy) { continue } - selector.Set(selected) + selector.ForceSet(selected) } } From efcb278f618c3e771fecb4b2ef14023fb5e8853f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 24 Apr 2023 10:30:12 +0800 Subject: [PATCH 228/530] chore: safe sing-mux close --- adapter/outbound/singmux.go | 17 ++++++++++++----- docs/config.yaml | 2 +- go.mod | 2 +- go.sum | 4 ++-- 4 files changed, 16 insertions(+), 9 deletions(-) diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index b1a64d99..cf18a6f3 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -3,7 +3,9 @@ package outbound import ( "context" "net" + "runtime" + CN "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" C "github.com/Dreamacro/clash/constant" @@ -62,7 +64,7 @@ func (s *SingMux) DialContext(ctx context.Context, metadata *C.Metadata, opts .. if err != nil { return nil, err } - return NewConn(c, s.ProxyAdapter), err + return NewConn(CN.NewRefConn(c, s), s.ProxyAdapter), err } func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { @@ -78,7 +80,7 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, if pc == nil { return nil, E.New("packetConn is nil") } - return newPacketConn(pc, s.ProxyAdapter), nil + return newPacketConn(CN.NewRefPacketConn(pc, s), s.ProxyAdapter), nil } func (s *SingMux) SupportUDP() bool { @@ -95,10 +97,13 @@ func (s *SingMux) SupportUOT() bool { return true } +func closeSingMux(s *SingMux) { + _ = s.client.Close() +} + func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.ProxyAdapter, error) { singDialer := &muxSingDialer{dialer: dialer.NewDialer(), proxy: proxy, statistic: option.Statistic} client, err := mux.NewClient(mux.Options{ - Context: context.TODO(), Dialer: singDialer, Protocol: option.Protocol, MaxConnections: option.MaxConnections, @@ -109,11 +114,13 @@ func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.P if err != nil { return nil, err } - return &SingMux{ + outbound := &SingMux{ ProxyAdapter: proxy, base: base, client: client, dialer: singDialer, onlyTcp: option.OnlyTcp, - }, nil + } + runtime.SetFinalizer(outbound, closeSingMux) + return outbound, nil } diff --git a/docs/config.yaml b/docs/config.yaml index e0fe5577..97bd40ec 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -309,7 +309,7 @@ proxies: # socks5 # min-streams: 4 # Minimum multiplexed streams in a connection before opening a new connection. Conflict with max-streams. # max-streams: 0 # Maximum multiplexed streams in a connection before opening a new connection. Conflict with max-connections and min-streams. # padding: false # Enable padding. Requires sing-box server version 1.3-beta9 or later. - # statistic: false # 控制是否将底层连接显示在面板中,方面打断底层连接 + # statistic: false # 控制是否将底层连接显示在面板中,方便打断底层连接 # only-tcp: false # 如果设置为true, smux的设置将不会对udp生效,udp连接会直接走底层协议 - name: "ss2" diff --git a/go.mod b/go.mod index 4b2e0a43..4de1206f 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( 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.20230423085534-0902e6216207 - github.com/sagernet/sing-mux v0.0.0-20230423111236-a3ebc1453fd6 + github.com/sagernet/sing-mux v0.0.0-20230424015424-9b0d527c3bb0 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index 26aa3830..e8573a63 100644 --- a/go.sum +++ b/go.sum @@ -147,8 +147,8 @@ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2 github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207 h1:+dDVjW20IT+e8maKryaDeRY2+RFmTFdrQeIzqE2WOss= github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-mux v0.0.0-20230423111236-a3ebc1453fd6 h1:Ehndd61kh3NL2nL8xtDQMZ89YIbC1wCyFMK2PxEBnls= -github.com/sagernet/sing-mux v0.0.0-20230423111236-a3ebc1453fd6/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= +github.com/sagernet/sing-mux v0.0.0-20230424015424-9b0d527c3bb0 h1:87jyxzTjq01VgEiUVSMNRKjCfsSfp/QwyUVT37eXY50= +github.com/sagernet/sing-mux v0.0.0-20230424015424-9b0d527c3bb0/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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= From 7bb5da30056d45ca7a465e23398053447f5610e0 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 25 Apr 2023 23:01:05 +0800 Subject: [PATCH 229/530] chore: support splice for direct outbound --- adapter/outbound/base.go | 8 ++++++++ common/buf/sing.go | 12 ++++++------ common/callback/callback.go | 8 ++++++++ common/net/bufconn.go | 10 ++++++++++ common/net/refconn.go | 8 ++++++++ common/net/sing.go | 5 +++++ component/dialer/tfo.go | 8 ++++++++ go.mod | 2 +- go.sum | 4 ++-- tunnel/statistic/tracker.go | 20 ++++++++++++++++++++ 10 files changed, 76 insertions(+), 9 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 04eec966..367638b8 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -204,6 +204,14 @@ func (c *conn) Upstream() any { return c.ExtendedConn } +func (c *conn) WriterReplaceable() bool { + return true +} + +func (c *conn) ReaderReplaceable() bool { + return true +} + func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { if _, ok := c.(syscall.Conn); !ok { // exclusion system conn like *net.TCPConn c = N.NewDeadlineConn(c) // most conn from outbound can't handle readDeadline correctly diff --git a/common/buf/sing.go b/common/buf/sing.go index c176ecb1..93140887 100644 --- a/common/buf/sing.go +++ b/common/buf/sing.go @@ -9,12 +9,12 @@ const BufferSize = buf.BufferSize type Buffer = buf.Buffer -var ( - New = buf.New - StackNew = buf.StackNew - StackNewSize = buf.StackNewSize - With = buf.With -) +var New = buf.New +var NewSize = buf.NewSize +var StackNew = buf.StackNew +var StackNewSize = buf.StackNewSize +var With = buf.With +var As = buf.As var KeepAlive = common.KeepAlive diff --git a/common/callback/callback.go b/common/callback/callback.go index 0bf720f4..fe76dc67 100644 --- a/common/callback/callback.go +++ b/common/callback/callback.go @@ -36,6 +36,14 @@ func (c *firstWriteCallBackConn) Upstream() any { return c.Conn } +func (c *firstWriteCallBackConn) WriterReplaceable() bool { + return c.written +} + +func (c *firstWriteCallBackConn) ReaderReplaceable() bool { + return true +} + var _ N.ExtendedConn = (*firstWriteCallBackConn)(nil) func NewFirstWriteCallBackConn(c C.Conn, callback func(error)) C.Conn { diff --git a/common/net/bufconn.go b/common/net/bufconn.go index f01a3dda..2ff73c82 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -69,6 +69,16 @@ func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) { return c.ExtendedConn.ReadBuffer(buffer) } +func (c *BufferedConn) ReadCached() *buf.Buffer { // call in sing/common/bufio.Copy + if c.r.Buffered() > 0 { + length := c.r.Buffered() + b, _ := c.r.Peek(length) + _, _ = c.r.Discard(length) + return buf.As(b) + } + return nil +} + func (c *BufferedConn) Upstream() any { return c.ExtendedConn } diff --git a/common/net/refconn.go b/common/net/refconn.go index 59225db0..537cb839 100644 --- a/common/net/refconn.go +++ b/common/net/refconn.go @@ -67,6 +67,14 @@ func (c *refConn) WriteBuffer(buffer *buf.Buffer) error { return c.conn.WriteBuffer(buffer) } +func (c *refConn) ReaderReplaceable() bool { // Relay() will handle reference + return true +} + +func (c *refConn) WriterReplaceable() bool { // Relay() will handle reference + return true +} + var _ ExtendedConn = (*refConn)(nil) func NewRefConn(conn net.Conn, ref any) net.Conn { diff --git a/common/net/sing.go b/common/net/sing.go index 89517326..7eb92f03 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -3,6 +3,7 @@ package net import ( "context" "net" + "runtime" "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/bufio" @@ -33,7 +34,11 @@ func NeedHandshake(conn any) bool { return false } +type CountFunc = network.CountFunc + // Relay copies between left and right bidirectionally. func Relay(leftConn, rightConn net.Conn) { + defer runtime.KeepAlive(leftConn) + defer runtime.KeepAlive(rightConn) _ = bufio.CopyConn(context.TODO(), leftConn, rightConn) } diff --git a/component/dialer/tfo.go b/component/dialer/tfo.go index d5337bdb..09d5cced 100644 --- a/component/dialer/tfo.go +++ b/component/dialer/tfo.go @@ -113,6 +113,14 @@ func (c *tfoConn) NeedHandshake() bool { return c.Conn == nil } +func (c *tfoConn) ReaderReplaceable() bool { + return c.Conn != nil +} + +func (c *tfoConn) WriterReplaceable() bool { + return c.Conn != nil +} + func dialTFO(ctx context.Context, netDialer net.Dialer, network, address string) (net.Conn, error) { ctx, cancel := context.WithCancel(ctx) dialer := tfo.Dialer{Dialer: netDialer, DisableTFO: false} diff --git a/go.mod b/go.mod index 4de1206f..3153ab1d 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( 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.20230423085534-0902e6216207 + github.com/sagernet/sing v0.2.5-0.20230425145913-0c037cb0e2c8 github.com/sagernet/sing-mux v0.0.0-20230424015424-9b0d527c3bb0 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 diff --git a/go.sum b/go.sum index e8573a63..a747291f 100644 --- a/go.sum +++ b/go.sum @@ -145,8 +145,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 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.20230423085534-0902e6216207 h1:+dDVjW20IT+e8maKryaDeRY2+RFmTFdrQeIzqE2WOss= -github.com/sagernet/sing v0.2.5-0.20230423085534-0902e6216207/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.5-0.20230425145913-0c037cb0e2c8 h1:bf0WjE6g+bRhNCSe5u0xTeZLK/NboSy1/tI4eqPjvU0= +github.com/sagernet/sing v0.2.5-0.20230425145913-0c037cb0e2c8/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= github.com/sagernet/sing-mux v0.0.0-20230424015424-9b0d527c3bb0 h1:87jyxzTjq01VgEiUVSMNRKjCfsSfp/QwyUVT37eXY50= github.com/sagernet/sing-mux v0.0.0-20230424015424-9b0d527c3bb0/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4= diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index b9682c22..c4feeddb 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -1,11 +1,13 @@ package statistic import ( + "io" "net" "time" "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/buf" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" @@ -61,6 +63,15 @@ func (tt *tcpTracker) ReadBuffer(buffer *buf.Buffer) (err error) { return } +func (tt *tcpTracker) UnwrapReader() (io.Reader, []N.CountFunc) { + return tt.Conn, []N.CountFunc{func(download int64) { + if tt.pushToManager { + tt.manager.PushDownloaded(download) + } + tt.DownloadTotal.Add(download) + }} +} + func (tt *tcpTracker) Write(b []byte) (int, error) { n, err := tt.Conn.Write(b) upload := int64(n) @@ -81,6 +92,15 @@ func (tt *tcpTracker) WriteBuffer(buffer *buf.Buffer) (err error) { return } +func (tt *tcpTracker) UnwrapWriter() (io.Writer, []N.CountFunc) { + return tt.Conn, []N.CountFunc{func(upload int64) { + if tt.pushToManager { + tt.manager.PushUploaded(upload) + } + tt.UploadTotal.Add(upload) + }} +} + func (tt *tcpTracker) Close() error { tt.manager.Leave(tt) return tt.Conn.Close() From 787e5ea28d0cc7b130a5c8a92c0dfa955e7ee913 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 26 Apr 2023 01:13:52 +0000 Subject: [PATCH 230/530] chore: version print error --- constant/features/low_memory.go | 1 + 1 file changed, 1 insertion(+) diff --git a/constant/features/low_memory.go b/constant/features/low_memory.go index 32d10fa6..0d252113 100644 --- a/constant/features/low_memory.go +++ b/constant/features/low_memory.go @@ -1,3 +1,4 @@ +//go:build with_low_memory package features func init() { From e1af1abcc23d76e184b3cdd37f7fc928d1b822d7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 26 Apr 2023 09:33:58 +0800 Subject: [PATCH 231/530] fix: wireguard auto close not working --- adapter/outbound/wireguard.go | 169 ++++++++++++++++++++++++++++++++-- 1 file changed, 159 insertions(+), 10 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index f96f2d6f..67cd9092 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -40,6 +40,7 @@ type WireGuard struct { startOnce sync.Once startErr error resolver *dns.Resolver + refP *refProxyAdapter } type WireGuardOption struct { @@ -100,6 +101,20 @@ func (d *wgSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) } +type wgSingErrorHandler struct { + name string +} + +var _ E.Handler = (*wgSingErrorHandler)(nil) + +func (w wgSingErrorHandler) NewError(ctx context.Context, err error) { + if E.IsClosedOrCanceled(err) { + log.SingLogger.Debug(fmt.Sprintf("[WG](%s) connection closed: %s", w.name, err)) + return + } + log.SingLogger.Error(fmt.Sprintf("[WG](%s) %s", w.name, err)) +} + type wgNetDialer struct { tunDevice wireguard.Device } @@ -174,7 +189,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { connectAddr = option.Addr() } } - outbound.bind = wireguard.NewClientBind(context.Background(), outbound, outbound.dialer, isConnect, connectAddr, reserved) + outbound.bind = wireguard.NewClientBind(context.Background(), wgSingErrorHandler{outbound.Name()}, outbound.dialer, isConnect, connectAddr, reserved) var localPrefixes []netip.Prefix @@ -312,13 +327,15 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { } } + refP := &refProxyAdapter{} + outbound.refP = refP if option.RemoteDnsResolve && len(option.Dns) > 0 { nss, err := dns.ParseNameServer(option.Dns) if err != nil { return nil, err } for i := range nss { - nss[i].ProxyAdapter = outbound + nss[i].ProxyAdapter = refP } outbound.resolver = dns.NewResolver(dns.Config{ Main: nss, @@ -329,14 +346,6 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { return outbound, nil } -func (w *WireGuard) NewError(ctx context.Context, err error) { - if E.IsClosedOrCanceled(err) { - log.SingLogger.Debug(fmt.Sprintf("[WG](%s) connection closed: %s", w.Name(), err)) - return - } - log.SingLogger.Error(fmt.Sprintf("[WG](%s) %s", w.Name(), err)) -} - func closeWireGuard(w *WireGuard) { if w.device != nil { w.device.Close() @@ -357,6 +366,8 @@ func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts if !metadata.Resolved() || w.resolver != nil { r := resolver.DefaultResolver if w.resolver != nil { + w.refP.SetProxyAdapter(w) + defer w.refP.ClearProxyAdapter() r = w.resolver } options = append(options, dialer.WithResolver(r)) @@ -391,6 +402,8 @@ func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadat if (!metadata.Resolved() || w.resolver != nil) && metadata.Host != "" { r := resolver.DefaultResolver if w.resolver != nil { + w.refP.SetProxyAdapter(w) + defer w.refP.ClearProxyAdapter() r = w.resolver } ip, err := resolver.ResolveIPWithResolver(ctx, metadata.Host, r) @@ -414,3 +427,139 @@ func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadat func (w *WireGuard) IsL3Protocol(metadata *C.Metadata) bool { return true } + +type refProxyAdapter struct { + proxyAdapter C.ProxyAdapter + count int + mutex sync.Mutex +} + +func (r *refProxyAdapter) SetProxyAdapter(proxyAdapter C.ProxyAdapter) { + r.mutex.Lock() + defer r.mutex.Unlock() + r.proxyAdapter = proxyAdapter + r.count++ +} + +func (r *refProxyAdapter) ClearProxyAdapter() { + r.mutex.Lock() + defer r.mutex.Unlock() + r.count-- + if r.count == 0 { + r.proxyAdapter = nil + } +} + +func (r *refProxyAdapter) Name() string { + if r.proxyAdapter != nil { + return r.proxyAdapter.Name() + } + return "" +} + +func (r *refProxyAdapter) Type() C.AdapterType { + if r.proxyAdapter != nil { + return r.proxyAdapter.Type() + } + return C.AdapterType(0) +} + +func (r *refProxyAdapter) Addr() string { + if r.proxyAdapter != nil { + return r.proxyAdapter.Addr() + } + return "" +} + +func (r *refProxyAdapter) SupportUDP() bool { + if r.proxyAdapter != nil { + return r.proxyAdapter.SupportUDP() + } + return false +} + +func (r *refProxyAdapter) SupportXUDP() bool { + if r.proxyAdapter != nil { + return r.proxyAdapter.SupportXUDP() + } + return false +} + +func (r *refProxyAdapter) SupportTFO() bool { + if r.proxyAdapter != nil { + return r.proxyAdapter.SupportTFO() + } + return false +} + +func (r *refProxyAdapter) MarshalJSON() ([]byte, error) { + if r.proxyAdapter != nil { + return r.proxyAdapter.MarshalJSON() + } + return nil, C.ErrNotSupport +} + +func (r *refProxyAdapter) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { + if r.proxyAdapter != nil { + return r.proxyAdapter.StreamConn(c, metadata) + } + return nil, C.ErrNotSupport +} + +func (r *refProxyAdapter) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { + if r.proxyAdapter != nil { + return r.proxyAdapter.DialContext(ctx, metadata, opts...) + } + return nil, C.ErrNotSupport +} + +func (r *refProxyAdapter) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.PacketConn, error) { + if r.proxyAdapter != nil { + return r.proxyAdapter.ListenPacketContext(ctx, metadata, opts...) + } + return nil, C.ErrNotSupport +} + +func (r *refProxyAdapter) SupportUOT() bool { + if r.proxyAdapter != nil { + return r.proxyAdapter.SupportUOT() + } + return false +} + +func (r *refProxyAdapter) SupportWithDialer() C.NetWork { + if r.proxyAdapter != nil { + return r.proxyAdapter.SupportWithDialer() + } + return C.InvalidNet +} + +func (r *refProxyAdapter) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (C.Conn, error) { + if r.proxyAdapter != nil { + return r.proxyAdapter.DialContextWithDialer(ctx, dialer, metadata) + } + return nil, C.ErrNotSupport +} + +func (r *refProxyAdapter) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (C.PacketConn, error) { + if r.proxyAdapter != nil { + return r.proxyAdapter.ListenPacketWithDialer(ctx, dialer, metadata) + } + return nil, C.ErrNotSupport +} + +func (r *refProxyAdapter) IsL3Protocol(metadata *C.Metadata) bool { + if r.proxyAdapter != nil { + return r.proxyAdapter.IsL3Protocol(metadata) + } + return false +} + +func (r *refProxyAdapter) Unwrap(metadata *C.Metadata, touch bool) C.Proxy { + if r.proxyAdapter != nil { + return r.proxyAdapter.Unwrap(metadata, touch) + } + return nil +} + +var _ C.ProxyAdapter = (*refProxyAdapter)(nil) From d8db25ee89770f4055f3676086aee34352aea957 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Wed, 26 Apr 2023 02:49:16 +0000 Subject: [PATCH 232/530] fix: domain-set wildcard match --- component/trie/domain_set.go | 2 +- component/trie/domain_set_test.go | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/component/trie/domain_set.go b/component/trie/domain_set.go index ce416e16..be793ad3 100644 --- a/component/trie/domain_set.go +++ b/component/trie/domain_set.go @@ -105,7 +105,7 @@ func (ss *DomainSet) Has(key string) bool { } } for ; ; nextBmIdx++ { - if ss.labels[nextBmIdx-nextNodeId] == domainStepByte { + if nextBmIdx-nextNodeId < len(ss.labels) && ss.labels[nextBmIdx-nextNodeId] == domainStepByte { bmIdx = nextBmIdx nodeId = nextNodeId i = j diff --git a/component/trie/domain_set_test.go b/component/trie/domain_set_test.go index c4160f6c..9e0e0b70 100644 --- a/component/trie/domain_set_test.go +++ b/component/trie/domain_set_test.go @@ -65,6 +65,7 @@ func TestDomainSetWildcard(t *testing.T) { "stun.*.*", "*.*.qq.com", "test.*.baidu.com", + "*.apple.com", } for _, domain := range domainSet { @@ -78,6 +79,7 @@ func TestDomainSetWildcard(t *testing.T) { assert.True(t, set.Has("stun.ab.cd")) assert.False(t, set.Has("test.baidu.com")) assert.False(t, set.Has("www.google.com")) + assert.False(t, set.Has("a.www.google.com")) assert.False(t, set.Has("test.qq.com")) assert.False(t, set.Has("test.test.test.qq.com")) } From 8db030d36ed7443d20d65c66d6c25595aa00b71f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 26 Apr 2023 11:05:45 +0800 Subject: [PATCH 233/530] fix: wireguard tcp close need long time --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3153ab1d..21064360 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba github.com/metacubex/sing-tun v0.1.4 - github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb + github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a github.com/miekg/dns v1.1.53 github.com/mroth/weightedrand/v2 v2.0.0 github.com/openacid/low v0.1.21 diff --git a/go.sum b/go.sum index a747291f..f26ac2ec 100644 --- a/go.sum +++ b/go.sum @@ -102,8 +102,8 @@ github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba h1:He 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/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb h1:uoeOqHaQmNPev9RewQlff9Z55yuczEhRizcgDf4lSAw= -github.com/metacubex/sing-wireguard v0.0.0-20230420053659-05c12d25b6eb/go.mod h1:Bsw2BvKMMMY0FhZPseDI50ZOalvoUPMKYyGpyqvIIqY= +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/mroth/weightedrand/v2 v2.0.0 h1:ADehnByWbliEDIazDAKFdBHoqgHSXAkgyKqM/9YsPoo= From 888c233e9c51d4f7c80fac0566bf81f5615ef734 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 26 Apr 2023 13:33:35 +0800 Subject: [PATCH 234/530] fix: sing-mux udp --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 21064360..5e805c16 100644 --- a/go.mod +++ b/go.mod @@ -28,8 +28,8 @@ require ( 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.20230425145913-0c037cb0e2c8 - github.com/sagernet/sing-mux v0.0.0-20230424015424-9b0d527c3bb0 + github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9 + github.com/sagernet/sing-mux v0.0.0-20230425130511-b0a6ffd8406f github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index f26ac2ec..5d251c05 100644 --- a/go.sum +++ b/go.sum @@ -145,10 +145,10 @@ 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.20230425145913-0c037cb0e2c8 h1:bf0WjE6g+bRhNCSe5u0xTeZLK/NboSy1/tI4eqPjvU0= -github.com/sagernet/sing v0.2.5-0.20230425145913-0c037cb0e2c8/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-mux v0.0.0-20230424015424-9b0d527c3bb0 h1:87jyxzTjq01VgEiUVSMNRKjCfsSfp/QwyUVT37eXY50= -github.com/sagernet/sing-mux v0.0.0-20230424015424-9b0d527c3bb0/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= +github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9 h1:kpgKJbhesj6BBLTKIfBCJGQPm2ww7pNxn566C6TrHdA= +github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing-mux v0.0.0-20230425130511-b0a6ffd8406f h1:iEpOTgBTjt0vZJVXMTqYq13XyIu/337TWbq6WZ3CMWc= +github.com/sagernet/sing-mux v0.0.0-20230425130511-b0a6ffd8406f/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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= From eceea72a567c82cc222e1cff1f8ccfdcb5a45498 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 26 Apr 2023 15:57:25 +0800 Subject: [PATCH 235/530] fix: tunnel udp panic --- adapter/outbound/singmux.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index cf18a6f3..acfdfe99 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -2,12 +2,14 @@ package outbound import ( "context" + "errors" "net" "runtime" CN "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" + "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" mux "github.com/sagernet/sing-mux" @@ -73,7 +75,17 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, } options := s.base.DialOptions(opts...) s.dialer.dialer = dialer.NewDialer(options...) - pc, err := s.client.ListenPacket(ctx, M.ParseSocksaddr(metadata.RemoteAddress())) + + // sing-mux use stream-oriented udp with a special address, so we need a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } + + pc, err := s.client.ListenPacket(ctx, M.SocksaddrFromNet(metadata.UDPAddr())) if err != nil { return nil, err } From a1b6d6050f44646e0e32581263f197f90ad3f916 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:02:21 +0000 Subject: [PATCH 236/530] chore: remove debug_api patch --- patch/add_debug_api.patch | 53 --------------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 patch/add_debug_api.patch diff --git a/patch/add_debug_api.patch b/patch/add_debug_api.patch deleted file mode 100644 index 7134b378..00000000 --- a/patch/add_debug_api.patch +++ /dev/null @@ -1,53 +0,0 @@ -Subject: [PATCH] Chore: add debug api ---- -Index: hub/route/debug.go -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/hub/route/debug.go b/hub/route/debug.go -new file mode 100644 ---- /dev/null (revision df1007e2b14f7a526d176410995998bf06054657) -+++ b/hub/route/debug.go (revision df1007e2b14f7a526d176410995998bf06054657) -@@ -0,0 +1,21 @@ -+package route -+ -+import ( -+ "github.com/Dreamacro/clash/log" -+ "github.com/go-chi/chi/v5" -+ "github.com/go-chi/chi/v5/middleware" -+ "net/http" -+ "runtime" -+) -+ -+func debugRouter() http.Handler { -+ handler := middleware.Profiler() -+ r := chi.NewRouter() -+ r.Mount("/", handler) -+ r.Put("/gc", func(writer http.ResponseWriter, request *http.Request) { -+ log.Debugln("trigger GC") -+ runtime.GC() -+ }) -+ -+ return r -+} -Index: hub/route/server.go -IDEA additional info: -Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP -<+>UTF-8 -=================================================================== -diff --git a/hub/route/server.go b/hub/route/server.go ---- a/hub/route/server.go (revision f83fd6c690928ca7861196e3ca5af566303f95d5) -+++ b/hub/route/server.go (revision df1007e2b14f7a526d176410995998bf06054657) -@@ -59,6 +59,11 @@ - MaxAge: 300, - }) - r.Use(corsM.Handler) -+ -+ r.Group(func(r chi.Router) { -+ r.Mount("/debug", debugRouter()) -+ }) -+ - r.Group(func(r chi.Router) { - r.Use(authentication) - r.Get("/", hello) From 30f93debc4769319afb6bf77837e5a3557788fc8 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 26 Apr 2023 14:09:17 +0000 Subject: [PATCH 237/530] chore: better workflow --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 87cfb07f..86352a15 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,6 @@ on: - ".github/ISSUE_TEMPLATE/**" branches: - Alpha - - Meta tags: - "v*" pull_request_target: From 573216befbea3399f36e8b4358cd2e4365a0e0e1 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 27 Apr 2023 01:39:29 +0000 Subject: [PATCH 238/530] fix: tracker remote addr check --- tunnel/statistic/tracker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index c4feeddb..0eaf4820 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -112,7 +112,7 @@ func (tt *tcpTracker) Upstream() any { func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *tcpTracker { if conn != nil { - if tcpAddr, ok := conn.RemoteAddr().(*net.TCPAddr); ok { + if tcpAddr, ok := conn.RemoteAddr().(*net.TCPAddr); ok && tcpAddr.IP != nil { metadata.RemoteDst = tcpAddr.IP.String() } else { metadata.RemoteDst = conn.RemoteDestination() From e4f762822a8613edb9b77227f9876a805f85fa26 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 27 Apr 2023 02:32:25 +0000 Subject: [PATCH 239/530] chore: better parse remote dst --- tunnel/statistic/tracker.go | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 0eaf4820..170cbc99 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -3,6 +3,7 @@ package statistic import ( "io" "net" + "net/netip" "time" "github.com/Dreamacro/clash/common/atomic" @@ -110,13 +111,24 @@ func (tt *tcpTracker) Upstream() any { return tt.Conn } +func parseRemoteDestination(addr net.Addr, conn C.Connection) string { + if addr == nil && conn != nil { + return conn.RemoteDestination() + } + if addrPort, err := netip.ParseAddrPort(addr.String()); err == nil && addrPort.Addr().IsValid() { + return addrPort.Addr().String() + } else { + if conn != nil { + return conn.RemoteDestination() + } else { + return "" + } + } +} + func NewTCPTracker(conn C.Conn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *tcpTracker { if conn != nil { - if tcpAddr, ok := conn.RemoteAddr().(*net.TCPAddr); ok && tcpAddr.IP != nil { - metadata.RemoteDst = tcpAddr.IP.String() - } else { - metadata.RemoteDst = conn.RemoteDestination() - } + metadata.RemoteDst = parseRemoteDestination(conn.RemoteAddr(), conn) } t := &tcpTracker{ @@ -190,7 +202,7 @@ func (ut *udpTracker) Close() error { } func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker { - metadata.RemoteDst = conn.RemoteDestination() + metadata.RemoteDst = parseRemoteDestination(nil, conn) ut := &udpTracker{ PacketConn: conn, From 928dcf9af9665af763190db52315f619435a3076 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 27 Apr 2023 06:55:53 +0000 Subject: [PATCH 240/530] chore: better memory fetching time --- tunnel/statistic/manager.go | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 381ea7e6..ba2e1298 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -61,6 +61,7 @@ func (m *Manager) Now() (up int64, down int64) { } func (m *Manager) Memory() uint64 { + m.updateMemory() return m.memory } @@ -70,16 +71,6 @@ func (m *Manager) Snapshot() *Snapshot { connections = append(connections, value.(tracker)) return true }) - - getMem := func() uint64 { - stat, err := m.process.MemoryInfo() - if err != nil { - return 0 - } - return stat.RSS - } - m.memory = getMem() - return &Snapshot{ UploadTotal: m.uploadTotal.Load(), DownloadTotal: m.downloadTotal.Load(), @@ -88,6 +79,14 @@ func (m *Manager) Snapshot() *Snapshot { } } +func (m *Manager) updateMemory() { + stat, err := m.process.MemoryInfo() + if err != nil { + return + } + m.memory = stat.RSS +} + func (m *Manager) ResetStatistic() { m.uploadTemp.Store(0) m.uploadBlip.Store(0) From 87d2d08a8f67705bc2ef27e5af497b542cafbbb7 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Thu, 27 Apr 2023 07:06:53 +0000 Subject: [PATCH 241/530] chore: `clash` filter link local --- config/config.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 24594ee2..71f4087e 100644 --- a/config/config.go +++ b/config/config.go @@ -841,7 +841,7 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) { } else { ips := make([]netip.Addr, 0) for _, addr := range addrs { - if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() { + if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback()&&!ipnet.IP.IsLinkLocalUnicast() { if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil { ips = append(ips, ip) } From 898f10ca96626cd4f85ed7289c6ebf2942192c80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Thu, 27 Apr 2023 22:18:09 +0800 Subject: [PATCH 242/530] Fix concurrent close on h2mux server conn --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5e805c16..0d4a638e 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( 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.20230425211221-a23ffbaeb5b9 - github.com/sagernet/sing-mux v0.0.0-20230425130511-b0a6ffd8406f + github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index 5d251c05..37cc84b1 100644 --- a/go.sum +++ b/go.sum @@ -147,8 +147,8 @@ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2 github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9 h1:kpgKJbhesj6BBLTKIfBCJGQPm2ww7pNxn566C6TrHdA= github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= -github.com/sagernet/sing-mux v0.0.0-20230425130511-b0a6ffd8406f h1:iEpOTgBTjt0vZJVXMTqYq13XyIu/337TWbq6WZ3CMWc= -github.com/sagernet/sing-mux v0.0.0-20230425130511-b0a6ffd8406f/go.mod h1:pF+RnLvCAOhECrvauy6LYOpBakJ/vuaF1Wm4lPsWryI= +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-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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= From a7233f603620d0e31ef3651d8eb5c3501d892e57 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 28 Apr 2023 16:55:35 +0000 Subject: [PATCH 243/530] fix: wildcard matching problem --- component/trie/domain_set.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/component/trie/domain_set.go b/component/trie/domain_set.go index be793ad3..41ca2161 100644 --- a/component/trie/domain_set.go +++ b/component/trie/domain_set.go @@ -104,8 +104,8 @@ func (ss *DomainSet) Has(key string) bool { goto RESTART } } - for ; ; nextBmIdx++ { - if nextBmIdx-nextNodeId < len(ss.labels) && ss.labels[nextBmIdx-nextNodeId] == domainStepByte { + for ; nextBmIdx-nextNodeId < len(ss.labels); nextBmIdx++ { + if ss.labels[nextBmIdx-nextNodeId] == domainStepByte { bmIdx = nextBmIdx nodeId = nextNodeId i = j From 6ecd1c31e5ae292cd891421cdec7153c0b2e2a91 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 29 Apr 2023 15:44:07 +0000 Subject: [PATCH 244/530] fix: tuic connection error using fast_open --- transport/tuic/client.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/transport/tuic/client.go b/transport/tuic/client.go index af00da03..583eaba7 100644 --- a/transport/tuic/client.go +++ b/transport/tuic/client.go @@ -307,6 +307,10 @@ type earlyConn struct { RequestTimeout time.Duration } +func (conn *earlyConn) ReaderReplaceable() bool { + return false +} + func (conn *earlyConn) response() error { if conn.RequestTimeout > 0 { _ = conn.SetReadDeadline(time.Now().Add(conn.RequestTimeout)) From 19b403da866b00a372760aeae74cd4d0dc507f02 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 30 Apr 2023 18:57:16 +0800 Subject: [PATCH 245/530] refactor: Switch to sing-shadowsocks2 client --- adapter/outbound/shadowsocks.go | 8 +- go.mod | 1 + go.sum | 2 + test/go.mod | 95 ++++++++---- test/go.sum | 263 ++++++++++++++++++-------------- 5 files changed, 214 insertions(+), 155 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index e2ed24c2..01b0bd46 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -6,7 +6,6 @@ import ( "fmt" "net" "strconv" - "time" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/structure" @@ -21,8 +20,7 @@ import ( v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" restlsC "github.com/3andne/restls-client-go" - shadowsocks "github.com/metacubex/sing-shadowsocks" - "github.com/metacubex/sing-shadowsocks/shadowimpl" + "github.com/sagernet/sing-shadowsocks2" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/uot" @@ -234,7 +232,9 @@ func (ss *ShadowSocks) SupportUOT() bool { func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) - method, err := shadowimpl.FetchMethod(option.Cipher, option.Password, time.Now) + method, err := shadowsocks.CreateMethod(context.Background(), option.Cipher, shadowsocks.MethodOptions{ + Password: option.Password, + }) if err != nil { return nil, fmt.Errorf("ss %s initialize error: %w", addr, err) } diff --git a/go.mod b/go.mod index 0d4a638e..baad3ea3 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9 github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e + github.com/sagernet/sing-shadowsocks2 v0.0.0-20230430083720-38321e1355cc github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index 37cc84b1..08ca5915 100644 --- a/go.sum +++ b/go.sum @@ -149,6 +149,8 @@ github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9 h1:kpgKJbhesj6BBLT github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9/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-20230430083720-38321e1355cc h1:Jvm/7wtYYRP4mrZtUpWJxNxwnntqK+n8e/xgMHkOyP0= +github.com/sagernet/sing-shadowsocks2 v0.0.0-20230430083720-38321e1355cc/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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= diff --git a/test/go.mod b/test/go.mod index 6cbf50e8..e2e164b7 100644 --- a/test/go.mod +++ b/test/go.mod @@ -6,26 +6,34 @@ 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.50 - github.com/stretchr/testify v1.8.1 - golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e + github.com/miekg/dns v1.1.53 + github.com/stretchr/testify v1.8.2 + golang.org/x/net v0.9.0 ) replace github.com/Dreamacro/clash => ../ require ( - github.com/Microsoft/go-winio v0.5.1 // indirect + github.com/3andne/restls-client-go v0.1.4 // indirect + github.com/Microsoft/go-winio v0.6.0 // indirect + github.com/RyuaNerin/go-krypto v1.0.2 // indirect + 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/coreos/go-iptables v0.6.0 // indirect - github.com/database64128/tfo-go/v2 v2.0.2 // 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/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 + github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect + 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/gofrs/uuid v4.3.1+incompatible // 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 @@ -33,53 +41,74 @@ require ( 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/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c // indirect - github.com/josharian/native v1.0.0 // indirect + github.com/hashicorp/yamux v0.1.1 // indirect + github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 // 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/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 // indirect - github.com/marten-seemann/qpack v0.3.0 // indirect - github.com/marten-seemann/qtls-go1-18 v0.1.3 // indirect - github.com/marten-seemann/qtls-go1-19 v0.1.1 // indirect - github.com/mdlayher/netlink v1.7.0 // indirect + github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 // indirect github.com/mdlayher/socket v0.4.0 // indirect - github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e // indirect - github.com/metacubex/sing-shadowsocks v0.1.0 // indirect - github.com/metacubex/sing-tun v0.1.0 // indirect - github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c // 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/sing-wireguard v0.0.0-20230426030325-41db09ae771a // indirect github.com/moby/term v0.0.0-20221105221325-4eb28fa6025c // indirect github.com/morikuni/aec v1.0.0 // indirect + github.com/mroth/weightedrand/v2 v2.0.0 // 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 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/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/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e // 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/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.1.0 // indirect - github.com/sagernet/sing-vmess v0.1.0 // indirect - github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c // indirect - github.com/samber/lo v1.35.0 // indirect + github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9 // indirect + github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e // indirect + github.com/sagernet/sing-shadowsocks2 v0.0.0-20230430083720-38321e1355cc // indirect + github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b // 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.3 // indirect + github.com/shoenig/go-m1cpu v0.1.5 // 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/u-root/uio v0.0.0-20210528114334-82958018845c // 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/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 - go.uber.org/atomic v1.10.0 // indirect - golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a // indirect - golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect + golang.org/x/crypto v0.8.0 // indirect + golang.org/x/exp v0.0.0-20230321023759-10a507213a29 // indirect + golang.org/x/mod v0.8.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 // indirect - golang.org/x/text v0.4.0 // indirect - golang.org/x/time v0.0.0-20191024005414-555d28b269f0 // indirect - golang.org/x/tools v0.1.12 // indirect - google.golang.org/protobuf v1.28.1 // indirect + golang.org/x/sys v0.7.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 gopkg.in/yaml.v3 v3.0.1 // indirect - gotest.tools/v3 v3.4.0 // indirect - gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c // indirect lukechampine.com/blake3 v1.1.7 // indirect ) diff --git a/test/go.sum b/test/go.sum index 22e24a16..bc4c6a7b 100644 --- a/test/go.sum +++ b/test/go.sum @@ -1,8 +1,17 @@ +github.com/3andne/restls-client-go v0.1.4 h1:kLNC2aSRHPlEVYmTj6EOqJoorCpobEe2toMRSfBF7FU= +github.com/3andne/restls-client-go v0.1.4/go.mod h1:04CGbRk1BwBiEDles8b5mlKgTqIwE5MqF7JDloJV47I= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY= -github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84= +github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= +github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= +github.com/RyuaNerin/go-krypto v1.0.2 h1:9KiZrrBs+tDrQ66dNy4nrX6SzntKtSKdm0wKHhdB4WM= +github.com/RyuaNerin/go-krypto v1.0.2/go.mod h1:17LzMeJCgzGTkPH3TmfzRnEJ/yA7ErhTPp9sxIqONtA= +github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok= +github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344/go.mod h1:9pIqrY6SXNL8vjRQE5Hd/OL5GyK/9MrGUWs87z/eFfk= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= +github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= +github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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= @@ -10,8 +19,6 @@ 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/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/database64128/tfo-go/v2 v2.0.2 h1:5rGgkJeLEKlNaqredfrPQNLnctn1b+1fq/8tdKdOzJg= -github.com/database64128/tfo-go/v2 v2.0.2/go.mod h1:FDdt4JaAsRU66wsYHxSVytYimPkKIHupVsxM+5DhvjY= 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= @@ -25,94 +32,100 @@ github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKoh github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/fanliao/go-promise v0.0.0-20141029170127-1890db352a72/go.mod h1:PjfxuH4FZdUyfMdtBio2lsRr1AKEaVPwelzuHuh8Lqc= +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= +github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391/go.mod h1:K2R7GhgxrlJzHw2qiPWsCZXf/kXEJN9PLnQK73Ll0po= +github.com/ericlagergren/saferand v0.0.0-20220206064634-960a4dd2bc5c h1:RUzBDdZ+e/HEe2Nh8lYsduiPAZygUfVXJn0Ncj5sHMg= +github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 h1:tlDMEdcPRQKBEz5nGDMvswiajqh7k8ogWRlhRwKy5mY= +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/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= +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/gofrs/uuid v4.3.1+incompatible h1:0/KbAdpx3UXAx1kEOWHJeOkpbgRFGHVgv+CFIY7dBJI= -github.com/gofrs/uuid v4.3.1+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= +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= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= 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/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.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= 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/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +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/hugelgupf/socketpair v0.0.0-20190730060125-05d35a94e714/go.mod h1:2Goc3h8EklBH5mspfHFxBnEoURQCGzQQH1ga9Myjvis= +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-20221001123530-5308ebe5334c h1:OCFM4+DXTWfNlyeoddrTwdup/ztkGSyAMR2UGcPckNQ= -github.com/insomniacslk/dhcp v0.0.0-20221001123530-5308ebe5334c/go.mod h1:h+MxyHxRg9NH3terB1nfRIUaQEcI0XOVkdR9LNBlp8E= -github.com/josharian/native v1.0.0 h1:Ts/E8zCSEsG17dUqv7joXJFybuMLjQfWE04tsBODTxk= -github.com/josharian/native v1.0.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= +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/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= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= -github.com/jsimonetti/rtnetlink v0.0.0-20190606172950-9527aa82566a/go.mod h1:Oz+70psSo5OFh8DBl0Zv2ACw7Esh6pPUphlvZG9x7uw= -github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= -github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqoO/u39cqLeBLebZ8fWdE96O7FxrAsRYhnVOdgHxok= -github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= -github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 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/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/marten-seemann/qpack v0.3.0 h1:UiWstOgT8+znlkDPOg2+3rIuYXJ2CnGDkGUXN6ki6hE= -github.com/marten-seemann/qpack v0.3.0/go.mod h1:cGfKPBiP4a9EQdxCwEwI/GEeWAsjSekBvx/X8mh58+g= -github.com/marten-seemann/qtls-go1-18 v0.1.3 h1:R4H2Ks8P6pAtUagjFty2p7BVHn3XiwDAl7TTQf5h7TI= -github.com/marten-seemann/qtls-go1-18 v0.1.3/go.mod h1:mJttiymBAByA49mhlNZZGrH5u1uXYZJ+RW28Py7f4m4= -github.com/marten-seemann/qtls-go1-19 v0.1.1 h1:mnbxeq3oEyQxQXwI4ReCgW9DPoPR94sNlqWoDZnjRIE= -github.com/marten-seemann/qtls-go1-19 v0.1.1/go.mod h1:5HTDWtVudo/WFsHKRNuOhWlbdjrfs5JHrYb0wIJqGpI= -github.com/mdlayher/ethernet v0.0.0-20190606142754-0394541c37b7/go.mod h1:U6ZQobyTjI/tJyq2HG+i/dfSoFUt8/aZCM+GKtmFk/Y= -github.com/mdlayher/netlink v0.0.0-20190409211403-11939a169225/go.mod h1:eQB3mZE4aiYnlUsyGGCOpPETfdQq4Jhsgf1fk3cwQaA= -github.com/mdlayher/netlink v1.0.0/go.mod h1:KxeJAFOFLG6AjpyDkQ/iIhxygIUKD+vcwqcnu43w/+M= -github.com/mdlayher/netlink v1.1.0/go.mod h1:H4WCitaheIsdF9yOYu8CFmCgQthAPIWZmcKp9uZHgmY= -github.com/mdlayher/netlink v1.1.1/go.mod h1:WTYpFb/WTvlRJAyKhZL5/uy69TDDpHHu2VZmb2XgV7o= -github.com/mdlayher/netlink v1.7.0 h1:ZNGI4V7i1fJ94DPYtWhI/R85i/Q7ZxnuhUJQcJMoodI= -github.com/mdlayher/netlink v1.7.0/go.mod h1:nKO5CSjE/DJjVhk/TNp6vCE1ktVxEA8VEh8drhZzxsQ= -github.com/mdlayher/raw v0.0.0-20190606142536-fef19f00fc18/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= -github.com/mdlayher/raw v0.0.0-20191009151244-50f2db8cc065/go.mod h1:7EpbotpCmVZcu+KCX4g9WaRNuu11uyhiW7+Le1dKawg= +github.com/mdlayher/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/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e h1:RnfC6+sShJ3biU2Q2wuh4FxZ8/3fp1QG+1zAfswVehA= -github.com/metacubex/quic-go v0.31.1-0.20221127023445-9f0ce65a734e/go.mod h1:7NPWVTLiX2Ss9q9gBNZaNHsPqZ3Tg/ApyrXxxUYbl78= -github.com/metacubex/sing-shadowsocks v0.1.0 h1:uGBtNkpy4QFlofaNkJf+iFegeLU11VzTUlkC46FHF8A= -github.com/metacubex/sing-shadowsocks v0.1.0/go.mod h1:8pBSYDKVxTtqUtGZyEh4ZpFJXwP6wBVVKrs6oQiOwmQ= -github.com/metacubex/sing-tun v0.1.0 h1:iQj0+0WjJynSKAtfv87wOZlVKWl3w9RvkOSkVe9zuMg= -github.com/metacubex/sing-tun v0.1.0/go.mod h1:l4JyI6RTrlHLQz5vSakg+wxA+LwGVI0Mz5ZtlOv67dA= -github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c h1:VHtXDny/TNOF7YDT9d9Qkr+x6K1O4cejXLlyPUXDeXQ= -github.com/metacubex/sing-wireguard v0.0.0-20221109114053-16c22adda03c/go.mod h1:fULJ451x1/XlpIhl+Oo+EPGKla9tFZaqT5dKLrZ+NvM= -github.com/miekg/dns v1.1.50 h1:DQUfb9uc6smULcREF09Uc+/Gd46YWqJd5DbpPE9xkcA= -github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME= +github.com/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/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/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/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/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= +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/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM= @@ -121,45 +134,79 @@ github.com/oschwald/geoip2-golang v1.8.0 h1:KfjYB8ojCEn/QLqsDU0AzrJ3R5Qa9vFlx3z6 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/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= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= +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/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e h1:5CFRo8FJbCuf5s/eTBdZpmMbn8Fe2eSMLNAYfKanA34= -github.com/sagernet/abx-go v0.0.0-20220819185957-dba1257d738e/go.mod h1:qbt0dWObotCfcjAJJ9AxtFPNSDUfZF+6dCpgKEOBn/g= 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.0 h1:FGmaP2BVPYO2IyC/3R1DaQa/zr+kOKHRgWqrmOF+Gu8= -github.com/sagernet/sing v0.1.0/go.mod h1:zvgDYKI+vCAW9RyfyrKTgleI+DOa8lzHMPC7VZo3OL4= -github.com/sagernet/sing-vmess v0.1.0 h1:x0tYBJRbVi7zVXpMEW45eApGpXIDs9ub3raglouAKMo= -github.com/sagernet/sing-vmess v0.1.0/go.mod h1:4lwj6EHrUlgRnKhbmtboGbt+wtl5+tHMv96Ez8LZArw= -github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c h1:qP3ZOHnjZalvqbjundbXiv/YrNlo3HOgrKc+S1QGs0U= -github.com/sagernet/wireguard-go v0.0.0-20221108054404-7c2acadba17c/go.mod h1:euOmN6O5kk9dQmgSS8Df4psAl3TCjxOz0NW60EWkSaI= -github.com/samber/lo v1.35.0 h1:GlT8CV1GE+v97Y7MLF1wXvX6mjoxZ+hi61tj/ZcQwY0= -github.com/samber/lo v1.35.0/go.mod h1:HLeWcJRRyLKp3+/XBJvOrerCQn9mhdKMHyd7IRlgeQ8= -github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9 h1:kpgKJbhesj6BBLTKIfBCJGQPm2ww7pNxn566C6TrHdA= +github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9/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-20230430083720-38321e1355cc h1:Jvm/7wtYYRP4mrZtUpWJxNxwnntqK+n8e/xgMHkOyP0= +github.com/sagernet/sing-shadowsocks2 v0.0.0-20230430083720-38321e1355cc/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-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= +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= +github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= +github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= +github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= +github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo= +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.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE= +github.com/shirou/gopsutil/v3 v3.23.3/go.mod h1:lSBNN6t3+D6W5e5nXTxc8KIMMVxAcS+6IJlffjRRlMU= +github.com/shoenig/go-m1cpu v0.1.4/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= +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/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/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= -github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= 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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +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.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/thoas/go-funk v0.9.1 h1:O549iLZqPpTUQ10ykd26sZhzD+rmR5pWhuElrhbC20M= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c h1:BFvcl34IGnw8yvJi8hlqLFo9EshRInwWBs2M5fGWzQA= -github.com/u-root/uio v0.0.0-20210528114334-82958018845c/go.mod h1:LpEX5FO/cB+WF4TYGY1V5qktpaZLkKkSegbr0V4eYXA= +github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= +github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +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.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= @@ -167,40 +214,35 @@ github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837/go.mod h1:YJTRELIWrGxR1s8x 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/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.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ= -go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a h1:diz9pEYuTIuLMJLs3rGDkeaTsNyRs6duYdFyPAxzE/U= -golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4= -golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE= +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/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.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +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/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190419010253-1f3472d942ba/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20191007182048-72f939374954/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200202094626-16171245cfb2/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-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e h1:IVOjWZQH/57UDcpX19vSmMz8w3ohroOMWohn8qWpRkg= -golang.org/x/net v0.2.1-0.20221117215542-ecf7fda6a59e/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= +golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= 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= @@ -208,60 +250,48 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190411185658-b44545bcd369/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190418153312-f0ce4c0180be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190606122018-79a91cf218c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/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-20200202164722-d101bd2416d5/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-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/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= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669 h1:pvmSpBoSG0gD2LLPAX15QHPig8xsbU0tu1sSAmResqk= -golang.org/x/sys v0.2.1-0.20221110211117-d684c6f88669/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/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.6.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/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.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.4.0 h1:BrVqGRd7+k1DiOgtnFvAkoQEWQvBc25ouMJM6429SFg= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +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/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 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.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +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/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.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= -google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= +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= 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/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -269,8 +299,5 @@ gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C 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= -gotest.tools/v3 v3.4.0/go.mod h1:CtbdzLSsqVhDgMtKsx03ird5YTGB3ar27v0u/yKBW5g= -gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c h1:m5lcgWnL3OElQNVyp3qcncItJ2c0sQlSGjYK2+nJTA4= -gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c/go.mod h1:TIvkJD0sxe8pIob3p6T8IzxXunlp6yfgktvTNp+DGNM= lukechampine.com/blake3 v1.1.7 h1:GgRMhmdsuK8+ii6UZFDL8Nb+VyMwadAgcJyfYHxG6n0= lukechampine.com/blake3 v1.1.7/go.mod h1:tkKEOtDkNtklkXtLNEOGNq5tcV90tJiA1vAA12R78LA= From d6931ec491dfad55d2043caddcef242939f536dc Mon Sep 17 00:00:00 2001 From: sleshep <9625413+sleshep@users.noreply.github.com> Date: Wed, 26 Apr 2023 15:57:55 +0800 Subject: [PATCH 246/530] feat: support system dns --- config/config.go | 4 +++- dns/system.go | 39 +++++++++++++++++++++++++++++++++++++++ dns/system_windows.go | 7 +++++++ dns/util.go | 8 ++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 dns/system.go create mode 100644 dns/system_windows.go diff --git a/config/config.go b/config/config.go index 71f4087e..35929849 100644 --- a/config/config.go +++ b/config/config.go @@ -841,7 +841,7 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) { } else { ips := make([]netip.Addr, 0) for _, addr := range addrs { - if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback()&&!ipnet.IP.IsLinkLocalUnicast() { + if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() && !ipnet.IP.IsLinkLocalUnicast() { if ip, err := netip.ParseAddr(ipnet.IP.String()); err == nil { ips = append(ips, ip) } @@ -938,6 +938,8 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) case "quic": addr, err = hostWithDefaultPort(u.Host, "853") dnsNetType = "quic" // DNS over QUIC + case "system": + dnsNetType = "system" // System DNS default: return nil, fmt.Errorf("DNS NameServer[%d] unsupport scheme: %s", idx, u.Scheme) } diff --git a/dns/system.go b/dns/system.go new file mode 100644 index 00000000..2e52f90f --- /dev/null +++ b/dns/system.go @@ -0,0 +1,39 @@ +//go:build !windows + +package dns + +import ( + "fmt" + "os" + "regexp" +) + +var ( + // nameserver xxx.xxx.xxx.xxx + nameserverPattern = regexp.MustCompile(`nameserver\s+(?P\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`) +) + +func loadSystemResolver() (clients []dnsClient, err error) { + content, err := os.ReadFile("/etc/resolv.conf") + if err != nil { + err = fmt.Errorf("failed to read /etc/resolv.conf: %w", err) + return + } + nameservers := make([]string, 0) + for _, line := range nameserverPattern.FindAllStringSubmatch(string(content), -1) { + addr := line[1] + nameservers = append(nameservers, addr) + } + if len(nameservers) == 0 { + err = fmt.Errorf("no nameserver found in /etc/resolv.conf") + return + } + servers := make([]NameServer, 0, len(nameservers)) + for _, addr := range nameservers { + servers = append(servers, NameServer{ + Addr: fmt.Sprintf("%s:%d", addr, 53), + Net: "udp", + }) + } + return transform(servers, nil), nil +} diff --git a/dns/system_windows.go b/dns/system_windows.go new file mode 100644 index 00000000..3334af96 --- /dev/null +++ b/dns/system_windows.go @@ -0,0 +1,7 @@ +//go:build windows + +package dns + +func loadSystemResolver() (clients []dnsClient, err error) { + return nil, errors.New("system resolver is not yet supported on Windows") +} diff --git a/dns/util.go b/dns/util.go index bfd2e9ed..948687ac 100644 --- a/dns/util.go +++ b/dns/util.go @@ -79,6 +79,14 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { case "dhcp": ret = append(ret, newDHCPClient(s.Addr)) continue + case "system": + clients, err := loadSystemResolver() + if err != nil { + log.Warnln("[DNS:system] load system resolver failed: %s", err.Error()) + continue + } + ret = append(ret, clients...) + continue case "quic": if doq, err := newDoQ(resolver, s.Addr, s.ProxyAdapter, s.ProxyName); err == nil { ret = append(ret, doq) From 94f990da31ad7231763afa1b6d74d23b9fa92dd9 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 1 May 2023 00:30:47 +0800 Subject: [PATCH 247/530] feat: support system dns for windows --- dns/system_windows.go | 109 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 107 insertions(+), 2 deletions(-) diff --git a/dns/system_windows.go b/dns/system_windows.go index 3334af96..3e9736d0 100644 --- a/dns/system_windows.go +++ b/dns/system_windows.go @@ -2,6 +2,111 @@ package dns -func loadSystemResolver() (clients []dnsClient, err error) { - return nil, errors.New("system resolver is not yet supported on Windows") +import ( + "fmt" + "net" + "os" + "syscall" + "unsafe" + + "golang.org/x/sys/windows" +) + +var ( + defaultNS = []string{"114.114.114.114:53"} +) + +type dnsConfig struct { + servers []string // server addresses (in host:port form) to use +} + +func loadSystemResolver() (clients []dnsClient, err error) { + content, err := dnsReadConfig() + if err != nil { + err = fmt.Errorf("failed to read system DNS: %w", err) + } + nameservers := content.servers + if len(nameservers) == 0 { + err = fmt.Errorf("no nameserver found in windows system") + return + } + servers := make([]NameServer, 0, len(nameservers)) + for _, addr := range nameservers { + servers = append(servers, NameServer{ + Addr: addr, + Net: "udp", + }) + } + return transform(servers, nil), nil +} + +func dnsReadConfig() (conf *dnsConfig, err error) { + conf = &dnsConfig{} + defer func() { + if len(conf.servers) == 0 { + conf.servers = defaultNS + } + }() + aas, err := adapterAddresses() + if err != nil { + return conf, err + } + for _, aa := range aas { + for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next { + sa, err := dns.Address.Sockaddr.Sockaddr() + if err != nil { + continue + } + var ip net.IP + switch sa := sa.(type) { + case *syscall.SockaddrInet4: + ip = net.IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) + case *syscall.SockaddrInet6: + //ip = make(net.IP, net.IPv6len) + //copy(ip, sa.Addr[:]) + //if ip[0] == 0xfe && ip[1] == 0xc0 { + // // Ignore these fec0/10 ones. Windows seems to + // // populate them as defaults on its misc rando + // // interfaces. + // continue + //} + continue + default: + // Unexpected type. + continue + } + conf.servers = append(conf.servers, net.JoinHostPort(ip.String(), "53")) + } + } + return conf, nil +} + +// adapterAddresses returns a list of IP adapter and address +// structures. The structure contains an IP adapter and flattened +// multiple IP addresses including unicast, anycast and multicast +// addresses. +func adapterAddresses() ([]*windows.IpAdapterAddresses, error) { + var b []byte + l := uint32(15000) // recommended initial size + for { + b = make([]byte, l) + err := windows.GetAdaptersAddresses(syscall.AF_UNSPEC, windows.GAA_FLAG_INCLUDE_PREFIX, 0, (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])), &l) + if err == nil { + if l == 0 { + return nil, nil + } + break + } + if err.(syscall.Errno) != syscall.ERROR_BUFFER_OVERFLOW { + return nil, os.NewSyscallError("getadaptersaddresses", err) + } + if l <= uint32(len(b)) { + return nil, os.NewSyscallError("getadaptersaddresses", err) + } + } + var aas []*windows.IpAdapterAddresses + for aa := (*windows.IpAdapterAddresses)(unsafe.Pointer(&b[0])); aa != nil; aa = aa.Next { + aas = append(aas, aa) + } + return aas, nil } From f35ff24d0c909d3e7a1a549b42ef058541f3b0dc Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 30 Apr 2023 17:10:57 +0000 Subject: [PATCH 248/530] docs: update config.yaml --- docs/config.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/config.yaml b/docs/config.yaml index 97bd40ec..2be8be37 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -177,6 +177,7 @@ dns: - 8.8.8.8 - tls://1.12.12.12:853 - tls://223.5.5.5:853 + - system:// # get DNS server from system's configuration enhanced-mode: fake-ip # or redir-host fake-ip-range: 198.18.0.1/16 # fake-ip 池设置 From 969c235490bcfe5cd14a743a9e624d01ac8f8e1c Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 1 May 2023 12:41:36 +0800 Subject: [PATCH 249/530] chore: Remove default DNS in system resolver --- config/config.go | 3 +++ dns/system_windows.go | 10 ---------- dns/util.go | 6 +++++- docs/config.yaml | 2 +- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/config/config.go b/config/config.go index 35929849..6425934e 100644 --- a/config/config.go +++ b/config/config.go @@ -1144,6 +1144,9 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul } // check default nameserver is pure ip addr for _, ns := range dnsCfg.DefaultNameserver { + if ns.Net == "system" { + continue + } host, _, err := net.SplitHostPort(ns.Addr) if err != nil || net.ParseIP(host) == nil { u, err := url.Parse(ns.Addr) diff --git a/dns/system_windows.go b/dns/system_windows.go index 3e9736d0..2e0aa237 100644 --- a/dns/system_windows.go +++ b/dns/system_windows.go @@ -12,10 +12,6 @@ import ( "golang.org/x/sys/windows" ) -var ( - defaultNS = []string{"114.114.114.114:53"} -) - type dnsConfig struct { servers []string // server addresses (in host:port form) to use } @@ -27,7 +23,6 @@ func loadSystemResolver() (clients []dnsClient, err error) { } nameservers := content.servers if len(nameservers) == 0 { - err = fmt.Errorf("no nameserver found in windows system") return } servers := make([]NameServer, 0, len(nameservers)) @@ -42,11 +37,6 @@ func loadSystemResolver() (clients []dnsClient, err error) { func dnsReadConfig() (conf *dnsConfig, err error) { conf = &dnsConfig{} - defer func() { - if len(conf.servers) == 0 { - conf.servers = defaultNS - } - }() aas, err := adapterAddresses() if err != nil { return conf, err diff --git a/dns/util.go b/dns/util.go index 948687ac..d85deb17 100644 --- a/dns/util.go +++ b/dns/util.go @@ -82,7 +82,11 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { case "system": clients, err := loadSystemResolver() if err != nil { - log.Warnln("[DNS:system] load system resolver failed: %s", err.Error()) + log.Errorln("[DNS:system] load system resolver failed: %s", err.Error()) + continue + } + if len(clients) == 0 { + log.Errorln("[DNS:system] no nameserver found in system") continue } ret = append(ret, clients...) diff --git a/docs/config.yaml b/docs/config.yaml index 2be8be37..66cab25c 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -177,7 +177,7 @@ dns: - 8.8.8.8 - tls://1.12.12.12:853 - tls://223.5.5.5:853 - - system:// # get DNS server from system's configuration + - 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 池设置 From 1eefa71e1f4db3920d40ba209b4e45d92c84fe36 Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 1 May 2023 12:58:02 +0800 Subject: [PATCH 250/530] chore: Make slash optional for system resolver --- config/config.go | 4 ++++ docs/config.yaml | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 6425934e..ff16ac11 100644 --- a/config/config.go +++ b/config/config.go @@ -974,6 +974,10 @@ func parsePureDNSServer(server string) string { return "udp://" + server } + if server == "system" { + return "system://" + } + if ip, err := netip.ParseAddr(server); err != nil { if strings.Contains(server, "://") { return server diff --git a/docs/config.yaml b/docs/config.yaml index 66cab25c..8721340f 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -177,7 +177,7 @@ 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 池设置 From 463da578ddae85c6b6c03657377daad490286550 Mon Sep 17 00:00:00 2001 From: sleshep <9625413+sleshep@users.noreply.github.com> Date: Mon, 1 May 2023 21:27:55 +0800 Subject: [PATCH 251/530] fixes #512: geo download failed when startup (#538) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fixes #512: geo download failed when startup - 启动阶段,executor还未初始化tunnel,tcpIn==nil导致geo下载失败,阻塞在 tcpIn <- context * chore: handled by the upper layer * chore: remove useless parameters --------- Co-authored-by: Skyxim --- adapter/inbound/socket.go | 15 ++++++--------- component/http/http.go | 8 ++++++-- listener/inner/tcp.go | 14 ++++++++++---- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index a6b1288c..e41ee925 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -30,21 +30,18 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad return context.NewConnContext(conn, metadata) } -func NewInner(conn net.Conn, dst string, host string) *context.ConnContext { +func NewInner(conn net.Conn, address string) *context.ConnContext { metadata := &C.Metadata{} metadata.NetWork = C.TCP metadata.Type = C.INNER metadata.DNSMode = C.DNSNormal - metadata.Host = host metadata.Process = C.ClashName - if h, port, err := net.SplitHostPort(dst); err == nil { + if h, port, err := net.SplitHostPort(address); err == nil { metadata.DstPort = port - if host == "" { - if ip, err := netip.ParseAddr(h); err == nil { - metadata.DstIP = ip - } else { - metadata.Host = h - } + if ip, err := netip.ParseAddr(h); err == nil { + metadata.DstIP = ip + } else { + metadata.Host = h } } diff --git a/component/http/http.go b/component/http/http.go index ece7b442..bcede09f 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -53,8 +53,12 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, DialContext: func(ctx context.Context, network, address string) (net.Conn, error) { - conn := inner.HandleTcp(address, "") - return conn, nil + if conn, err := inner.HandleTcp(address); err == nil { + return conn, nil + } else { + d := net.Dialer{} + return d.DialContext(ctx, network, address) + } }, TLSClientConfig: tls.GetDefaultTLSConfig(), } diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index a7e38588..9ba87e2f 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -1,9 +1,11 @@ package inner import ( + "errors" + "net" + "github.com/Dreamacro/clash/adapter/inbound" C "github.com/Dreamacro/clash/constant" - "net" ) var tcpIn chan<- C.ConnContext @@ -12,9 +14,13 @@ func New(in chan<- C.ConnContext) { tcpIn = in } -func HandleTcp(dst string, host string) net.Conn { +func HandleTcp(address string) (conn net.Conn, err error) { + if tcpIn == nil { + return nil, errors.New("tcp uninitialized") + } + // executor Parsed conn1, conn2 := net.Pipe() - context := inbound.NewInner(conn2, dst, host) + context := inbound.NewInner(conn2, address) tcpIn <- context - return conn1 + return conn1, nil } From f90066f286e02b2349988f838b8b29b0da82f4c9 Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 1 May 2023 23:38:02 +0800 Subject: [PATCH 252/530] chore: Update dependencies --- go.mod | 6 +++--- go.sum | 14 ++++++-------- test/go.mod | 6 +++--- test/go.sum | 14 ++++++-------- 4 files changed, 18 insertions(+), 22 deletions(-) diff --git a/go.mod b/go.mod index baad3ea3..0639de6a 100644 --- a/go.mod +++ b/go.mod @@ -28,16 +28,16 @@ require ( 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.20230425211221-a23ffbaeb5b9 + github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e - github.com/sagernet/sing-shadowsocks2 v0.0.0-20230430083720-38321e1355cc + github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9 github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b 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.3 + github.com/shirou/gopsutil/v3 v3.23.4 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.2 github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 diff --git a/go.sum b/go.sum index 08ca5915..548e19f6 100644 --- a/go.sum +++ b/go.sum @@ -145,12 +145,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.20230425211221-a23ffbaeb5b9 h1:kpgKJbhesj6BBLTKIfBCJGQPm2ww7pNxn566C6TrHdA= -github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +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-20230430083720-38321e1355cc h1:Jvm/7wtYYRP4mrZtUpWJxNxwnntqK+n8e/xgMHkOyP0= -github.com/sagernet/sing-shadowsocks2 v0.0.0-20230430083720-38321e1355cc/go.mod h1:Dpib342FFR68SZ3CSRYxk/zWbanAqRBrCxoLuda5I0A= +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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= @@ -165,9 +165,8 @@ 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.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE= -github.com/shirou/gopsutil/v3 v3.23.3/go.mod h1:lSBNN6t3+D6W5e5nXTxc8KIMMVxAcS+6IJlffjRRlMU= -github.com/shoenig/go-m1cpu v0.1.4/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= +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= @@ -249,7 +248,6 @@ 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.6.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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= diff --git a/test/go.mod b/test/go.mod index e2e164b7..1327f84f 100644 --- a/test/go.mod +++ b/test/go.mod @@ -75,9 +75,9 @@ require ( github.com/quic-go/qtls-go1-20 v0.1.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.20230425211221-a23ffbaeb5b9 // 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-20230430083720-38321e1355cc // 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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect @@ -85,7 +85,7 @@ require ( 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.3 // indirect + github.com/shirou/gopsutil/v3 v3.23.4 // indirect github.com/shoenig/go-m1cpu v0.1.5 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect diff --git a/test/go.sum b/test/go.sum index bc4c6a7b..b6f03871 100644 --- a/test/go.sum +++ b/test/go.sum @@ -155,12 +155,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.20230425211221-a23ffbaeb5b9 h1:kpgKJbhesj6BBLTKIfBCJGQPm2ww7pNxn566C6TrHdA= -github.com/sagernet/sing v0.2.5-0.20230425211221-a23ffbaeb5b9/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +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-20230430083720-38321e1355cc h1:Jvm/7wtYYRP4mrZtUpWJxNxwnntqK+n8e/xgMHkOyP0= -github.com/sagernet/sing-shadowsocks2 v0.0.0-20230430083720-38321e1355cc/go.mod h1:Dpib342FFR68SZ3CSRYxk/zWbanAqRBrCxoLuda5I0A= +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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= @@ -175,9 +175,8 @@ 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.3 h1:Syt5vVZXUDXPEXpIBt5ziWsJ4LdSAAxF4l/xZeQgSEE= -github.com/shirou/gopsutil/v3 v3.23.3/go.mod h1:lSBNN6t3+D6W5e5nXTxc8KIMMVxAcS+6IJlffjRRlMU= -github.com/shoenig/go-m1cpu v0.1.4/go.mod h1:Wwvst4LR89UxjeFtLRMrpgRiyY4xPsejnVZym39dbAQ= +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= @@ -267,7 +266,6 @@ 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.6.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/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= From d61a5af3351a7c4392bc5fe2b747906952b579ef Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 2 May 2023 21:35:40 +0800 Subject: [PATCH 253/530] chore: update release note --- .github/workflows/build.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86352a15..ccbe3dc6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -246,11 +246,8 @@ jobs: Release created at ${{ env.BUILDTIME }} Synchronize ${{ github.ref_name }} branch code updates, keeping only the latest version
- ### release version - `default(not specified in file name)`: compiled with GOAMD64=v3 - `cgo`: support lwip tun stack, compiled with GOAMD64=v1 - `compatible`: compiled with GOAMD64=v1 - Check details between different architectural levels [here](https://github.com/golang/go/wiki/MinimumRequirements#amd64). + [我应该下载哪个文件? / Which file should I download?](https://github.com/MetaCubeX/Clash.Meta/wiki/FAQ) + [查看文档 / Docs](https://metacubex.github.io/Meta-Docs/) EOF - name: Upload Prerelease From 7ae3e78b15ddce72079d3aaa53bacf84bb5f754f Mon Sep 17 00:00:00 2001 From: PuerNya Date: Tue, 2 May 2023 20:55:25 +0800 Subject: [PATCH 254/530] Feat: rewrite http outbound --- adapter/outbound/http.go | 37 +++++++++++++++++++------------------ 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 2d5fd899..82fff5bb 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -10,7 +10,6 @@ import ( "io" "net" "net/http" - "net/url" "strconv" "github.com/Dreamacro/clash/component/dialer" @@ -98,34 +97,36 @@ func (h *Http) SupportWithDialer() C.NetWork { func (h *Http) shakeHand(metadata *C.Metadata, rw io.ReadWriter) error { addr := metadata.RemoteAddress() - req := &http.Request{ - Method: http.MethodConnect, - URL: &url.URL{ - Host: addr, - }, - Host: addr, - Header: http.Header{ - "Proxy-Connection": []string{"Keep-Alive"}, - }, + HeaderString := "CONNECT " + addr + " HTTP/1.1\r\n" + tempHeaders := map[string]string{ + "Host": addr, + "User-Agent": "Go-http-client/1.1", + "Proxy-Connection": "Keep-Alive", } - //增加headers - if len(h.option.Headers) != 0 { - for key, value := range h.option.Headers { - req.Header.Add(key, value) - } + for key, value := range h.option.Headers { + tempHeaders[key] = value } if h.user != "" && h.pass != "" { auth := h.user + ":" + h.pass - req.Header.Add("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth))) + tempHeaders["Proxy-Authorization"] = "Basic " + base64.StdEncoding.EncodeToString([]byte(auth)) } - if err := req.Write(rw); err != nil { + for key, value := range tempHeaders { + HeaderString += key + ": " + value + "\r\n" + } + + HeaderString += "\r\n" + + _, err := rw.Write([]byte(HeaderString)) + + if err != nil { return err } - resp, err := http.ReadResponse(bufio.NewReader(rw), req) + resp, err := http.ReadResponse(bufio.NewReader(rw), nil) + if err != nil { return err } From 8c0168d3a8e8a038ee08cf3fba4fda2f1b91c0ae Mon Sep 17 00:00:00 2001 From: Skyxim Date: Fri, 5 May 2023 07:27:36 +0000 Subject: [PATCH 255/530] chore: upgrade dependencies --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 0639de6a..52a7ad10 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.2.5-0.20230501044132-8365dd48a17a github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e - github.com/sagernet/sing-shadowsocks2 v0.0.0-20230501032827-681c9c4ee0e9 + github.com/sagernet/sing-shadowsocks2 v0.0.0-20230503144228-9896afb7d1ba github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 diff --git a/go.sum b/go.sum index 548e19f6..074cfed6 100644 --- a/go.sum +++ b/go.sum @@ -151,6 +151,8 @@ github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e h1:t8nuY9plpHEzl 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-shadowsocks2 v0.0.0-20230503144228-9896afb7d1ba h1:IyAM9hOexorIEtKWufGZ+YoJWGdTqfJv0iaLb6crY8Q= +github.com/sagernet/sing-shadowsocks2 v0.0.0-20230503144228-9896afb7d1ba/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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= From bd431fbf49e01819d625c4b6758ea59539c99661 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 6 May 2023 15:49:10 +0800 Subject: [PATCH 256/530] fix: Update unsafe pointer add usage --- component/geodata/strmatcher/mph_matcher.go | 26 +++++++++------------ component/tls/reality.go | 2 +- transport/vless/conn.go | 12 +++++----- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/component/geodata/strmatcher/mph_matcher.go b/component/geodata/strmatcher/mph_matcher.go index 3c10cb49..8d8b0508 100644 --- a/component/geodata/strmatcher/mph_matcher.go +++ b/component/geodata/strmatcher/mph_matcher.go @@ -234,26 +234,26 @@ tail: case s == 0: case s < 4: h ^= uint64(*(*byte)(p)) - h ^= uint64(*(*byte)(add(p, s>>1))) << 8 - h ^= uint64(*(*byte)(add(p, s-1))) << 16 + h ^= uint64(*(*byte)(unsafe.Add(p, s>>1))) << 8 + h ^= uint64(*(*byte)(unsafe.Add(p, s-1))) << 16 h = rotl31(h*m1) * m2 case s <= 8: h ^= uint64(readUnaligned32(p)) - h ^= uint64(readUnaligned32(add(p, s-4))) << 32 + h ^= uint64(readUnaligned32(unsafe.Add(p, s-4))) << 32 h = rotl31(h*m1) * m2 case s <= 16: h ^= readUnaligned64(p) h = rotl31(h*m1) * m2 - h ^= readUnaligned64(add(p, s-8)) + h ^= readUnaligned64(unsafe.Add(p, s-8)) h = rotl31(h*m1) * m2 case s <= 32: h ^= readUnaligned64(p) h = rotl31(h*m1) * m2 - h ^= readUnaligned64(add(p, 8)) + h ^= readUnaligned64(unsafe.Add(p, 8)) h = rotl31(h*m1) * m2 - h ^= readUnaligned64(add(p, s-16)) + h ^= readUnaligned64(unsafe.Add(p, s-16)) h = rotl31(h*m1) * m2 - h ^= readUnaligned64(add(p, s-8)) + h ^= readUnaligned64(unsafe.Add(p, s-8)) h = rotl31(h*m1) * m2 default: v1 := h @@ -263,16 +263,16 @@ tail: for s >= 32 { v1 ^= readUnaligned64(p) v1 = rotl31(v1*m1) * m2 - p = add(p, 8) + p = unsafe.Add(p, 8) v2 ^= readUnaligned64(p) v2 = rotl31(v2*m2) * m3 - p = add(p, 8) + p = unsafe.Add(p, 8) v3 ^= readUnaligned64(p) v3 = rotl31(v3*m3) * m4 - p = add(p, 8) + p = unsafe.Add(p, 8) v4 ^= readUnaligned64(p) v4 = rotl31(v4*m4) * m1 - p = add(p, 8) + p = unsafe.Add(p, 8) s -= 32 } h = v1 ^ v2 ^ v3 ^ v4 @@ -285,10 +285,6 @@ tail: return uintptr(h) } -func add(p unsafe.Pointer, x uintptr) unsafe.Pointer { - return unsafe.Pointer(uintptr(p) + x) -} - func readUnaligned32(p unsafe.Pointer) uint32 { q := (*[4]byte)(p) return uint32(q[0]) | uint32(q[1])<<8 | uint32(q[2])<<16 | uint32(q[3])<<24 diff --git a/component/tls/reality.go b/component/tls/reality.go index dd4f3af8..b8a7fa3a 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -141,7 +141,7 @@ var pOffset = utils.MustOK(reflect.TypeOf((*utls.UConn)(nil)).Elem().FieldByName func (c *realityVerifier) VerifyPeerCertificate(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { //p, _ := reflect.TypeOf(c.Conn).Elem().FieldByName("peerCertificates") - certs := *(*[]*x509.Certificate)(unsafe.Pointer(uintptr(unsafe.Pointer(c.Conn)) + pOffset)) + certs := *(*[]*x509.Certificate)(unsafe.Add(unsafe.Pointer(c.Conn), pOffset)) if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok { h := hmac.New(sha512.New, c.authKey) h.Write(pub) diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 6c3714e0..9289afcf 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -474,34 +474,34 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { c.writeFilterApplicationData = true c.addons = client.Addons var t reflect.Type - var p uintptr + var p unsafe.Pointer switch underlying := conn.(type) { case *gotls.Conn: //log.Debugln("type tls") c.Conn = underlying.NetConn() c.tlsConn = underlying t = reflect.TypeOf(underlying).Elem() - p = uintptr(unsafe.Pointer(underlying)) + p = unsafe.Pointer(underlying) case *utls.UConn: //log.Debugln("type *utls.UConn") c.Conn = underlying.NetConn() c.tlsConn = underlying t = reflect.TypeOf(underlying.Conn).Elem() - p = uintptr(unsafe.Pointer(underlying.Conn)) + p = unsafe.Pointer(underlying.Conn) case *tlsC.UConn: //log.Debugln("type *tlsC.UConn") c.Conn = underlying.NetConn() c.tlsConn = underlying.UConn t = reflect.TypeOf(underlying.Conn).Elem() //log.Debugln("t:%v", t) - p = uintptr(unsafe.Pointer(underlying.Conn)) + p = unsafe.Pointer(underlying.Conn) default: return nil, fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, client.Addons.Flow) } i, _ := t.FieldByName("input") r, _ := t.FieldByName("rawInput") - c.input = (*bytes.Reader)(unsafe.Pointer(p + i.Offset)) - c.rawInput = (*bytes.Buffer)(unsafe.Pointer(p + r.Offset)) + c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset)) + c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset)) //if _, ok := c.Conn.(*net.TCPConn); !ok { // log.Debugln("XTLS underlying conn is not *net.TCPConn, got %T", c.Conn) //} From 0cb594dd5d481defafb1e8612ad3b37f39413c06 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 10 May 2023 07:23:49 +0800 Subject: [PATCH 257/530] chore: upgrade dependencies --- adapter/outbound/shadowsocks.go | 2 +- go.mod | 38 +++++++------- go.sum | 87 +++++++++++++++------------------ 3 files changed, 59 insertions(+), 68 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 01b0bd46..7ee9e634 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -20,7 +20,7 @@ import ( v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" restlsC "github.com/3andne/restls-client-go" - "github.com/sagernet/sing-shadowsocks2" + "github.com/metacubex/sing-shadowsocks2" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/uot" diff --git a/go.mod b/go.mod index 52a7ad10..531eeefe 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.19 require ( github.com/3andne/restls-client-go v0.1.4 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da - github.com/cilium/ebpf v0.9.3 + github.com/cilium/ebpf v0.10.0 github.com/coreos/go-iptables v0.6.0 - github.com/dlclark/regexp2 v1.7.0 + github.com/dlclark/regexp2 v1.9.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 @@ -18,19 +18,19 @@ require ( github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 github.com/jpillora/backoff v1.0.0 github.com/lunixbochs/struc v0.0.0-20200707160740-784aaebc1d40 - github.com/mdlayher/netlink v1.7.2-0.20221213171556-9881fafed8c7 + github.com/mdlayher/netlink v1.7.2 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 - github.com/metacubex/sing-shadowsocks v0.2.2-0.20230422111054-f54786eee8ba - github.com/metacubex/sing-tun v0.1.4 + github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230509232051-858c32776907 + github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a - github.com/miekg/dns v1.1.53 - github.com/mroth/weightedrand/v2 v2.0.0 + 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.20230501044132-8365dd48a17a + github.com/sagernet/sing v0.2.5-0.20230509045155-f60c80c56f21 github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e - github.com/sagernet/sing-shadowsocks2 v0.0.0-20230503144228-9896afb7d1ba github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 @@ -40,16 +40,16 @@ require ( github.com/shirou/gopsutil/v3 v3.23.4 github.com/sirupsen/logrus v1.9.0 github.com/stretchr/testify v1.8.2 - github.com/xtls/go v0.0.0-20220914232946-0441cf4cf837 + github.com/xtls/go v0.0.0-20230107031059-4610f88d00f3 github.com/zhangyunhao116/fastrand v0.3.0 - go.etcd.io/bbolt v1.3.6 + go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.2 - golang.org/x/crypto v0.8.0 - golang.org/x/exp v0.0.0-20230321023759-10a507213a29 - golang.org/x/net v0.9.0 - golang.org/x/sync v0.1.0 - golang.org/x/sys v0.7.0 - google.golang.org/protobuf v1.28.2-0.20230118093459-a9481185b34d + golang.org/x/crypto v0.9.0 + golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 + 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 ) @@ -76,9 +76,8 @@ require ( github.com/klauspost/compress v1.15.15 // indirect github.com/klauspost/cpuid/v2 v2.0.12 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect - github.com/mdlayher/socket v0.4.0 // indirect + github.com/mdlayher/socket v0.4.1 // indirect github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // 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 @@ -104,5 +103,4 @@ require ( 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 - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect ) diff --git a/go.sum b/go.sum index 074cfed6..ccbc7238 100644 --- a/go.sum +++ b/go.sum @@ -14,15 +14,15 @@ 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/dlclark/regexp2 v1.9.0 h1:pTK/l/3qYIKaRXuHnEnIf7Y5NxfRPfpb7dis6/gdlVI= +github.com/dlclark/regexp2 v1.9.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= @@ -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.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-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0= @@ -82,34 +82,32 @@ github.com/klauspost/compress v1.15.15/go.mod h1:ZcK2JAFqKOpnBlxcLsJzYfrS9X1akm9 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/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +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/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/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-20230509232051-858c32776907 h1:GbsWXKtzgn+QvYrdhP3TL/FJPmoxWIs4VjUP53BTaQ0= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230509232051-858c32776907/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= +github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= +github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= 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/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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +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= +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= @@ -138,21 +136,17 @@ github.com/quic-go/qtls-go1-19 v0.2.1 h1:aJcKNMkH5ASEJB9FXNeZCyTEIHU1J7MmHyz1Q1T 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/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 v0.2.5-0.20230509045155-f60c80c56f21 h1:voT2nOCvukNfRLn9KxQYEYSu9/OZsCqEmD6tEFJAnBw= +github.com/sagernet/sing v0.2.5-0.20230509045155-f60c80c56f21/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-shadowsocks2 v0.0.0-20230503144228-9896afb7d1ba h1:IyAM9hOexorIEtKWufGZ+YoJWGdTqfJv0iaLb6crY8Q= -github.com/sagernet/sing-shadowsocks2 v0.0.0-20230503144228-9896afb7d1ba/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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= @@ -200,8 +194,8 @@ github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 h1:tHNk7XK9GkmKUR6Gh8gV github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923/go.mod h1:eLL9Nub3yfAho7qB0MzZizFhTU2QkLeoVsWdHtDW264= 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.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= @@ -209,16 +203,16 @@ github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtb 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= 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.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-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o= +golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/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= @@ -227,19 +221,18 @@ 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.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-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-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-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= @@ -250,8 +243,9 @@ 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= @@ -270,11 +264,10 @@ 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-20200227125254-8fa46927fb4f/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= From 99f7c4f8210978e6a5795ae3d2b365359c4bf82d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 10 May 2023 08:31:16 +0800 Subject: [PATCH 258/530] fix: ss aead udp problem --- component/proxydialer/proxydialer.go | 2 +- go.mod | 2 +- go.sum | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index fc5cb294..83010f96 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -71,7 +71,7 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { currentMeta := &C.Metadata{Type: C.INNER} - if err := currentMeta.SetRemoteAddress(address); err != nil { + if err := currentMeta.SetRemoteAddress(rAddrPort.String()); err != nil { return nil, err } return p.listenPacket(ctx, currentMeta) diff --git a/go.mod b/go.mod index 531eeefe..26ccf70d 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c - github.com/metacubex/sing-shadowsocks2 v0.0.0-20230509232051-858c32776907 + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230510002911-25e95d677383 github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a github.com/miekg/dns v1.1.54 diff --git a/go.sum b/go.sum index ccbc7238..9a3499e3 100644 --- a/go.sum +++ b/go.sum @@ -98,8 +98,8 @@ github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594 h1:KD96JPdTIa 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.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-20230509232051-858c32776907 h1:GbsWXKtzgn+QvYrdhP3TL/FJPmoxWIs4VjUP53BTaQ0= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230509232051-858c32776907/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230510002911-25e95d677383 h1:YdLeRuENJZ9QL58Kf/qtMp1wZv9VGQJYMqZ2WEF6/FM= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230510002911-25e95d677383/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco= From 67b9314693dad67c9ad0df8345dcbd67aa870989 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 10 May 2023 09:03:49 +0800 Subject: [PATCH 259/530] fix: tuic can't work with proxy-dialer --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 26ccf70d..f590f382 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/jpillora/backoff v1.0.0 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.20230322045857-901b636b4594 + github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c github.com/metacubex/sing-shadowsocks2 v0.0.0-20230510002911-25e95d677383 github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 diff --git a/go.sum b/go.sum index 9a3499e3..5054c691 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.20230322045857-901b636b4594 h1:KD96JPdTIayTGGgRl6PuVqo2Bpo6+x3LqDDyqrYDDXw= -github.com/metacubex/quic-go v0.33.3-0.20230322045857-901b636b4594/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= +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/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-20230510002911-25e95d677383 h1:YdLeRuENJZ9QL58Kf/qtMp1wZv9VGQJYMqZ2WEF6/FM= From 15a8d7c4730abb941961672651216cff81c75383 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 10 May 2023 09:36:06 +0800 Subject: [PATCH 260/530] chore: better tuic earlyConn impl --- transport/tuic/client.go | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/transport/tuic/client.go b/transport/tuic/client.go index 583eaba7..c18a9049 100644 --- a/transport/tuic/client.go +++ b/transport/tuic/client.go @@ -11,6 +11,7 @@ import ( "sync" "sync/atomic" "time" + "unsafe" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" @@ -289,7 +290,8 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta return nil, err } - conn := &earlyConn{BufferedConn: N.NewBufferedConn(stream), RequestTimeout: t.RequestTimeout} + bufConn := N.NewBufferedConn(stream) + conn := &earlyConn{ExtendedConn: bufConn, bufConn: bufConn, RequestTimeout: t.RequestTimeout} if !t.FastOpen { err = conn.Response() if err != nil { @@ -300,22 +302,19 @@ func (t *clientImpl) DialContextWithDialer(ctx context.Context, metadata *C.Meta } type earlyConn struct { - *N.BufferedConn - resOnce sync.Once - resErr error + N.ExtendedConn // only expose standard N.ExtendedConn function to outside + bufConn *N.BufferedConn + resOnce sync.Once + resErr error RequestTimeout time.Duration } -func (conn *earlyConn) ReaderReplaceable() bool { - return false -} - func (conn *earlyConn) response() error { if conn.RequestTimeout > 0 { _ = conn.SetReadDeadline(time.Now().Add(conn.RequestTimeout)) } - response, err := ReadResponse(conn) + response, err := ReadResponse(conn.bufConn) if err != nil { _ = conn.Close() return err @@ -340,7 +339,7 @@ func (conn *earlyConn) Read(b []byte) (n int, err error) { if err != nil { return 0, err } - return conn.BufferedConn.Read(b) + return conn.bufConn.Read(b) } func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) { @@ -348,7 +347,19 @@ func (conn *earlyConn) ReadBuffer(buffer *buf.Buffer) (err error) { if err != nil { return err } - return conn.BufferedConn.ReadBuffer(buffer) + return conn.bufConn.ReadBuffer(buffer) +} + +func (conn *earlyConn) Upstream() any { + return conn.bufConn +} + +func (conn *earlyConn) ReaderReplaceable() bool { + return atomic.LoadUint32((*uint32)(unsafe.Pointer(&conn.resOnce))) == 1 && conn.resErr == nil +} + +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) { From 3b291d3fbfd92536c68165efae7728f594759f40 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 10 May 2023 16:03:28 +0800 Subject: [PATCH 261/530] fix: sing inbound should check needAdditionReadDeadline on udp too --- common/net/sing.go | 2 +- listener/sing/sing.go | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/common/net/sing.go b/common/net/sing.go index 7eb92f03..aa6f6917 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -23,7 +23,7 @@ func NewDeadlineConn(conn net.Conn) ExtendedConn { return deadline.NewFallbackConn(conn) } -func NewDeadlinePacketConn(pc net.PacketConn) net.PacketConn { +func NewDeadlinePacketConn(pc net.PacketConn) network.NetPacketConn { return deadline.NewFallbackPacketConn(bufio.NewPacketConn(pc)) } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 2ccdfe2d..4a86dc82 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -18,6 +18,7 @@ import ( 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" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" @@ -104,6 +105,9 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. additions = slices.Clone(additions) additions = append(additions, ctxAdditions...) } + if deadline.NeedAdditionalReadDeadline(conn) { + conn = N.NewDeadlinePacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline + } defer func() { _ = conn.Close() }() mutex := sync.Mutex{} conn2 := conn // a new interface to set nil in defer From c58400572ce2c93e523fbc55c7f2f469c3180be0 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 10 May 2023 22:35:50 +0800 Subject: [PATCH 262/530] chore: sing inbound support WaitReadPacket --- listener/shadowsocks/udp.go | 2 +- listener/sing/sing.go | 21 ++++++++++++++++--- listener/sing_shadowsocks/server.go | 31 +++++++++++++++++++++-------- listener/sing_tun/dns.go | 26 +++++++++++++++++++----- 4 files changed, 63 insertions(+), 17 deletions(-) diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index 3f058406..ef67d4e8 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -32,7 +32,7 @@ func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UD conn := pickCipher.PacketConn(l) go func() { for { - buf := pool.Get(pool.RelayBufferSize) + buf := pool.Get(pool.UDPBufferSize) n, remoteAddr, err := conn.ReadFrom(buf) if err != nil { pool.Put(buf) diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 4a86dc82..7292df33 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -116,11 +116,26 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() + readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) for { - buff := buf.NewPacket() // do not use stack buffer - dest, err := conn.ReadPacket(buff) + var ( + buff *buf.Buffer + dest M.Socksaddr + err error + ) + newBuffer := func() *buf.Buffer { + buff = buf.NewPacket() // do not use stack buffer + return buff + } + if isReadWaiter { + dest, err = readWaiter.WaitReadPacket(newBuffer) + } else { + dest, err = conn.ReadPacket(newBuffer()) + } if err != nil { - buff.Release() + if buff != nil { + buff.Release() + } if ShouldIgnorePacketError(err) { break } diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index c7e05bb5..31b342e8 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -21,7 +21,7 @@ import ( "github.com/sagernet/sing/common" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" - "github.com/sagernet/sing/common/metadata" + M "github.com/sagernet/sing/common/metadata" ) type Listener struct { @@ -92,19 +92,34 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C go func() { conn := bufio.NewPacketConn(ul) + readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) for { - buff := buf.NewPacket() - remoteAddr, err := conn.ReadPacket(buff) + var ( + buff *buf.Buffer + dest M.Socksaddr + err error + ) + newBuffer := func() *buf.Buffer { + buff = buf.NewPacket() // do not use stack buffer + return buff + } + if isReadWaiter { + dest, err = readWaiter.WaitReadPacket(newBuffer) + } else { + dest, err = conn.ReadPacket(newBuffer()) + } if err != nil { - buff.Release() + if buff != nil { + buff.Release() + } if sl.closed { break } continue } - _ = sl.service.NewPacket(context.TODO(), conn, buff, metadata.Metadata{ + _ = sl.service.NewPacket(context.TODO(), conn, buff, M.Metadata{ Protocol: "shadowsocks", - Source: remoteAddr, + Source: dest, }) } }() @@ -170,9 +185,9 @@ func (l *Listener) AddrList() (addrList []net.Addr) { func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { ctx := sing.WithAdditions(context.TODO(), additions...) - err := l.service.NewConnection(ctx, conn, metadata.Metadata{ + err := l.service.NewConnection(ctx, conn, M.Metadata{ Protocol: "shadowsocks", - Source: metadata.ParseSocksaddr(conn.RemoteAddr().String()), + Source: M.ParseSocksaddr(conn.RemoteAddr().String()), }) if err != nil { _ = conn.Close() diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index dc33be91..fcf0cc9c 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -17,6 +17,7 @@ import ( D "github.com/miekg/dns" "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/network" ) @@ -108,14 +109,29 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() + readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) for { - // safe size which is 1232 from https://dnsflagday.net/2020/. - // so 2048 is enough - buff := buf.NewSize(2 * 1024) + var ( + buff *buf.Buffer + dest M.Socksaddr + err error + ) + newBuffer := func() *buf.Buffer { + // safe size which is 1232 from https://dnsflagday.net/2020/. + // so 2048 is enough + buff = buf.NewSize(2 * 1024) + return buff + } _ = conn.SetReadDeadline(time.Now().Add(DefaultDnsReadTimeout)) - dest, err := conn.ReadPacket(buff) + if isReadWaiter { + dest, err = readWaiter.WaitReadPacket(newBuffer) + } else { + dest, err = conn.ReadPacket(newBuffer()) + } if err != nil { - buff.Release() + if buff != nil { + buff.Release() + } if sing.ShouldIgnorePacketError(err) { break } From 98394095e452ab971ff6fa541f6f8844765f910d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 11 May 2023 00:03:40 +0800 Subject: [PATCH 263/530] fix: udp can't auto close --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index f590f382..b51e646a 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( 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.20230509045155-f60c80c56f21 + github.com/sagernet/sing v0.2.5-0.20230510160026-237a991b46d0 github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 diff --git a/go.sum b/go.sum index 5054c691..abb18231 100644 --- a/go.sum +++ b/go.sum @@ -143,8 +143,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 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.20230509045155-f60c80c56f21 h1:voT2nOCvukNfRLn9KxQYEYSu9/OZsCqEmD6tEFJAnBw= -github.com/sagernet/sing v0.2.5-0.20230509045155-f60c80c56f21/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.5-0.20230510160026-237a991b46d0 h1:NS4U+yQ4ToyRqFvCS91BM1D6fQbriW1qvioxSj5PvI4= +github.com/sagernet/sing v0.2.5-0.20230510160026-237a991b46d0/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-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4= From d9fa051dd8dd47a948bb2eb74b0f17040a1b08c4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 11 May 2023 11:30:20 +0800 Subject: [PATCH 264/530] chore: drop bufio.Reader in BufferedConn to let gc can clean up its internal buf --- common/net/bufconn.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/common/net/bufconn.go b/common/net/bufconn.go index 2ff73c82..6da2d9d1 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -62,7 +62,7 @@ func (c *BufferedConn) Buffered() int { } func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) { - if c.r.Buffered() > 0 { + if c.r != nil && c.r.Buffered() > 0 { _, err = buffer.ReadOnceFrom(c.r) return } @@ -70,10 +70,11 @@ func (c *BufferedConn) ReadBuffer(buffer *buf.Buffer) (err error) { } func (c *BufferedConn) ReadCached() *buf.Buffer { // call in sing/common/bufio.Copy - if c.r.Buffered() > 0 { + if c.r != nil && c.r.Buffered() > 0 { length := c.r.Buffered() b, _ := c.r.Peek(length) _, _ = c.r.Discard(length) + c.r = nil // drop bufio.Reader to let gc can clean up its internal buf return buf.As(b) } return nil @@ -84,7 +85,7 @@ func (c *BufferedConn) Upstream() any { } func (c *BufferedConn) ReaderReplaceable() bool { - if c.r.Buffered() > 0 { + if c.r != nil && c.r.Buffered() > 0 { return false } return true From 75cd72385ab67b6d60388c790e8f0ff3b539cbc4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 11 May 2023 13:47:51 +0800 Subject: [PATCH 265/530] chore: decrease direct udp read memory used for no-windows platform --- adapter/outbound/base.go | 18 ++++++++-- adapter/outbound/direct.go | 8 +---- common/net/packet.go | 68 ++++++++++++++++++++++++++++++++++++ common/net/packet_posix.go | 64 +++++++++++++++++++++++++++++++++ common/net/packet_windows.go | 15 ++++++++ constant/adapters.go | 2 +- tunnel/connection.go | 10 +++--- tunnel/statistic/tracker.go | 10 ++++++ 8 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 common/net/packet.go create mode 100644 common/net/packet_posix.go create mode 100644 common/net/packet_windows.go diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index 367638b8..e4a553b9 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -220,7 +220,7 @@ func NewConn(c net.Conn, a C.ProxyAdapter) C.Conn { } type packetConn struct { - net.PacketConn + N.EnhancePacketConn chain C.Chain adapterName string connID string @@ -242,15 +242,27 @@ func (c *packetConn) AppendToChains(a C.ProxyAdapter) { } func (c *packetConn) LocalAddr() net.Addr { - lAddr := c.PacketConn.LocalAddr() + lAddr := c.EnhancePacketConn.LocalAddr() return N.NewCustomAddr(c.adapterName, c.connID, lAddr) // make quic-go's connMultiplexer happy } +func (c *packetConn) Upstream() any { + return c.EnhancePacketConn +} + +func (c *packetConn) WriterReplaceable() bool { + return true +} + +func (c *packetConn) ReaderReplaceable() bool { + return true +} + func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn { if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn pc = N.NewDeadlinePacketConn(pc) // most conn from outbound can't handle readDeadline correctly } - return &packetConn{pc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} + return &packetConn{N.NewEnhancePacketConn(pc), []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} } func parseRemoteDestination(addr string) string { diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index eae37d7a..94b59cd0 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -3,8 +3,6 @@ package outbound import ( "context" "errors" - "net" - "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" @@ -39,11 +37,7 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, if err != nil { return nil, err } - return newPacketConn(&directPacketConn{pc}, d), nil -} - -type directPacketConn struct { - net.PacketConn + return newPacketConn(pc, d), nil } func NewDirect() *Direct { diff --git a/common/net/packet.go b/common/net/packet.go new file mode 100644 index 00000000..30f1104a --- /dev/null +++ b/common/net/packet.go @@ -0,0 +1,68 @@ +package net + +import ( + "net" + + "github.com/Dreamacro/clash/common/pool" +) + +type EnhancePacketConn interface { + net.PacketConn + WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) + Upstream() any +} + +func NewEnhancePacketConn(pc net.PacketConn) EnhancePacketConn { + if udpConn, isUDPConn := pc.(*net.UDPConn); isUDPConn { + return &enhanceUDPConn{UDPConn: udpConn} + } + return &enhancePacketConn{PacketConn: pc} +} + +type enhancePacketConn struct { + net.PacketConn +} + +func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + return waitReadFrom(c.PacketConn) +} + +func (c *enhancePacketConn) Upstream() any { + return c.PacketConn +} + +func (c *enhancePacketConn) WriterReplaceable() bool { + return true +} + +func (c *enhancePacketConn) ReaderReplaceable() bool { + return true +} + +func (c *enhanceUDPConn) Upstream() any { + return c.UDPConn +} + +func (c *enhanceUDPConn) WriterReplaceable() bool { + return true +} + +func (c *enhanceUDPConn) ReaderReplaceable() bool { + return true +} + +func waitReadFrom(pc net.PacketConn) (data []byte, put func(), addr net.Addr, err error) { + readBuf := pool.Get(pool.UDPBufferSize) + put = func() { + _ = pool.Put(readBuf) + } + var readN int + readN, addr, err = pc.ReadFrom(readBuf) + if readN > 0 { + data = readBuf[:readN] + } else { + put() + put = nil + } + return +} diff --git a/common/net/packet_posix.go b/common/net/packet_posix.go new file mode 100644 index 00000000..18c72a1c --- /dev/null +++ b/common/net/packet_posix.go @@ -0,0 +1,64 @@ +//go:build !windows + +package net + +import ( + "io" + "net" + "strconv" + "syscall" + + "github.com/Dreamacro/clash/common/pool" +) + +type enhanceUDPConn struct { + *net.UDPConn + rawConn syscall.RawConn +} + +func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + if c.rawConn == nil { + c.rawConn, _ = c.UDPConn.SyscallConn() + } + var readErr error + err = c.rawConn.Read(func(fd uintptr) (done bool) { + readBuf := pool.Get(pool.UDPBufferSize) + put = func() { + _ = pool.Put(readBuf) + } + var readFrom syscall.Sockaddr + var readN int + readN, _, _, readFrom, readErr = syscall.Recvmsg(int(fd), readBuf, nil, 0) + if readN > 0 { + data = readBuf[:readN] + } else { + put() + put = nil + } + if readErr == syscall.EAGAIN { + return false + } + if readFrom != nil { + switch from := readFrom.(type) { + case *syscall.SockaddrInet4: + ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 4 bytes + addr = &net.UDPAddr{IP: ip[:], Port: from.Port} + case *syscall.SockaddrInet6: + ip := from.Addr // copy from.Addr; ip escapes, so this line allocates 16 bytes + addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: strconv.FormatInt(int64(from.ZoneId), 10)} + } + } + if readN == 0 { + readErr = io.EOF + } + return true + }) + if err != nil { + return + } + if readErr != nil { + err = readErr + return + } + return +} diff --git a/common/net/packet_windows.go b/common/net/packet_windows.go new file mode 100644 index 00000000..a5bf75aa --- /dev/null +++ b/common/net/packet_windows.go @@ -0,0 +1,15 @@ +//go:build windows + +package net + +import ( + "net" +) + +type enhanceUDPConn struct { + *net.UDPConn +} + +func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + return waitReadFrom(c.UDPConn) +} diff --git a/constant/adapters.go b/constant/adapters.go index 2a2c68c1..73877dec 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -81,7 +81,7 @@ type Conn interface { } type PacketConn interface { - net.PacketConn + N.EnhancePacketConn Connection // Deprecate WriteWithMetadata because of remote resolve DNS cause TURN failed // WriteWithMetadata(p []byte, metadata *Metadata) (n int, err error) diff --git a/tunnel/connection.go b/tunnel/connection.go index c64a5266..c95e33f2 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -7,7 +7,6 @@ import ( "time" N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" ) @@ -27,18 +26,16 @@ func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata return nil } -func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, fAddr netip.Addr) { - buf := pool.Get(pool.UDPBufferSize) +func handleUDPToLocal(packet C.UDPPacket, pc N.EnhancePacketConn, key string, oAddr, fAddr netip.Addr) { defer func() { _ = pc.Close() closeAllLocalCoon(key) natTable.Delete(key) - _ = pool.Put(buf) }() for { _ = pc.SetReadDeadline(time.Now().Add(udpTimeout)) - n, from, err := pc.ReadFrom(buf) + data, put, from, err := pc.WaitReadFrom() if err != nil { return } @@ -54,7 +51,8 @@ func handleUDPToLocal(packet C.UDPPacket, pc net.PacketConn, key string, oAddr, } } - _, err = packet.WriteBack(buf[:n], fromUDPAddr) + _, err = packet.WriteBack(data, fromUDPAddr) + put() if err != nil { return } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 170cbc99..685b5e90 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -186,6 +186,16 @@ func (ut *udpTracker) ReadFrom(b []byte) (int, net.Addr, error) { return n, addr, err } +func (ut *udpTracker) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, addr, err = ut.PacketConn.WaitReadFrom() + download := int64(len(data)) + if ut.pushToManager { + ut.manager.PushDownloaded(download) + } + ut.DownloadTotal.Add(download) + return +} + func (ut *udpTracker) WriteTo(b []byte, addr net.Addr) (int, error) { n, err := ut.PacketConn.WriteTo(b, addr) upload := int64(n) From e404695a0de07a338161829d87262c76d4827a03 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 11 May 2023 15:34:28 +0800 Subject: [PATCH 266/530] fix: mux's udp should add write lock --- adapter/outbound/singmux.go | 2 +- adapter/outbound/vless.go | 13 +++++++------ adapter/outbound/vmess.go | 13 +------------ common/net/packet.go | 20 ++++++++++++++++++++ 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index acfdfe99..555a0ecb 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -92,7 +92,7 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, if pc == nil { return nil, E.New("packetConn is nil") } - return newPacketConn(CN.NewRefPacketConn(pc, s), s.ProxyAdapter), nil + return newPacketConn(CN.NewRefPacketConn(CN.NewThreadSafePacketConn(pc), s), s.ProxyAdapter), nil } func (s *SingMux) SupportUDP() bool { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index d7db27d5..82ecf927 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -13,6 +13,7 @@ import ( "sync" "github.com/Dreamacro/clash/common/convert" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" @@ -372,15 +373,15 @@ func (v *Vless) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada } if v.option.XUDP { - return newPacketConn(&threadSafePacketConn{ - PacketConn: vmessSing.NewXUDPConn(c, M.SocksaddrFromNet(metadata.UDPAddr())), - }, v), nil + return newPacketConn(N.NewThreadSafePacketConn( + vmessSing.NewXUDPConn(c, M.SocksaddrFromNet(metadata.UDPAddr())), + ), v), nil } else if v.option.PacketAddr { - return newPacketConn(&threadSafePacketConn{ - PacketConn: packetaddr.NewConn(&vlessPacketConn{ + return newPacketConn(N.NewThreadSafePacketConn( + packetaddr.NewConn(&vlessPacketConn{ Conn: c, rAddr: metadata.UDPAddr(), }, M.SocksaddrFromNet(metadata.UDPAddr())), - }, v), nil + ), v), nil } return newPacketConn(&vlessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil } diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 8901f3d5..91e509d7 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -379,7 +379,7 @@ func (v *Vmess) ListenPacketOnStreamConn(ctx context.Context, c net.Conn, metada } if pc, ok := c.(net.PacketConn); ok { - return newPacketConn(&threadSafePacketConn{PacketConn: pc}, v), nil + return newPacketConn(N.NewThreadSafePacketConn(pc), v), nil } return newPacketConn(&vmessPacketConn{Conn: c, rAddr: metadata.UDPAddr()}, v), nil } @@ -489,17 +489,6 @@ func NewVmess(option VmessOption) (*Vmess, error) { return v, nil } -type threadSafePacketConn struct { - net.PacketConn - access sync.Mutex -} - -func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { - c.access.Lock() - defer c.access.Unlock() - return c.PacketConn.WriteTo(b, addr) -} - type vmessPacketConn struct { net.Conn rAddr net.Addr diff --git a/common/net/packet.go b/common/net/packet.go index 30f1104a..43a2bc9c 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -2,6 +2,7 @@ package net import ( "net" + "sync" "github.com/Dreamacro/clash/common/pool" ) @@ -66,3 +67,22 @@ func waitReadFrom(pc net.PacketConn) (data []byte, put func(), addr net.Addr, er } return } + +type threadSafePacketConn struct { + net.PacketConn + access sync.Mutex +} + +func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { + c.access.Lock() + defer c.access.Unlock() + return c.PacketConn.WriteTo(b, addr) +} + +func (c *threadSafePacketConn) Upstream() any { + return c.PacketConn +} + +func NewThreadSafePacketConn(pc net.PacketConn) net.PacketConn { + return &threadSafePacketConn{PacketConn: pc} +} From 234f7dbd3b13c96918977da7c0018098d569cde5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 11 May 2023 19:01:41 +0800 Subject: [PATCH 267/530] chore: decrease shadowsocks udp read memory used for no-windows platform --- adapter/outbound/shadowsocks.go | 3 +- common/net/bind.go | 35 +++-- common/net/deadline/packet.go | 172 ++++++++++++++++++++++ common/net/deadline/pipe.go | 84 +++++++++++ common/net/packet.go | 65 +------- common/net/packet/packet.go | 70 +++++++++ common/net/{ => packet}/packet_posix.go | 2 +- common/net/{ => packet}/packet_windows.go | 2 +- common/net/sing.go | 4 - go.mod | 4 +- go.sum | 4 +- listener/sing/sing.go | 2 +- 12 files changed, 361 insertions(+), 86 deletions(-) create mode 100644 common/net/deadline/packet.go create mode 100644 common/net/deadline/pipe.go create mode 100644 common/net/packet/packet.go rename common/net/{ => packet}/packet_posix.go (98%) rename common/net/{ => packet}/packet_windows.go (93%) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 7ee9e634..44bfe64f 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -21,7 +21,6 @@ import ( restlsC "github.com/3andne/restls-client-go" "github.com/metacubex/sing-shadowsocks2" - "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/uot" ) @@ -194,7 +193,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - pc = ss.method.DialPacketConn(bufio.NewBindPacketConn(pc, addr)) + pc = ss.method.DialPacketConn(N.NewBindPacketConn(N.NewEnhancePacketConn(pc), addr)) return newPacketConn(pc, ss), nil } diff --git a/common/net/bind.go b/common/net/bind.go index 1e20a8c0..edf51ccb 100644 --- a/common/net/bind.go +++ b/common/net/bind.go @@ -3,34 +3,43 @@ package net import "net" type bindPacketConn struct { - net.PacketConn + EnhancePacketConn rAddr net.Addr } -func (wpc *bindPacketConn) Read(b []byte) (n int, err error) { - n, _, err = wpc.PacketConn.ReadFrom(b) +func (c *bindPacketConn) Read(b []byte) (n int, err error) { + n, _, err = c.EnhancePacketConn.ReadFrom(b) return n, err } -func (wpc *bindPacketConn) Write(b []byte) (n int, err error) { - return wpc.PacketConn.WriteTo(b, wpc.rAddr) +func (c *bindPacketConn) WaitRead() (data []byte, put func(), err error) { + data, put, _, err = c.EnhancePacketConn.WaitReadFrom() + return } -func (wpc *bindPacketConn) RemoteAddr() net.Addr { - return wpc.rAddr +func (c *bindPacketConn) Write(b []byte) (n int, err error) { + return c.EnhancePacketConn.WriteTo(b, c.rAddr) } -func (wpc *bindPacketConn) LocalAddr() net.Addr { - if wpc.PacketConn.LocalAddr() == nil { +func (c *bindPacketConn) RemoteAddr() net.Addr { + return c.rAddr +} + +func (c *bindPacketConn) LocalAddr() net.Addr { + if c.EnhancePacketConn.LocalAddr() == nil { return &net.UDPAddr{IP: net.IPv4zero, Port: 0} } else { - return wpc.PacketConn.LocalAddr() + return c.EnhancePacketConn.LocalAddr() } } -func NewBindPacketConn(pc net.PacketConn, rAddr net.Addr) net.Conn { +func (c *bindPacketConn) Upstream() any { + return c.EnhancePacketConn +} + +func NewBindPacketConn(pc EnhancePacketConn, rAddr net.Addr) net.Conn { return &bindPacketConn{ - PacketConn: pc, - rAddr: rAddr, + EnhancePacketConn: pc, + rAddr: rAddr, } } diff --git a/common/net/deadline/packet.go b/common/net/deadline/packet.go new file mode 100644 index 00000000..4f2e9111 --- /dev/null +++ b/common/net/deadline/packet.go @@ -0,0 +1,172 @@ +package deadline + +import ( + "net" + "os" + "time" + + "github.com/Dreamacro/clash/common/atomic" + "github.com/Dreamacro/clash/common/net/packet" +) + +type readResult struct { + data []byte + put func() + addr net.Addr + err error +} + +type PacketConn struct { + net.PacketConn + deadline atomic.TypedValue[time.Time] + pipeDeadline pipeDeadline + disablePipe atomic.Bool + inRead atomic.Bool + resultCh chan *readResult +} + +func NewPacketConn(pc net.PacketConn) net.PacketConn { + c := &PacketConn{ + PacketConn: pc, + pipeDeadline: makePipeDeadline(), + resultCh: make(chan *readResult, 1), + } + c.resultCh <- nil + if enhancePacketConn, isEnhance := pc.(packet.EnhancePacketConn); isEnhance { + return &EnhancePacketConn{ + PacketConn: c, + enhancePacketConn: enhancePacketConn, + } + } + return c +} + +func (c *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { + select { + case result := <-c.resultCh: + if result != nil { + n = copy(p, result.data) + addr = result.addr + err = result.err + c.resultCh <- nil // finish cache read + return + } else { + c.resultCh <- nil + break + } + case <-c.pipeDeadline.wait(): + return 0, nil, os.ErrDeadlineExceeded + } + + if c.disablePipe.Load() { + return c.PacketConn.ReadFrom(p) + } else if c.deadline.Load().IsZero() { + c.inRead.Store(true) + defer c.inRead.Store(false) + n, addr, err = c.PacketConn.ReadFrom(p) + return + } + + <-c.resultCh + go c.pipeReadFrom(len(p)) + + return c.ReadFrom(p) +} + +func (c *PacketConn) pipeReadFrom(size int) { + buffer := make([]byte, size) + n, addr, err := c.PacketConn.ReadFrom(buffer) + buffer = buffer[:n] + c.resultCh <- &readResult{ + data: buffer, + addr: addr, + err: err, + } +} + +func (c *PacketConn) SetReadDeadline(t time.Time) error { + if c.disablePipe.Load() { + return c.PacketConn.SetReadDeadline(t) + } else if c.inRead.Load() { + c.disablePipe.Store(true) + return c.PacketConn.SetReadDeadline(t) + } + c.deadline.Store(t) + c.pipeDeadline.set(t) + return nil +} + +func (c *PacketConn) ReaderReplaceable() bool { + select { + case result := <-c.resultCh: + c.resultCh <- result + if result != nil { + return false // cache reading + } else { + break + } + default: + return false // pipe reading + } + return c.disablePipe.Load() || c.deadline.Load().IsZero() +} + +func (c *PacketConn) WriterReplaceable() bool { + return true +} + +func (c *PacketConn) Upstream() any { + return c.PacketConn +} + +func (c *PacketConn) NeedAdditionalReadDeadline() bool { + return false +} + +type EnhancePacketConn struct { + *PacketConn + enhancePacketConn packet.EnhancePacketConn +} + +func (c *EnhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + select { + case result := <-c.resultCh: + if result != nil { + data = result.data + put = result.put + addr = result.addr + err = result.err + c.resultCh <- nil // finish cache read + return + } else { + c.resultCh <- nil + break + } + case <-c.pipeDeadline.wait(): + return nil, nil, nil, os.ErrDeadlineExceeded + } + + if c.disablePipe.Load() { + return c.enhancePacketConn.WaitReadFrom() + } else if c.deadline.Load().IsZero() { + c.inRead.Store(true) + defer c.inRead.Store(false) + data, put, addr, err = c.enhancePacketConn.WaitReadFrom() + return + } + + <-c.resultCh + go c.pipeWaitReadFrom() + + return c.WaitReadFrom() +} + +func (c *EnhancePacketConn) pipeWaitReadFrom() { + data, put, addr, err := c.enhancePacketConn.WaitReadFrom() + c.resultCh <- &readResult{ + data: data, + put: put, + addr: addr, + err: err, + } +} diff --git a/common/net/deadline/pipe.go b/common/net/deadline/pipe.go new file mode 100644 index 00000000..2cccfb42 --- /dev/null +++ b/common/net/deadline/pipe.go @@ -0,0 +1,84 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package deadline + +import ( + "sync" + "time" +) + +// pipeDeadline is an abstraction for handling timeouts. +type pipeDeadline struct { + mu sync.Mutex // Guards timer and cancel + timer *time.Timer + cancel chan struct{} // Must be non-nil +} + +func makePipeDeadline() pipeDeadline { + return pipeDeadline{cancel: make(chan struct{})} +} + +// set sets the point in time when the deadline will time out. +// A timeout event is signaled by closing the channel returned by waiter. +// Once a timeout has occurred, the deadline can be refreshed by specifying a +// t value in the future. +// +// A zero value for t prevents timeout. +func (d *pipeDeadline) set(t time.Time) { + d.mu.Lock() + defer d.mu.Unlock() + + if d.timer != nil && !d.timer.Stop() { + <-d.cancel // Wait for the timer callback to finish and close cancel + } + d.timer = nil + + // Time is zero, then there is no deadline. + closed := isClosedChan(d.cancel) + if t.IsZero() { + if closed { + d.cancel = make(chan struct{}) + } + return + } + + // Time in the future, setup a timer to cancel in the future. + if dur := time.Until(t); dur > 0 { + if closed { + d.cancel = make(chan struct{}) + } + d.timer = time.AfterFunc(dur, func() { + close(d.cancel) + }) + return + } + + // Time in the past, so close immediately. + if !closed { + close(d.cancel) + } +} + +// wait returns a channel that is closed when the deadline is exceeded. +func (d *pipeDeadline) wait() chan struct{} { + d.mu.Lock() + defer d.mu.Unlock() + return d.cancel +} + +func isClosedChan(c <-chan struct{}) bool { + select { + case <-c: + return true + default: + return false + } +} + +func makeFilledChan() chan struct{} { + ch := make(chan struct{}, 1) + ch <- struct{}{} + return ch +} diff --git a/common/net/packet.go b/common/net/packet.go index 43a2bc9c..2895b537 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -4,69 +4,14 @@ import ( "net" "sync" - "github.com/Dreamacro/clash/common/pool" + "github.com/Dreamacro/clash/common/net/deadline" + "github.com/Dreamacro/clash/common/net/packet" ) -type EnhancePacketConn interface { - net.PacketConn - WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) - Upstream() any -} +type EnhancePacketConn = packet.EnhancePacketConn -func NewEnhancePacketConn(pc net.PacketConn) EnhancePacketConn { - if udpConn, isUDPConn := pc.(*net.UDPConn); isUDPConn { - return &enhanceUDPConn{UDPConn: udpConn} - } - return &enhancePacketConn{PacketConn: pc} -} - -type enhancePacketConn struct { - net.PacketConn -} - -func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { - return waitReadFrom(c.PacketConn) -} - -func (c *enhancePacketConn) Upstream() any { - return c.PacketConn -} - -func (c *enhancePacketConn) WriterReplaceable() bool { - return true -} - -func (c *enhancePacketConn) ReaderReplaceable() bool { - return true -} - -func (c *enhanceUDPConn) Upstream() any { - return c.UDPConn -} - -func (c *enhanceUDPConn) WriterReplaceable() bool { - return true -} - -func (c *enhanceUDPConn) ReaderReplaceable() bool { - return true -} - -func waitReadFrom(pc net.PacketConn) (data []byte, put func(), addr net.Addr, err error) { - readBuf := pool.Get(pool.UDPBufferSize) - put = func() { - _ = pool.Put(readBuf) - } - var readN int - readN, addr, err = pc.ReadFrom(readBuf) - if readN > 0 { - data = readBuf[:readN] - } else { - put() - put = nil - } - return -} +var NewEnhancePacketConn = packet.NewEnhancePacketConn +var NewDeadlinePacketConn = deadline.NewPacketConn type threadSafePacketConn struct { net.PacketConn diff --git a/common/net/packet/packet.go b/common/net/packet/packet.go new file mode 100644 index 00000000..d823334e --- /dev/null +++ b/common/net/packet/packet.go @@ -0,0 +1,70 @@ +package packet + +import ( + "net" + + "github.com/Dreamacro/clash/common/pool" +) + +type EnhancePacketConn interface { + net.PacketConn + WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) +} + +func NewEnhancePacketConn(pc net.PacketConn) EnhancePacketConn { + if udpConn, isUDPConn := pc.(*net.UDPConn); isUDPConn { + return &enhanceUDPConn{UDPConn: udpConn} + } + if enhancePC, isEnhancePC := pc.(EnhancePacketConn); isEnhancePC { + return enhancePC + } + return &enhancePacketConn{PacketConn: pc} +} + +type enhancePacketConn struct { + net.PacketConn +} + +func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + return waitReadFrom(c.PacketConn) +} + +func (c *enhancePacketConn) Upstream() any { + return c.PacketConn +} + +func (c *enhancePacketConn) WriterReplaceable() bool { + return true +} + +func (c *enhancePacketConn) ReaderReplaceable() bool { + return true +} + +func (c *enhanceUDPConn) Upstream() any { + return c.UDPConn +} + +func (c *enhanceUDPConn) WriterReplaceable() bool { + return true +} + +func (c *enhanceUDPConn) ReaderReplaceable() bool { + return true +} + +func waitReadFrom(pc net.PacketConn) (data []byte, put func(), addr net.Addr, err error) { + readBuf := pool.Get(pool.UDPBufferSize) + put = func() { + _ = pool.Put(readBuf) + } + var readN int + readN, addr, err = pc.ReadFrom(readBuf) + if readN > 0 { + data = readBuf[:readN] + } else { + put() + put = nil + } + return +} diff --git a/common/net/packet_posix.go b/common/net/packet/packet_posix.go similarity index 98% rename from common/net/packet_posix.go rename to common/net/packet/packet_posix.go index 18c72a1c..3c5d23a6 100644 --- a/common/net/packet_posix.go +++ b/common/net/packet/packet_posix.go @@ -1,6 +1,6 @@ //go:build !windows -package net +package packet import ( "io" diff --git a/common/net/packet_windows.go b/common/net/packet/packet_windows.go similarity index 93% rename from common/net/packet_windows.go rename to common/net/packet/packet_windows.go index a5bf75aa..cb4c518b 100644 --- a/common/net/packet_windows.go +++ b/common/net/packet/packet_windows.go @@ -1,6 +1,6 @@ //go:build windows -package net +package packet import ( "net" diff --git a/common/net/sing.go b/common/net/sing.go index aa6f6917..c92008ba 100644 --- a/common/net/sing.go +++ b/common/net/sing.go @@ -23,10 +23,6 @@ func NewDeadlineConn(conn net.Conn) ExtendedConn { return deadline.NewFallbackConn(conn) } -func NewDeadlinePacketConn(pc net.PacketConn) network.NetPacketConn { - return deadline.NewFallbackPacketConn(bufio.NewPacketConn(pc)) -} - func NeedHandshake(conn any) bool { if earlyConn, isEarlyConn := common.Cast[network.EarlyConn](conn); isEarlyConn && earlyConn.NeedHandshake() { return true diff --git a/go.mod b/go.mod index b51e646a..ffa071ae 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c - github.com/metacubex/sing-shadowsocks2 v0.0.0-20230510002911-25e95d677383 + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511095725-1d6e98507d8c github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a github.com/miekg/dns v1.1.54 @@ -103,4 +103,4 @@ require ( 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 -) +) \ No newline at end of file diff --git a/go.sum b/go.sum index abb18231..9bad1a3a 100644 --- a/go.sum +++ b/go.sum @@ -98,8 +98,8 @@ github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 h1:E/sNW9tugF github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= 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-20230510002911-25e95d677383 h1:YdLeRuENJZ9QL58Kf/qtMp1wZv9VGQJYMqZ2WEF6/FM= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230510002911-25e95d677383/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511095725-1d6e98507d8c h1:LlKpVuMuccNe3JfKJ+G+JMxiqw4FBSVsK/jQYatSsnY= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511095725-1d6e98507d8c/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 7292df33..fe806e0f 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -106,7 +106,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. additions = append(additions, ctxAdditions...) } if deadline.NeedAdditionalReadDeadline(conn) { - conn = N.NewDeadlinePacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline + conn = deadline.NewFallbackPacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline } defer func() { _ = conn.Close() }() mutex := sync.Mutex{} From 76caab19bf1401f2eb9caa45922e155e9f3bbbed Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 11 May 2023 19:58:50 +0800 Subject: [PATCH 268/530] fix: Deadline not apply on EnhancePacketConn --- adapter/outbound/base.go | 5 +++-- common/net/deadline/packet.go | 4 ++++ common/net/packet.go | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index e4a553b9..c5901d7f 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -259,10 +259,11 @@ func (c *packetConn) ReaderReplaceable() bool { } func newPacketConn(pc net.PacketConn, a C.ProxyAdapter) C.PacketConn { + epc := N.NewEnhancePacketConn(pc) if _, ok := pc.(syscall.Conn); !ok { // exclusion system conn like *net.UDPConn - pc = N.NewDeadlinePacketConn(pc) // most conn from outbound can't handle readDeadline correctly + epc = N.NewDeadlineEnhancePacketConn(epc) // most conn from outbound can't handle readDeadline correctly } - return &packetConn{N.NewEnhancePacketConn(pc), []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} + return &packetConn{epc, []string{a.Name()}, a.Name(), utils.NewUUIDV4().String(), parseRemoteDestination(a.Addr())} } func parseRemoteDestination(addr string) string { diff --git a/common/net/deadline/packet.go b/common/net/deadline/packet.go index 4f2e9111..38b5f579 100644 --- a/common/net/deadline/packet.go +++ b/common/net/deadline/packet.go @@ -128,6 +128,10 @@ type EnhancePacketConn struct { enhancePacketConn packet.EnhancePacketConn } +func NewEnhancePacketConn(pc packet.EnhancePacketConn) packet.EnhancePacketConn { + return NewPacketConn(pc).(packet.EnhancePacketConn) +} + func (c *EnhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { select { case result := <-c.resultCh: diff --git a/common/net/packet.go b/common/net/packet.go index 2895b537..261c721c 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -12,6 +12,7 @@ type EnhancePacketConn = packet.EnhancePacketConn var NewEnhancePacketConn = packet.NewEnhancePacketConn var NewDeadlinePacketConn = deadline.NewPacketConn +var NewDeadlineEnhancePacketConn = deadline.NewEnhancePacketConn type threadSafePacketConn struct { net.PacketConn From 51e9f3598ed43164db03cfb5e8c621249407f2a6 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 11 May 2023 20:42:36 +0800 Subject: [PATCH 269/530] fix: shadowsocks rc4-md5 not working --- go.mod | 4 ++-- go.sum | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index ffa071ae..a0a19311 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c - github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511095725-1d6e98507d8c + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511124108-b20f64384bdd github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a github.com/miekg/dns v1.1.54 @@ -103,4 +103,4 @@ require ( 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 -) \ No newline at end of file +) diff --git a/go.sum b/go.sum index 9bad1a3a..53f730b8 100644 --- a/go.sum +++ b/go.sum @@ -98,8 +98,8 @@ github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 h1:E/sNW9tugF github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= 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-20230511095725-1d6e98507d8c h1:LlKpVuMuccNe3JfKJ+G+JMxiqw4FBSVsK/jQYatSsnY= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511095725-1d6e98507d8c/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511124108-b20f64384bdd h1:RXdD763CbvqaJOyFLAh6xa8xg7BZTkOJ0p8fBc7kB+w= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511124108-b20f64384bdd/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco= From 8dd7632d0a7e84c26d69a0c87e7c287b03de914d Mon Sep 17 00:00:00 2001 From: cubemaze <117334465+cubemaze@users.noreply.github.com> Date: Thu, 11 May 2023 21:24:38 +0800 Subject: [PATCH 270/530] chore: update docs --- docs/config.yaml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 8721340f..4239abcf 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -77,32 +77,32 @@ tun: # auto-detect-interface: true # 自动识别出口网卡 # auto-route: true # 配置路由表 # mtu: 9000 # 最大传输单元 - # strict_route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 - inet4_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 + # strict-route: true # 将所有连接路由到tun来防止泄漏,但你的设备将无法其他设备被访问 + inet4-route-address: # 启用 auto_route 时使用自定义路由而不是默认路由 - 0.0.0.0/1 - 128.0.0.0/1 - inet6_route_address: # 启用 auto_route 时使用自定义路由而不是默认路由 + inet6-route-address: # 启用 auto_route 时使用自定义路由而不是默认路由 - "::/1" - "8000::/1" - # endpoint_independent_nat: false # 启用独立于端点的 NAT - # include_uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route + # endpoint-independent-nat: false # 启用独立于端点的 NAT + # include-uid: # UID 规则仅在 Linux 下被支持,并且需要 auto_route # - 0 - # include_uid_range: # 限制被路由的的用户范围 + # include-uid-range: # 限制被路由的的用户范围 # - 1000-99999 - # exclude_uid: # 排除路由的的用户 + # exclude-uid: # 排除路由的的用户 #- 1000 - # exclude_uid_range: # 排除路由的的用户范围 + # exclude-uid-range: # 排除路由的的用户范围 # - 1000-99999 # Android 用户和应用规则仅在 Android 下被支持 - # 并且需要 auto_route + # 并且需要 auto-route - # include_android_user: # 限制被路由的 Android 用户 + # include-android-user: # 限制被路由的 Android 用户 # - 0 # - 10 - # include_package: # 限制被路由的 Android 应用包名 + # include-package: # 限制被路由的 Android 应用包名 # - com.android.chrome - # exclude_package: # 排除被路由的 Android 应用包名 + # exclude-package: # 排除被路由的 Android 应用包名 # - com.android.captiveportallogin #ebpf配置 From 534282839ca7cb886203807714d7427aa38128a4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 11 May 2023 21:31:29 +0800 Subject: [PATCH 271/530] chore: better tproxy error logging --- listener/tproxy/packet.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index 2a274f61..4967adc6 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -78,7 +78,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natT }() conn, err := listenLocalConn(rAddr, lAddr, in, natTable) if err != nil { - log.Errorln("listenLocalConn failed with error: %s, packet loss", err.Error()) + log.Errorln("listenLocalConn failed with error: %s, packet loss (rAddr[%T]=%s lAddr[%T]=%s)", err.Error(), rAddr, remote, lAddr, local) return nil, err } natTable.AddLocalConn(local, remote, conn) From f1be9b3f4aee53be5fe9438ed9c452cb6456e6f8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 11 May 2023 22:45:27 +0800 Subject: [PATCH 272/530] fix: tuic server return error udp address --- transport/tuic/protocol.go | 5 +++++ tunnel/connection.go | 11 +++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/transport/tuic/protocol.go b/transport/tuic/protocol.go index a460eecc..472bb980 100644 --- a/transport/tuic/protocol.go +++ b/transport/tuic/protocol.go @@ -465,6 +465,11 @@ func NewAddress(metadata *C.Metadata) Address { } 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 diff --git a/tunnel/connection.go b/tunnel/connection.go index c95e33f2..73c3e499 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -44,10 +44,13 @@ func handleUDPToLocal(packet C.UDPPacket, pc N.EnhancePacketConn, key string, oA _fromUDPAddr := *fromUDPAddr fromUDPAddr = &_fromUDPAddr // make a copy if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok { - if fAddr.IsValid() && (oAddr.Unmap() == fromAddr.Unmap()) { - fromUDPAddr.IP = fAddr.Unmap().AsSlice() - } else { - fromUDPAddr.IP = fromAddr.Unmap().AsSlice() + fromAddr = fromAddr.Unmap() + if fAddr.IsValid() && (oAddr.Unmap() == fromAddr) { + fromAddr = fAddr.Unmap() + } + fromUDPAddr.IP = fromAddr.AsSlice() + if fromAddr.Is4() { + fromUDPAddr.Zone = "" // only ipv6 can have the zone } } From a22b1cd69e37b6739512079ca517eb748bf59e63 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 12 May 2023 09:14:27 +0800 Subject: [PATCH 273/530] fix: sing-based listener panic --- adapter/outbound/shadowsocks.go | 2 +- common/net/bind.go | 4 ++-- common/net/packet.go | 12 ++++++++---- common/net/refconn.go | 23 ++++++++++++++++++++--- listener/sing/sing.go | 14 ++++++++++++-- listener/sing_shadowsocks/server.go | 7 +++++-- listener/sing_tun/dns.go | 7 +++++-- tunnel/statistic/tracker.go | 4 ++++ 8 files changed, 57 insertions(+), 16 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 44bfe64f..02e975ef 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -193,7 +193,7 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial if err != nil { return nil, err } - pc = ss.method.DialPacketConn(N.NewBindPacketConn(N.NewEnhancePacketConn(pc), addr)) + pc = ss.method.DialPacketConn(N.NewBindPacketConn(pc, addr)) return newPacketConn(pc, ss), nil } diff --git a/common/net/bind.go b/common/net/bind.go index edf51ccb..231c24c2 100644 --- a/common/net/bind.go +++ b/common/net/bind.go @@ -37,9 +37,9 @@ func (c *bindPacketConn) Upstream() any { return c.EnhancePacketConn } -func NewBindPacketConn(pc EnhancePacketConn, rAddr net.Addr) net.Conn { +func NewBindPacketConn(pc net.PacketConn, rAddr net.Addr) net.Conn { return &bindPacketConn{ - EnhancePacketConn: pc, + EnhancePacketConn: NewEnhancePacketConn(pc), rAddr: rAddr, } } diff --git a/common/net/packet.go b/common/net/packet.go index 261c721c..d01c9efe 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -15,20 +15,24 @@ var NewDeadlinePacketConn = deadline.NewPacketConn var NewDeadlineEnhancePacketConn = deadline.NewEnhancePacketConn type threadSafePacketConn struct { - net.PacketConn + EnhancePacketConn access sync.Mutex } func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { c.access.Lock() defer c.access.Unlock() - return c.PacketConn.WriteTo(b, addr) + return c.EnhancePacketConn.WriteTo(b, addr) } func (c *threadSafePacketConn) Upstream() any { - return c.PacketConn + return c.EnhancePacketConn +} + +func (c *threadSafePacketConn) ReaderReplaceable() bool { + return true } func NewThreadSafePacketConn(pc net.PacketConn) net.PacketConn { - return &threadSafePacketConn{PacketConn: pc} + return &threadSafePacketConn{EnhancePacketConn: NewEnhancePacketConn(pc)} } diff --git a/common/net/refconn.go b/common/net/refconn.go index 537cb839..0f32ebc1 100644 --- a/common/net/refconn.go +++ b/common/net/refconn.go @@ -82,10 +82,15 @@ func NewRefConn(conn net.Conn, ref any) net.Conn { } type refPacketConn struct { - pc net.PacketConn + pc EnhancePacketConn ref any } +func (pc *refPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + defer runtime.KeepAlive(pc.ref) + return pc.pc.WaitReadFrom() +} + func (pc *refPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { defer runtime.KeepAlive(pc.ref) return pc.pc.ReadFrom(p) @@ -121,6 +126,18 @@ func (pc *refPacketConn) SetWriteDeadline(t time.Time) error { return pc.pc.SetWriteDeadline(t) } -func NewRefPacketConn(pc net.PacketConn, ref any) net.PacketConn { - return &refPacketConn{pc: pc, ref: ref} +func (pc *refPacketConn) Upstream() any { + return pc.pc +} + +func (pc *refPacketConn) ReaderReplaceable() bool { // Relay() will handle reference + return true +} + +func (pc *refPacketConn) WriterReplaceable() bool { // Relay() will handle reference + return true +} + +func NewRefPacketConn(pc net.PacketConn, ref any) net.PacketConn { + return &refPacketConn{pc: NewEnhancePacketConn(pc), ref: ref} } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index fe806e0f..2a2d8474 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -58,6 +58,14 @@ func (c *waitCloseConn) Upstream() any { return c.ExtendedConn } +func (c *waitCloseConn) ReaderReplaceable() bool { + return true +} + +func (c *waitCloseConn) WriterReplaceable() bool { + return true +} + func UpstreamMetadata(metadata M.Metadata) M.Metadata { return M.Metadata{ Source: metadata.Source, @@ -116,7 +124,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() - readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) + connReader := network.UnwrapPacketReader(conn) // decrease runtime cost for bufio.CreatePacketReadWaiter for { var ( buff *buf.Buffer @@ -127,7 +135,9 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. buff = buf.NewPacket() // do not use stack buffer return buff } - if isReadWaiter { + // syscallPacketReadWaiter.WaitReadPacket will cache newBuffer function + // so create new PacketReadWaiter in each loop + if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(connReader); isReadWaiter { dest, err = readWaiter.WaitReadPacket(newBuffer) } else { dest, err = conn.ReadPacket(newBuffer()) diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 31b342e8..b35e1238 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -22,6 +22,7 @@ import ( "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing/common/network" ) type Listener struct { @@ -92,7 +93,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C go func() { conn := bufio.NewPacketConn(ul) - readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) + connReader := network.UnwrapPacketReader(conn) // decrease runtime cost for bufio.CreatePacketReadWaiter for { var ( buff *buf.Buffer @@ -103,7 +104,9 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C buff = buf.NewPacket() // do not use stack buffer return buff } - if isReadWaiter { + // syscallPacketReadWaiter.WaitReadPacket will cache newBuffer function + // so create new PacketReadWaiter in each loop + if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(connReader); isReadWaiter { dest, err = readWaiter.WaitReadPacket(newBuffer) } else { dest, err = conn.ReadPacket(newBuffer()) diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index fcf0cc9c..5ec6d96b 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -109,7 +109,8 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() - readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) + + connReader := network.UnwrapPacketReader(conn) // decrease runtime cost for bufio.CreatePacketReadWaiter for { var ( buff *buf.Buffer @@ -123,7 +124,9 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. return buff } _ = conn.SetReadDeadline(time.Now().Add(DefaultDnsReadTimeout)) - if isReadWaiter { + // syscallPacketReadWaiter.WaitReadPacket will cache newBuffer function + // so create new PacketReadWaiter in each loop + if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(connReader); isReadWaiter { dest, err = readWaiter.WaitReadPacket(newBuffer) } else { dest, err = conn.ReadPacket(newBuffer()) diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index 685b5e90..a2a921ac 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -211,6 +211,10 @@ func (ut *udpTracker) Close() error { return ut.PacketConn.Close() } +func (ut *udpTracker) Upstream() any { + return ut.PacketConn +} + func NewUDPTracker(conn C.PacketConn, manager *Manager, metadata *C.Metadata, rule C.Rule, uploadTotal int64, downloadTotal int64, pushToManager bool) *udpTracker { metadata.RemoteDst = parseRemoteDestination(nil, conn) From b6749830345bb9b6e82bf06f2099a10d05da0f53 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 12 May 2023 12:12:22 +0800 Subject: [PATCH 274/530] chore: improve read waiter interface --- go.mod | 2 +- go.sum | 4 ++-- listener/sing/sing.go | 22 +++++++++++---------- listener/sing_shadowsocks/server.go | 23 +++++++++++----------- listener/sing_tun/dns.go | 30 +++++++++++++++-------------- 5 files changed, 43 insertions(+), 38 deletions(-) diff --git a/go.mod b/go.mod index a0a19311..9b1e2dbd 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( 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.20230510160026-237a991b46d0 + github.com/sagernet/sing v0.2.5-0.20230512033628-9be7806bab51 github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e github.com/sagernet/sing-shadowtls v0.1.2-0.20230417103049-4f682e05f19b github.com/sagernet/sing-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 diff --git a/go.sum b/go.sum index 53f730b8..d38293a3 100644 --- a/go.sum +++ b/go.sum @@ -143,8 +143,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 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.20230510160026-237a991b46d0 h1:NS4U+yQ4ToyRqFvCS91BM1D6fQbriW1qvioxSj5PvI4= -github.com/sagernet/sing v0.2.5-0.20230510160026-237a991b46d0/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +github.com/sagernet/sing v0.2.5-0.20230512033628-9be7806bab51 h1:ySJuouhl890pBZly51Hkb2mbDnz+qSQCLF5j+4IFHis= +github.com/sagernet/sing v0.2.5-0.20230512033628-9be7806bab51/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-shadowtls v0.1.2-0.20230417103049-4f682e05f19b h1:ouW/6IDCrxkBe19YSbdCd7buHix7b+UZ6BM4Zz74XF4= diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 2a2d8474..9bf52e9c 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -124,21 +124,23 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. defer mutex.Unlock() conn2 = nil }() - connReader := network.UnwrapPacketReader(conn) // decrease runtime cost for bufio.CreatePacketReadWaiter + var buff *buf.Buffer + newBuffer := func() *buf.Buffer { + buff = buf.NewPacket() // do not use stack buffer + return buff + } + readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) + if isReadWaiter { + readWaiter.InitializeReadWaiter(newBuffer) + } for { var ( - buff *buf.Buffer dest M.Socksaddr err error ) - newBuffer := func() *buf.Buffer { - buff = buf.NewPacket() // do not use stack buffer - return buff - } - // syscallPacketReadWaiter.WaitReadPacket will cache newBuffer function - // so create new PacketReadWaiter in each loop - if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(connReader); isReadWaiter { - dest, err = readWaiter.WaitReadPacket(newBuffer) + buff = nil // clear last loop status, avoid repeat release + if isReadWaiter { + dest, err = readWaiter.WaitReadPacket() } else { dest, err = conn.ReadPacket(newBuffer()) } diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index b35e1238..1fa9a3ba 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -22,7 +22,6 @@ import ( "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" - "github.com/sagernet/sing/common/network" ) type Listener struct { @@ -93,21 +92,23 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C go func() { conn := bufio.NewPacketConn(ul) - connReader := network.UnwrapPacketReader(conn) // decrease runtime cost for bufio.CreatePacketReadWaiter + var buff *buf.Buffer + newBuffer := func() *buf.Buffer { + buff = buf.NewPacket() // do not use stack buffer + return buff + } + readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) + if isReadWaiter { + readWaiter.InitializeReadWaiter(newBuffer) + } for { var ( - buff *buf.Buffer dest M.Socksaddr err error ) - newBuffer := func() *buf.Buffer { - buff = buf.NewPacket() // do not use stack buffer - return buff - } - // syscallPacketReadWaiter.WaitReadPacket will cache newBuffer function - // so create new PacketReadWaiter in each loop - if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(connReader); isReadWaiter { - dest, err = readWaiter.WaitReadPacket(newBuffer) + buff = nil // clear last loop status, avoid repeat release + if isReadWaiter { + dest, err = readWaiter.WaitReadPacket() } else { dest, err = conn.ReadPacket(newBuffer()) } diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 5ec6d96b..88e3f6d6 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -110,24 +110,26 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. conn2 = nil }() - connReader := network.UnwrapPacketReader(conn) // decrease runtime cost for bufio.CreatePacketReadWaiter + var buff *buf.Buffer + newBuffer := func() *buf.Buffer { + // safe size which is 1232 from https://dnsflagday.net/2020/. + // so 2048 is enough + buff = buf.NewSize(2 * 1024) + return buff + } + readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn) + if isReadWaiter { + readWaiter.InitializeReadWaiter(newBuffer) + } for { var ( - buff *buf.Buffer dest M.Socksaddr err error ) - newBuffer := func() *buf.Buffer { - // safe size which is 1232 from https://dnsflagday.net/2020/. - // so 2048 is enough - buff = buf.NewSize(2 * 1024) - return buff - } _ = conn.SetReadDeadline(time.Now().Add(DefaultDnsReadTimeout)) - // syscallPacketReadWaiter.WaitReadPacket will cache newBuffer function - // so create new PacketReadWaiter in each loop - if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(connReader); isReadWaiter { - dest, err = readWaiter.WaitReadPacket(newBuffer) + buff = nil // clear last loop status, avoid repeat release + if isReadWaiter { + dest, err = readWaiter.WaitReadPacket() } else { dest, err = conn.ReadPacket(newBuffer()) } @@ -140,7 +142,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } return err } - go func() { + go func(buff *buf.Buffer) { ctx, cancel := context.WithTimeout(ctx, DefaultDnsRelayTimeout) defer cancel() inData := buff.Bytes() @@ -165,7 +167,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. if err != nil { return } - }() + }(buff) // catch buff at goroutine create, avoid next loop change buff } return nil } From ed174789619ecaa20838f8c91bb3573052870675 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 13 May 2023 09:38:14 +0800 Subject: [PATCH 275/530] feat: Support insecure gRPC --- adapter/outbound/vless.go | 22 +++++++++++++--------- adapter/outbound/vmess.go | 27 ++++++++++++--------------- transport/gun/gun.go | 5 ++++- 3 files changed, 29 insertions(+), 25 deletions(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 82ecf927..048350e9 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -596,15 +596,19 @@ func NewVless(option VlessOption) (*Vless, error) { Host: v.option.ServerName, ClientFingerprint: v.option.ClientFingerprint, } - tlsConfig := tlsC.GetGlobalTLSConfig(&tls.Config{ - InsecureSkipVerify: v.option.SkipCertVerify, - ServerName: v.option.ServerName, - }) - - if v.option.ServerName == "" { - host, _, _ := net.SplitHostPort(v.addr) - tlsConfig.ServerName = host - gunConfig.Host = host + if option.ServerName == "" { + gunConfig.Host = v.addr + } + var tlsConfig *tls.Config + if option.TLS { + tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{ + InsecureSkipVerify: v.option.SkipCertVerify, + ServerName: v.option.ServerName, + }) + if option.ServerName == "" { + host, _, _ := net.SplitHostPort(v.addr) + tlsConfig.ServerName = host + } } v.gunTLSConfig = tlsConfig diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 91e509d7..c0063b3e 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -413,13 +413,6 @@ func NewVmess(option VmessOption) (*Vmess, error) { option.PacketAddr = false } - switch option.Network { - case "h2", "grpc": - if !option.TLS { - option.TLS = true - } - } - v := &Vmess{ Base: &Base{ name: option.Name, @@ -464,15 +457,19 @@ func NewVmess(option VmessOption) (*Vmess, error) { Host: v.option.ServerName, ClientFingerprint: v.option.ClientFingerprint, } - tlsConfig := &tls.Config{ - InsecureSkipVerify: v.option.SkipCertVerify, - ServerName: v.option.ServerName, + if option.ServerName == "" { + gunConfig.Host = v.addr } - - if v.option.ServerName == "" { - host, _, _ := net.SplitHostPort(v.addr) - tlsConfig.ServerName = host - gunConfig.Host = host + var tlsConfig *tls.Config + if option.TLS { + tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{ + InsecureSkipVerify: v.option.SkipCertVerify, + ServerName: v.option.ServerName, + }) + if option.ServerName == "" { + host, _, _ := net.SplitHostPort(v.addr) + tlsConfig.ServerName = host + } } v.gunTLSConfig = tlsConfig diff --git a/transport/gun/gun.go b/transport/gun/gun.go index 36cf68f8..e98f7fb5 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -199,9 +199,12 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re if err != nil { return nil, err } - wrap.remoteAddr = pconn.RemoteAddr() + if tlsConfig == nil { + return pconn, nil + } + if len(Fingerprint) != 0 { if realityConfig == nil { if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { From c6fed3e97f3e86d474dd9700817082cc5bab1f22 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 14 May 2023 00:21:59 +0800 Subject: [PATCH 276/530] fix: TLS certificate pool initialize Co-authored-by: Skyxim --- component/tls/config.go | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/component/tls/config.go b/component/tls/config.go index b5b56591..6f808248 100644 --- a/component/tls/config.go +++ b/component/tls/config.go @@ -33,10 +33,22 @@ func AddCertificate(certificate string) error { } } +func initializeCertPool() { + var err error + certPool, err = x509.SystemCertPool() + if err != nil { + certPool = x509.NewCertPool() + } + for _, cert := range trustCerts { + certPool.AddCert(cert) + } +} + func ResetCertificate() { mutex.Lock() defer mutex.Unlock() trustCerts = nil + initializeCertPool() } func getCertPool() *x509.CertPool { @@ -49,12 +61,7 @@ func getCertPool() *x509.CertPool { if certPool != nil { return certPool } - certPool, err := x509.SystemCertPool() - if err == nil { - for _, cert := range trustCerts { - certPool.AddCert(cert) - } - } + initializeCertPool() } return certPool } From c7557b8e483c823f5298ef98d91cf7c29005c6c6 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 14 May 2023 12:34:47 +0800 Subject: [PATCH 277/530] feat: Updater detect and download AMD64v3 artifact Co-authored-by: Larvan2 <78135608+larvan2@users.noreply.github.com> --- hub/updater/updater.go | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 3d80707a..9762f3f3 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -17,15 +17,16 @@ import ( clashHttp "github.com/Dreamacro/clash/component/http" "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" + + "github.com/klauspost/cpuid/v2" ) // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/updater/updater.go // Updater is the Clash.Meta updater. var ( - goarch string - goos string - goarm string - gomips string + goarm string + gomips string + amd64Compatible string workDir string @@ -45,6 +46,12 @@ var ( latestVersion string ) +func init() { + if runtime.GOARCH == "amd64" && cpuid.CPU.X64Level() < 3 { + amd64Compatible = "-compatible" + } +} + type updateError struct { Message string } @@ -59,8 +66,6 @@ func Update(execPath string) (err error) { mu.Lock() defer mu.Unlock() - goos = runtime.GOOS - goarch = runtime.GOARCH latestVersion, err = getLatestVersion() if err != nil { return err @@ -128,12 +133,10 @@ func prepare(exePath string) (err error) { //log.Infoln(packageName) backupDir = filepath.Join(workDir, "meta-backup") - if goos == "windows" && goarch == "amd64" { - updateExeName = "clash.meta" + "-" + goos + "-" + goarch + "-compatible.exe" - } else if goos == "linux" && goarch == "amd64" { - updateExeName = "clash.meta" + "-" + goos + "-" + goarch + "-compatible" + if runtime.GOOS == "windows" { + updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible + ".exe" } else { - updateExeName = "clash.meta" + "-" + goos + "-" + goarch + updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible } log.Infoln("updateExeName: %s ", updateExeName) @@ -198,7 +201,7 @@ func replace() error { var err error log.Infoln("replacing: %s to %s", updateExeName, currentExeName) - if goos == "windows" { + if runtime.GOOS == "windows" { // rename fails with "File in use" error err = copyFile(updateExeName, currentExeName) } else { @@ -430,17 +433,15 @@ func getLatestVersion() (version string, err error) { func updateDownloadURL() { var middle string - if goarch == "arm" && goarm != "" { - middle = fmt.Sprintf("-%s-%sv%s-%s", goos, goarch, goarm, latestVersion) - } else if isMIPS(goarch) && gomips != "" { - middle = fmt.Sprintf("-%s-%s-%s-%s", goos, goarch, gomips, latestVersion) - } else if goarch == "amd64" && (goos == "windows" || goos == "linux") { - middle = fmt.Sprintf("-%s-%s-compatible-%s", goos, goarch, latestVersion) + if runtime.GOARCH == "arm" && goarm != "" { + middle = fmt.Sprintf("-%s-%sv%s-%s", runtime.GOOS, runtime.GOARCH, goarm, latestVersion) + } else if isMIPS(runtime.GOARCH) && gomips != "" { + middle = fmt.Sprintf("-%s-%s-%s-%s", runtime.GOOS, runtime.GOARCH, gomips, latestVersion) } else { - middle = fmt.Sprintf("-%s-%s-%s", goos, goarch, latestVersion) + middle = fmt.Sprintf("-%s-%s%s-%s", runtime.GOOS, runtime.GOARCH, amd64Compatible, latestVersion) } - if goos == "windows" { + if runtime.GOOS == "windows" { middle += ".zip" } else { middle += ".gz" From 872a28a5eb4a4593d2f3f11db63aff04abfb4744 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sun, 14 May 2023 13:43:25 +0800 Subject: [PATCH 278/530] Fix: deprecated action commands (#556) Co-authored-by: 8Mi_Yile --- .github/workflows/build.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ccbe3dc6..ecc9c8a5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -126,7 +126,7 @@ jobs: shell: bash - name: Setup Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: "1.20" check-latest: true @@ -254,7 +254,6 @@ jobs: uses: softprops/action-gh-release@v1 if: ${{ success() }} with: - tag: ${{ github.ref_name }} tag_name: Prerelease-${{ github.ref_name }} files: | bin/* @@ -281,7 +280,6 @@ jobs: uses: softprops/action-gh-release@v1 if: ${{ success() }} with: - tag: ${{ github.ref_name }} tag_name: ${{ github.ref_name }} files: bin/* generate_release_notes: true @@ -306,10 +304,10 @@ jobs: working-directory: bin - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v2 - name: Setup Docker buildx - uses: docker/setup-buildx-action@v1 + uses: docker/setup-buildx-action@v2 with: version: latest @@ -317,7 +315,7 @@ jobs: # https://github.com/docker/metadata-action - name: Extract Docker metadata id: meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v4 with: images: ${{ env.REGISTRY }}/${{ secrets.DOCKERHUB_ACCOUNT }}/${{secrets.DOCKERHUB_REPO}} - name: Show files @@ -326,7 +324,7 @@ jobs: ls bin/ - name: Log into registry if: github.event_name != 'pull_request' - uses: docker/login-action@v1 + uses: docker/login-action@v2 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.DOCKER_HUB_USER }} @@ -336,7 +334,7 @@ jobs: # https://github.com/docker/build-push-action - name: Build and push Docker image id: build-and-push - uses: docker/build-push-action@v2 + uses: docker/build-push-action@v4 with: context: . file: ./Dockerfile From 1a9104c003707e23dc2612f23a2ef73792a97b77 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 15 May 2023 19:06:58 +0800 Subject: [PATCH 279/530] fix: UDP packet should not return io.EOF --- common/net/packet/packet_posix.go | 9 +++++---- go.mod | 2 +- go.sum | 4 ++-- tunnel/connection.go | 4 +++- 4 files changed, 11 insertions(+), 8 deletions(-) diff --git a/common/net/packet/packet_posix.go b/common/net/packet/packet_posix.go index 3c5d23a6..2861482f 100644 --- a/common/net/packet/packet_posix.go +++ b/common/net/packet/packet_posix.go @@ -3,7 +3,6 @@ package packet import ( - "io" "net" "strconv" "syscall" @@ -34,6 +33,7 @@ func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, } else { put() put = nil + data = nil } if readErr == syscall.EAGAIN { return false @@ -48,9 +48,10 @@ func (c *enhanceUDPConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, addr = &net.UDPAddr{IP: ip[:], Port: from.Port, Zone: strconv.FormatInt(int64(from.ZoneId), 10)} } } - if readN == 0 { - readErr = io.EOF - } + // udp should not convert readN == 0 to io.EOF + //if readN == 0 { + // readErr = io.EOF + //} return true }) if err != nil { diff --git a/go.mod b/go.mod index 9b1e2dbd..3ecee7a1 100644 --- a/go.mod +++ b/go.mod @@ -21,7 +21,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c - github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511124108-b20f64384bdd + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230515071211-0c3604faef69 github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a github.com/miekg/dns v1.1.54 diff --git a/go.sum b/go.sum index d38293a3..80d18133 100644 --- a/go.sum +++ b/go.sum @@ -98,8 +98,8 @@ github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 h1:E/sNW9tugF github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= 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-20230511124108-b20f64384bdd h1:RXdD763CbvqaJOyFLAh6xa8xg7BZTkOJ0p8fBc7kB+w= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230511124108-b20f64384bdd/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230515071211-0c3604faef69 h1:6mwe6TyQUqjpqu8QwRlY5xR5VjENzXtM3LVRhjq00nw= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230515071211-0c3604faef69/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco= diff --git a/tunnel/connection.go b/tunnel/connection.go index 73c3e499..321c7d06 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -55,7 +55,9 @@ func handleUDPToLocal(packet C.UDPPacket, pc N.EnhancePacketConn, key string, oA } _, err = packet.WriteBack(data, fromUDPAddr) - put() + if put != nil { + put() + } if err != nil { return } From 8b631f11b86994c370ed5e35d14d2882ae21f9e7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 15 May 2023 22:45:08 +0800 Subject: [PATCH 280/530] chore: better sing's udp api support --- common/net/packet/packet.go | 3 ++ common/net/packet/packet_sing.go | 74 ++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 common/net/packet/packet_sing.go diff --git a/common/net/packet/packet.go b/common/net/packet/packet.go index d823334e..6329803b 100644 --- a/common/net/packet/packet.go +++ b/common/net/packet/packet.go @@ -18,6 +18,9 @@ func NewEnhancePacketConn(pc net.PacketConn) EnhancePacketConn { if enhancePC, isEnhancePC := pc.(EnhancePacketConn); isEnhancePC { return enhancePC } + if singPC, isSingPC := pc.(SingPacketConn); isSingPC { + return newEnhanceSingPacketConn(singPC) + } return &enhancePacketConn{PacketConn: pc} } diff --git a/common/net/packet/packet_sing.go b/common/net/packet/packet_sing.go new file mode 100644 index 00000000..9be1a4a1 --- /dev/null +++ b/common/net/packet/packet_sing.go @@ -0,0 +1,74 @@ +package packet + +import ( + "net" + + "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type SingPacketConn = N.NetPacketConn + +type enhanceSingPacketConn struct { + N.NetPacketConn + readWaiter N.PacketReadWaiter +} + +func (c *enhanceSingPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + var buff *buf.Buffer + var dest M.Socksaddr + newBuffer := func() *buf.Buffer { + buff = buf.NewPacket() // do not use stack buffer + return buff + } + if c.readWaiter != nil { + c.readWaiter.InitializeReadWaiter(newBuffer) + defer c.readWaiter.InitializeReadWaiter(nil) + dest, err = c.readWaiter.WaitReadPacket() + } else { + dest, err = c.NetPacketConn.ReadPacket(newBuffer()) + } + if dest.IsFqdn() { + addr = dest + } else { + addr = dest.UDPAddr() + } + if err != nil { + if buff != nil { + buff.Release() + } + return + } + if buff == nil { + return + } + if buff.IsEmpty() { + buff.Release() + return + } + data = buff.Bytes() + put = buff.Release + return +} + +func (c *enhanceSingPacketConn) Upstream() any { + return c.NetPacketConn +} + +func (c *enhanceSingPacketConn) WriterReplaceable() bool { + return true +} + +func (c *enhanceSingPacketConn) ReaderReplaceable() bool { + return true +} + +func newEnhanceSingPacketConn(conn N.NetPacketConn) *enhanceSingPacketConn { + epc := &enhanceSingPacketConn{NetPacketConn: conn} + if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn); isReadWaiter { + epc.readWaiter = readWaiter + } + return epc +} From e552b5475fef42f12ce23db9b5ae76fd110b6e6c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 16 May 2023 14:55:50 +0800 Subject: [PATCH 281/530] fix: tfoConn panic --- component/dialer/tfo.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/component/dialer/tfo.go b/component/dialer/tfo.go index 09d5cced..4863d6ae 100644 --- a/component/dialer/tfo.go +++ b/component/dialer/tfo.go @@ -18,10 +18,11 @@ type tfoConn struct { } func (c *tfoConn) Dial(earlyData []byte) (err error) { - c.Conn, err = c.dialFn(c.ctx, earlyData) + conn, err := c.dialFn(c.ctx, earlyData) if err != nil { return } + c.Conn = conn c.dialed <- true return err } From 6b1a4385b298251099f25189833234bbd5feb65f Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 17 May 2023 00:17:23 +0800 Subject: [PATCH 282/530] chore: better updater --- hub/route/upgrade.go | 3 ++- hub/updater/updater.go | 30 +++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index 0a7c54f9..a58f224c 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -30,8 +30,9 @@ func upgrade(w http.ResponseWriter, r *http.Request) { err = updater.Update(execPath) if err != nil { + log.Warnln("%s", err) render.Status(r, http.StatusInternalServerError) - render.JSON(w, r, newError(fmt.Sprintf("Upgrade: %s", err))) + render.JSON(w, r, newError(fmt.Sprintf("%s", err))) return } diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 9762f3f3..90b14c27 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -8,6 +8,7 @@ import ( "io" "net/http" "os" + "os/exec" "path/filepath" "runtime" "strings" @@ -74,7 +75,7 @@ func Update(execPath string) (err error) { log.Infoln("current version %s, latest version %s", constant.Version, latestVersion) if latestVersion == constant.Version { - err := &updateError{Message: "Already using latest version"} + err := &updateError{Message: "already using latest version"} return err } @@ -433,8 +434,12 @@ func getLatestVersion() (version string, err error) { func updateDownloadURL() { var middle string - if runtime.GOARCH == "arm" && goarm != "" { - middle = fmt.Sprintf("-%s-%sv%s-%s", runtime.GOOS, runtime.GOARCH, goarm, latestVersion) + if runtime.GOARCH == "arm" && probeGoARM() { + //-linux-armv7-alpha-e552b54.gz + middle = fmt.Sprintf("-%s-%s%s-%s", runtime.GOOS, runtime.GOARCH, goarm, latestVersion) + } else if runtime.GOARCH == "arm64" { + //-linux-arm64-alpha-e552b54.gz + middle = fmt.Sprintf("-%s-%s-%s", runtime.GOOS, runtime.GOARCH, latestVersion) } else if isMIPS(runtime.GOARCH) && gomips != "" { middle = fmt.Sprintf("-%s-%s-%s-%s", runtime.GOOS, runtime.GOARCH, gomips, latestVersion) } else { @@ -463,3 +468,22 @@ func isMIPS(arch string) (ok bool) { return false } } + +// linux only +func probeGoARM() (ok bool) { + cmd := exec.Command("cat", "/proc/cpuinfo") + output, err := cmd.Output() + if err != nil { + log.Errorln("probe goarm error:%s", err) + return false + } + cpuInfo := string(output) + if strings.Contains(cpuInfo, "vfpv3") || strings.Contains(cpuInfo, "vfpv4") { + goarm = "v7" + } else if strings.Contains(cpuInfo, "vfp") { + goarm = "v6" + } else { + goarm = "v5" + } + return true +} From 033f902ace8662e5b5da0019cefb9c739847935b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 18 May 2023 13:15:08 +0800 Subject: [PATCH 283/530] chore: more context passing in outbounds --- adapter/outbound/base.go | 4 ++-- adapter/outbound/http.go | 8 +++----- adapter/outbound/shadowsocks.go | 11 ++--------- adapter/outbound/shadowsocksr.go | 6 +++--- adapter/outbound/snell.go | 6 +++--- adapter/outbound/socks5.go | 8 +++----- adapter/outbound/trojan.go | 16 ++++++++-------- adapter/outbound/vless.go | 20 ++++++++++---------- adapter/outbound/vmess.go | 16 ++++++++-------- adapter/outbound/wireguard.go | 4 ++-- constant/adapters.go | 4 ++-- transport/trojan/trojan.go | 6 +++--- transport/v2ray-plugin/websocket.go | 5 +++-- transport/vless/xtls.go | 6 +----- transport/vmess/tls.go | 11 +---------- transport/vmess/websocket.go | 22 +++++++++++----------- 16 files changed, 65 insertions(+), 88 deletions(-) diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index c5901d7f..f2ce56c9 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -45,8 +45,8 @@ func (b *Base) Type() C.AdapterType { return b.tp } -// StreamConn implements C.ProxyAdapter -func (b *Base) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (b *Base) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { return c, C.ErrNotSupport } diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 82fff5bb..78735b2d 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -40,12 +40,10 @@ type HttpOption struct { Headers map[string]string `proxy:"headers,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (h *Http) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (h *Http) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { if h.tlsConfig != nil { cc := tls.Client(c, h.tlsConfig) - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() err := cc.HandshakeContext(ctx) c = cc if err != nil { @@ -82,7 +80,7 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad safeConnClose(c, err) }(c) - c, err = h.StreamConn(c, metadata) + c, err = h.StreamConnContext(ctx, c, metadata) if err != nil { return nil, err } diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 02e975ef..e6c74592 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -84,14 +84,7 @@ type restlsOption struct { RestlsScript string `obfs:"restls-script,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (ss *ShadowSocks) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { - // fix tls handshake not timeout - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - return ss.StreamConnContext(ctx, c, metadata) -} - +// StreamConnContext implements C.ProxyAdapter func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { useEarly := false switch ss.obfsMode { @@ -102,7 +95,7 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada c = obfs.NewHTTPObfs(c, ss.obfsOption.Host, port) case "websocket": var err error - c, err = v2rayObfs.NewV2rayObfs(c, ss.v2rayOption) + c, err = v2rayObfs.NewV2rayObfs(ctx, c, ss.v2rayOption) if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 2b94ab0c..d33d6586 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -38,8 +38,8 @@ type ShadowSocksROption struct { UDP bool `proxy:"udp,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (ssr *ShadowSocksR) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (ssr *ShadowSocksR) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { c = ssr.obfs.StreamConn(c) c = ssr.cipher.StreamConn(c) var ( @@ -83,7 +83,7 @@ func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dia safeConnClose(c, err) }(c) - c, err = ssr.StreamConn(c, metadata) + c, err = ssr.StreamConnContext(ctx, c, metadata) return NewConn(c, ssr), err } diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index 1ec0a430..fc1f4eb3 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -52,8 +52,8 @@ func streamConn(c net.Conn, option streamOption) *snell.Snell { return snell.StreamConn(c, option.psk, option.version) } -// StreamConn implements C.ProxyAdapter -func (s *Snell) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (s *Snell) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption}) if metadata.NetWork == C.UDP { err := snell.WriteUDPHeader(c, s.version) @@ -101,7 +101,7 @@ func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta safeConnClose(c, err) }(c) - c, err = s.StreamConn(c, metadata) + c, err = s.StreamConnContext(ctx, c, metadata) return NewConn(c, s), err } diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 26f5733b..9af4d0fc 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -39,12 +39,10 @@ type Socks5Option struct { Fingerprint string `proxy:"fingerprint,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (ss *Socks5) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (ss *Socks5) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { if ss.tls { cc := tls.Client(c, ss.tlsConfig) - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() err := cc.HandshakeContext(ctx) c = cc if err != nil { @@ -88,7 +86,7 @@ func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, me safeConnClose(c, err) }(c) - c, err = ss.StreamConn(c, metadata) + c, err = ss.StreamConnContext(ctx, c, metadata) if err != nil { return nil, err } diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index b9bbc33f..81fb1ceb 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -50,7 +50,7 @@ type TrojanOption struct { ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } -func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) { +func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) { if t.option.Network == "ws" { host, port, _ := net.SplitHostPort(t.addr) wsOpts := &trojan.WebsocketOption{ @@ -71,14 +71,14 @@ func (t *Trojan) plainStream(c net.Conn) (net.Conn, error) { wsOpts.Headers = header } - return t.instance.StreamWebsocketConn(c, wsOpts) + return t.instance.StreamWebsocketConn(ctx, c, wsOpts) } - return t.instance.StreamConn(c) + return t.instance.StreamConn(ctx, c) } -// StreamConn implements C.ProxyAdapter -func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (t *Trojan) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error if tlsC.HaveGlobalFingerprint() && len(t.option.ClientFingerprint) == 0 { @@ -88,7 +88,7 @@ func (t *Trojan) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) if t.transport != nil { c, err = gun.StreamGunWithConn(c, t.gunTLSConfig, t.gunConfig, t.realityConfig) } else { - c, err = t.plainStream(c) + c, err = t.plainStream(ctx, c) } if err != nil { @@ -151,7 +151,7 @@ func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, met safeConnClose(c, err) }(c) - c, err = t.StreamConn(c, metadata) + c, err = t.StreamConnContext(ctx, c, metadata) if err != nil { return nil, err } @@ -199,7 +199,7 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me safeConnClose(c, err) }(c) tcpKeepAlive(c) - c, err = t.plainStream(c) + c, err = t.plainStream(ctx, c) if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 048350e9..e3aff5fb 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -75,7 +75,7 @@ type VlessOption struct { ClientFingerprint string `proxy:"client-fingerprint,omitempty"` } -func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error if tlsC.HaveGlobalFingerprint() && len(v.option.ClientFingerprint) == 0 { @@ -129,10 +129,10 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { convert.SetUserAgent(wsOpts.Headers) } } - c, err = vmess.StreamWebsocketConn(c, wsOpts) + c, err = vmess.StreamWebsocketConn(ctx, c, wsOpts) case "http": // readability first, so just copy default TLS logic - c, err = v.streamTLSOrXTLSConn(c, false) + c, err = v.streamTLSOrXTLSConn(ctx, c, false) if err != nil { return nil, err } @@ -147,7 +147,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { c = vmess.StreamHTTPConn(c, httpOpts) case "h2": - c, err = v.streamTLSOrXTLSConn(c, true) + c, err = v.streamTLSOrXTLSConn(ctx, c, true) if err != nil { return nil, err } @@ -163,7 +163,7 @@ func (v *Vless) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { default: // default tcp network // handle TLS And XTLS - c, err = v.streamTLSOrXTLSConn(c, false) + c, err = v.streamTLSOrXTLSConn(ctx, c, false) } if err != nil { @@ -201,7 +201,7 @@ func (v *Vless) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err return } -func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) { +func (v *Vless) streamTLSOrXTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (net.Conn, error) { host, _, _ := net.SplitHostPort(v.addr) if v.isLegacyXTLSEnabled() && !isH2 { @@ -215,7 +215,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) xtlsOpts.Host = v.option.ServerName } - return vless.StreamXTLSConn(conn, &xtlsOpts) + return vless.StreamXTLSConn(ctx, conn, &xtlsOpts) } else if v.option.TLS { tlsOpts := vmess.TLSConfig{ @@ -234,7 +234,7 @@ func (v *Vless) streamTLSOrXTLSConn(conn net.Conn, isH2 bool) (net.Conn, error) tlsOpts.Host = v.option.ServerName } - return vmess.StreamTLSConn(conn, &tlsOpts) + return vmess.StreamTLSConn(ctx, conn, &tlsOpts) } return conn, nil @@ -283,7 +283,7 @@ func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta safeConnClose(c, err) }(c) - c, err = v.StreamConn(c, metadata) + c, err = v.StreamConnContext(ctx, c, metadata) if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } @@ -348,7 +348,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met safeConnClose(c, err) }(c) - c, err = v.StreamConn(c, metadata) + c, err = v.StreamConnContext(ctx, c, metadata) if err != nil { return nil, fmt.Errorf("new vless client error: %v", err) } diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index c0063b3e..058ce49d 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -89,8 +89,8 @@ type WSOptions struct { EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"` } -// StreamConn implements C.ProxyAdapter -func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +// StreamConnContext implements C.ProxyAdapter +func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { var err error if tlsC.HaveGlobalFingerprint() && (len(v.option.ClientFingerprint) == 0) { @@ -138,7 +138,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { wsOpts.TLSConfig.ServerName = host } } - c, err = clashVMess.StreamWebsocketConn(c, wsOpts) + c, err = clashVMess.StreamWebsocketConn(ctx, c, wsOpts) case "http": // readability first, so just copy default TLS logic if v.option.TLS { @@ -153,7 +153,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { if v.option.ServerName != "" { tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(c, tlsOpts) + c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts) if err != nil { return nil, err } @@ -182,7 +182,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(c, &tlsOpts) + c, err = clashVMess.StreamTLSConn(ctx, c, &tlsOpts) if err != nil { return nil, err } @@ -210,7 +210,7 @@ func (v *Vmess) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(c, tlsOpts) + c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts) } } @@ -294,7 +294,7 @@ func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta safeConnClose(c, err) }(c) - c, err = v.StreamConn(c, metadata) + c, err = v.StreamConnContext(ctx, c, metadata) return NewConn(c, v), err } @@ -355,7 +355,7 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met safeConnClose(c, err) }(c) - c, err = v.StreamConn(c, metadata) + c, err = v.StreamConnContext(ctx, c, metadata) if err != nil { return nil, fmt.Errorf("new vmess client error: %v", err) } diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 67cd9092..38b5aa02 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -499,9 +499,9 @@ func (r *refProxyAdapter) MarshalJSON() ([]byte, error) { return nil, C.ErrNotSupport } -func (r *refProxyAdapter) StreamConn(c net.Conn, metadata *C.Metadata) (net.Conn, error) { +func (r *refProxyAdapter) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.Metadata) (net.Conn, error) { if r.proxyAdapter != nil { - return r.proxyAdapter.StreamConn(c, metadata) + return r.proxyAdapter.StreamConnContext(ctx, c, metadata) } return nil, C.ErrNotSupport } diff --git a/constant/adapters.go b/constant/adapters.go index 73877dec..12579685 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -106,11 +106,11 @@ type ProxyAdapter interface { // // Examples: // conn, _ := net.DialContext(context.Background(), "tcp", "host:port") - // conn, _ = adapter.StreamConn(conn, metadata) + // conn, _ = adapter.StreamConnContext(context.Background(), conn, metadata) // // It returns a C.Conn with protocol which start with // a new session (if any) - StreamConn(c net.Conn, metadata *Metadata) (net.Conn, error) + StreamConnContext(ctx context.Context, c net.Conn, metadata *Metadata) (net.Conn, error) // DialContext return a C.Conn with protocol which // contains multiplexing-related reuse logic (if any) diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 8eae8237..8b4146c6 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -70,7 +70,7 @@ type Trojan struct { hexPassword []byte } -func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { +func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error) { alpn := defaultALPN if len(t.option.ALPN) != 0 { alpn = t.option.ALPN @@ -149,7 +149,7 @@ func (t *Trojan) StreamConn(conn net.Conn) (net.Conn, error) { } } -func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) { +func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptions *WebsocketOption) (net.Conn, error) { alpn := defaultWebsocketALPN if len(t.option.ALPN) != 0 { alpn = t.option.ALPN @@ -162,7 +162,7 @@ func (t *Trojan) StreamWebsocketConn(conn net.Conn, wsOptions *WebsocketOption) ServerName: t.option.ServerName, } - return vmess.StreamWebsocketConn(conn, &vmess.WebsocketConfig{ + return vmess.StreamWebsocketConn(ctx, conn, &vmess.WebsocketConfig{ Host: wsOptions.Host, Port: wsOptions.Port, Path: wsOptions.Path, diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 7c2c8a88..25483670 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -1,6 +1,7 @@ package obfs import ( + "context" "crypto/tls" "net" "net/http" @@ -22,7 +23,7 @@ type Option struct { } // NewV2rayObfs return a HTTPObfs -func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) { +func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn, error) { header := http.Header{} for k, v := range option.Headers { header.Add(k, v) @@ -57,7 +58,7 @@ func NewV2rayObfs(conn net.Conn, option *Option) (net.Conn, error) { } var err error - conn, err = vmess.StreamWebsocketConn(conn, config) + conn, err = vmess.StreamWebsocketConn(ctx, conn, config) if err != nil { return nil, err } diff --git a/transport/vless/xtls.go b/transport/vless/xtls.go index 3a319568..09929fc3 100644 --- a/transport/vless/xtls.go +++ b/transport/vless/xtls.go @@ -6,7 +6,6 @@ import ( "net" tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" xtls "github.com/xtls/go" ) @@ -21,7 +20,7 @@ type XTLSConfig struct { NextProtos []string } -func StreamXTLSConn(conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { +func StreamXTLSConn(ctx context.Context, conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { xtlsConfig := &xtls.Config{ ServerName: cfg.Host, InsecureSkipVerify: cfg.SkipCertVerify, @@ -38,9 +37,6 @@ func StreamXTLSConn(conn net.Conn, cfg *XTLSConfig) (net.Conn, error) { xtlsConn := xtls.Client(conn, xtlsConfig) - // fix xtls handshake not timeout - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() err := xtlsConn.HandshakeContext(ctx) return xtlsConn, err } diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index f020d273..54813029 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -7,7 +7,6 @@ import ( "net" tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" ) type TLSConfig struct { @@ -19,7 +18,7 @@ type TLSConfig struct { Reality *tlsC.RealityConfig } -func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { +func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn, error) { tlsConfig := &tls.Config{ ServerName: cfg.Host, InsecureSkipVerify: cfg.SkipCertVerify, @@ -39,15 +38,10 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { if cfg.Reality == nil { utlsConn, valid := GetUTLSConn(conn, cfg.ClientFingerprint, tlsConfig) if valid { - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - 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, cfg.ClientFingerprint, tlsConfig, cfg.Reality) } } @@ -57,9 +51,6 @@ func StreamTLSConn(conn net.Conn, cfg *TLSConfig) (net.Conn, error) { tlsConn := tls.Client(conn, tlsConfig) - ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) - defer cancel() - err := tlsConn.HandshakeContext(ctx) return tlsConn, err } diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index e7335d84..a4ce99a9 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -194,17 +194,17 @@ func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error { earlyDataBuf := bytes.NewBuffer(earlyData) if _, err := base64EarlyDataEncoder.Write(earlyDataBuf.Next(wsedc.config.MaxEarlyData)); err != nil { - return errors.New("failed to encode early data: " + err.Error()) + return fmt.Errorf("failed to encode early data: %w", err) } if errc := base64EarlyDataEncoder.Close(); errc != nil { - return errors.New("failed to encode early data tail: " + errc.Error()) + return fmt.Errorf("failed to encode early data tail: %w", errc) } var err error - if wsedc.Conn, err = streamWebsocketConn(wsedc.underlay, wsedc.config, base64DataBuf); err != nil { + if wsedc.Conn, err = streamWebsocketConn(wsedc.ctx, wsedc.underlay, wsedc.config, base64DataBuf); err != nil { wsedc.Close() - return errors.New("failed to dial WebSocket: " + err.Error()) + return fmt.Errorf("failed to dial WebSocket: %w", err) } wsedc.dialed <- true @@ -340,7 +340,7 @@ func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Co return N.NewDeadlineConn(conn), nil } -func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { +func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { dialer := &websocket.Dialer{ NetDial: func(network, addr string) (net.Conn, error) { @@ -396,13 +396,13 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf } } - wsConn, resp, err := dialer.Dial(uri.String(), headers) + wsConn, resp, err := dialer.DialContext(ctx, uri.String(), headers) if err != nil { - reason := err.Error() + reason := err if resp != nil { - reason = resp.Status + reason = errors.New(resp.Status) } - return nil, fmt.Errorf("dial %s error: %s", uri.Host, reason) + return nil, fmt.Errorf("dial %s error: %w", uri.Host, reason) } conn = &websocketConn{ @@ -417,7 +417,7 @@ func streamWebsocketConn(conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buf return N.NewDeadlineConn(conn), nil } -func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) { +func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig) (net.Conn, error) { if u, err := url.Parse(c.Path); err == nil { if q := u.Query(); q.Get("ed") != "" { if ed, err := strconv.Atoi(q.Get("ed")); err == nil { @@ -434,5 +434,5 @@ func StreamWebsocketConn(conn net.Conn, c *WebsocketConfig) (net.Conn, error) { return streamWebsocketWithEarlyDataConn(conn, c) } - return streamWebsocketConn(conn, c, nil) + return streamWebsocketConn(ctx, conn, c, nil) } From 6e0c3a368f94efc1535f2f08a78e0cc5e927722a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 19 May 2023 11:08:14 +0800 Subject: [PATCH 284/530] chore: upgrade dependencies --- go.mod | 8 ++++---- go.sum | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/go.mod b/go.mod index 3ecee7a1..a55cc3d8 100644 --- a/go.mod +++ b/go.mod @@ -17,11 +17,12 @@ require ( github.com/hashicorp/golang-lru v0.5.4 github.com/insomniacslk/dhcp v0.0.0-20230407062729-974c6f05fe16 github.com/jpillora/backoff v1.0.0 + 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/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c - github.com/metacubex/sing-shadowsocks2 v0.0.0-20230515071211-0c3604faef69 + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230519030442-556ef530768f github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a github.com/miekg/dns v1.1.54 @@ -29,8 +30,8 @@ require ( 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.20230512033628-9be7806bab51 - github.com/sagernet/sing-mux v0.0.0-20230427141602-9836fc9b052e + github.com/sagernet/sing v0.2.5-0.20230519030052-49166ac42700 + 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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 @@ -74,7 +75,6 @@ require ( github.com/hashicorp/yamux v0.1.1 // indirect github.com/josharian/native v1.1.0 // indirect github.com/klauspost/compress v1.15.15 // indirect - github.com/klauspost/cpuid/v2 v2.0.12 // 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 diff --git a/go.sum b/go.sum index 80d18133..4a7601b8 100644 --- a/go.sum +++ b/go.sum @@ -98,8 +98,8 @@ github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 h1:E/sNW9tugF github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58/go.mod h1:9nOiGX6kqV3+ZbkDKdTNzdFD726QQHPH6WDb36jUSpA= 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-20230515071211-0c3604faef69 h1:6mwe6TyQUqjpqu8QwRlY5xR5VjENzXtM3LVRhjq00nw= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230515071211-0c3604faef69/go.mod h1:r+JnKYxqLJIkRhpT9xb3b11icXsvM6yVjCxr2Smp1Og= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230519030442-556ef530768f h1:aWgVMoAm5V2Ur9key6L//mUSBrVMl/zw/4GDG4ZjyZI= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230519030442-556ef530768f/go.mod h1:jVDD4N22bDPPKA73NvB7aqdlLWiAwv8D+jx7HwhcWak= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco= @@ -143,10 +143,10 @@ 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.20230512033628-9be7806bab51 h1:ySJuouhl890pBZly51Hkb2mbDnz+qSQCLF5j+4IFHis= -github.com/sagernet/sing v0.2.5-0.20230512033628-9be7806bab51/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 v0.2.5-0.20230519030052-49166ac42700 h1:NTiK4CtFIzD+OZkjR2/jP8IZJ/S8gKhiOoeU2ycXKDg= +github.com/sagernet/sing v0.2.5-0.20230519030052-49166ac42700/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.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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 h1:BHOnxrbC929JonuKqFdJ7ZbDp7zs4oTlH5KFvKtWu9U= From 89ae640487f62981bdd6de3d8e5c5be065f54c79 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 19 May 2023 19:57:55 +0800 Subject: [PATCH 285/530] fix: ensure group not empty --- adapter/outboundgroup/groupbase.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 8e253e63..895ca421 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -130,10 +130,6 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { } } - if len(proxies) == 0 { - return append(proxies, tunnel.Proxies()["COMPATIBLE"]) - } - if len(gb.providers) > 1 && len(gb.filterRegs) > 1 { var newProxies []C.Proxy proxiesSet := map[string]struct{}{} @@ -189,6 +185,10 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { proxies = newProxies } + if len(proxies) == 0 { + return append(proxies, tunnel.Proxies()["COMPATIBLE"]) + } + return proxies } From ae8d42fb8271204a2c9ece3c1f6389d10a5728d2 Mon Sep 17 00:00:00 2001 From: 8Mi_Yile Date: Fri, 19 May 2023 21:00:00 +0800 Subject: [PATCH 286/530] Fix: update action to support Node 16 (#565) --- .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 ecc9c8a5..bbf8e721 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -223,7 +223,7 @@ jobs: working-directory: bin - name: Delete current release assets - uses: andreaswilli/delete-release-assets-action@v2.0.0 + uses: 8Mi-Tech/delete-release-assets-action@main with: github_token: ${{ secrets.GITHUB_TOKEN }} tag: Prerelease-${{ github.ref_name }} From 2b1e69153b5b15740e3aa7f47d162ce3fd41b7d5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 19 May 2023 23:29:43 +0800 Subject: [PATCH 287/530] chore: better packet deadline --- common/net/deadline/packet.go | 109 ++++++++++---------------- common/net/deadline/packet_enhance.go | 73 +++++++++++++++++ common/net/deadline/packet_sing.go | 96 +++++++++++++++++++++++ common/net/packet.go | 4 +- common/net/packet/packet.go | 6 +- common/net/packet/packet_sing.go | 5 ++ 6 files changed, 222 insertions(+), 71 deletions(-) create mode 100644 common/net/deadline/packet_enhance.go create mode 100644 common/net/deadline/packet_sing.go diff --git a/common/net/deadline/packet.go b/common/net/deadline/packet.go index 38b5f579..f68aadaf 100644 --- a/common/net/deadline/packet.go +++ b/common/net/deadline/packet.go @@ -11,12 +11,13 @@ import ( type readResult struct { data []byte - put func() addr net.Addr err error + enhanceReadResult + singReadResult } -type PacketConn struct { +type NetPacketConn struct { net.PacketConn deadline atomic.TypedValue[time.Time] pipeDeadline pipeDeadline @@ -25,23 +26,45 @@ type PacketConn struct { resultCh chan *readResult } -func NewPacketConn(pc net.PacketConn) net.PacketConn { - c := &PacketConn{ +func NewNetPacketConn(pc net.PacketConn) net.PacketConn { + npc := &NetPacketConn{ PacketConn: pc, pipeDeadline: makePipeDeadline(), resultCh: make(chan *readResult, 1), } - c.resultCh <- nil - if enhancePacketConn, isEnhance := pc.(packet.EnhancePacketConn); isEnhance { - return &EnhancePacketConn{ - PacketConn: c, - enhancePacketConn: enhancePacketConn, + npc.resultCh <- nil + if enhancePC, isEnhance := pc.(packet.EnhancePacketConn); isEnhance { + epc := &EnhancePacketConn{ + NetPacketConn: npc, + enhancePacketConn: enhancePacketConn{ + netPacketConn: npc, + enhancePacketConn: enhancePC, + }, + } + if singPC, isSingPC := pc.(packet.SingPacketConn); isSingPC { + return &EnhanceSingPacketConn{ + EnhancePacketConn: epc, + singPacketConn: singPacketConn{ + netPacketConn: npc, + singPacketConn: singPC, + }, + } + } + return epc + } + if singPC, isSingPC := pc.(packet.SingPacketConn); isSingPC { + return &SingPacketConn{ + NetPacketConn: npc, + singPacketConn: singPacketConn{ + netPacketConn: npc, + singPacketConn: singPC, + }, } } - return c + return npc } -func (c *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { +func (c *NetPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { select { case result := <-c.resultCh: if result != nil { @@ -73,7 +96,7 @@ func (c *PacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { return c.ReadFrom(p) } -func (c *PacketConn) pipeReadFrom(size int) { +func (c *NetPacketConn) pipeReadFrom(size int) { buffer := make([]byte, size) n, addr, err := c.PacketConn.ReadFrom(buffer) buffer = buffer[:n] @@ -84,7 +107,7 @@ func (c *PacketConn) pipeReadFrom(size int) { } } -func (c *PacketConn) SetReadDeadline(t time.Time) error { +func (c *NetPacketConn) SetReadDeadline(t time.Time) error { if c.disablePipe.Load() { return c.PacketConn.SetReadDeadline(t) } else if c.inRead.Load() { @@ -96,7 +119,7 @@ func (c *PacketConn) SetReadDeadline(t time.Time) error { return nil } -func (c *PacketConn) ReaderReplaceable() bool { +func (c *NetPacketConn) ReaderReplaceable() bool { select { case result := <-c.resultCh: c.resultCh <- result @@ -111,66 +134,14 @@ func (c *PacketConn) ReaderReplaceable() bool { return c.disablePipe.Load() || c.deadline.Load().IsZero() } -func (c *PacketConn) WriterReplaceable() bool { +func (c *NetPacketConn) WriterReplaceable() bool { return true } -func (c *PacketConn) Upstream() any { +func (c *NetPacketConn) Upstream() any { return c.PacketConn } -func (c *PacketConn) NeedAdditionalReadDeadline() bool { +func (c *NetPacketConn) NeedAdditionalReadDeadline() bool { return false } - -type EnhancePacketConn struct { - *PacketConn - enhancePacketConn packet.EnhancePacketConn -} - -func NewEnhancePacketConn(pc packet.EnhancePacketConn) packet.EnhancePacketConn { - return NewPacketConn(pc).(packet.EnhancePacketConn) -} - -func (c *EnhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { - select { - case result := <-c.resultCh: - if result != nil { - data = result.data - put = result.put - addr = result.addr - err = result.err - c.resultCh <- nil // finish cache read - return - } else { - c.resultCh <- nil - break - } - case <-c.pipeDeadline.wait(): - return nil, nil, nil, os.ErrDeadlineExceeded - } - - if c.disablePipe.Load() { - return c.enhancePacketConn.WaitReadFrom() - } else if c.deadline.Load().IsZero() { - c.inRead.Store(true) - defer c.inRead.Store(false) - data, put, addr, err = c.enhancePacketConn.WaitReadFrom() - return - } - - <-c.resultCh - go c.pipeWaitReadFrom() - - return c.WaitReadFrom() -} - -func (c *EnhancePacketConn) pipeWaitReadFrom() { - data, put, addr, err := c.enhancePacketConn.WaitReadFrom() - c.resultCh <- &readResult{ - data: data, - put: put, - addr: addr, - err: err, - } -} diff --git a/common/net/deadline/packet_enhance.go b/common/net/deadline/packet_enhance.go new file mode 100644 index 00000000..589e1447 --- /dev/null +++ b/common/net/deadline/packet_enhance.go @@ -0,0 +1,73 @@ +package deadline + +import ( + "net" + "os" + + "github.com/Dreamacro/clash/common/net/packet" +) + +type EnhancePacketConn struct { + *NetPacketConn + enhancePacketConn +} + +var _ packet.EnhancePacketConn = (*EnhancePacketConn)(nil) + +func NewEnhancePacketConn(pc packet.EnhancePacketConn) packet.EnhancePacketConn { + return NewNetPacketConn(pc).(packet.EnhancePacketConn) +} + +type enhanceReadResult struct { + put func() +} + +type enhancePacketConn struct { + netPacketConn *NetPacketConn + enhancePacketConn packet.EnhancePacketConn +} + +func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + select { + case result := <-c.netPacketConn.resultCh: + if result != nil { + data = result.data + put = result.put + addr = result.addr + err = result.err + c.netPacketConn.resultCh <- nil // finish cache read + return + } else { + c.netPacketConn.resultCh <- nil + break + } + case <-c.netPacketConn.pipeDeadline.wait(): + return nil, nil, nil, os.ErrDeadlineExceeded + } + + if c.netPacketConn.disablePipe.Load() { + return c.enhancePacketConn.WaitReadFrom() + } else if c.netPacketConn.deadline.Load().IsZero() { + c.netPacketConn.inRead.Store(true) + defer c.netPacketConn.inRead.Store(false) + data, put, addr, err = c.enhancePacketConn.WaitReadFrom() + return + } + + <-c.netPacketConn.resultCh + go c.pipeWaitReadFrom() + + return c.WaitReadFrom() +} + +func (c *enhancePacketConn) pipeWaitReadFrom() { + data, put, addr, err := c.enhancePacketConn.WaitReadFrom() + c.netPacketConn.resultCh <- &readResult{ + data: data, + enhanceReadResult: enhanceReadResult{ + put: put, + }, + addr: addr, + err: err, + } +} diff --git a/common/net/deadline/packet_sing.go b/common/net/deadline/packet_sing.go new file mode 100644 index 00000000..f69022ab --- /dev/null +++ b/common/net/deadline/packet_sing.go @@ -0,0 +1,96 @@ +package deadline + +import ( + "os" + + "github.com/Dreamacro/clash/common/net/packet" + "github.com/sagernet/sing/common/buf" + M "github.com/sagernet/sing/common/metadata" +) + +type SingPacketConn struct { + *NetPacketConn + singPacketConn +} + +var _ packet.SingPacketConn = (*SingPacketConn)(nil) + +func NewSingPacketConn(pc packet.SingPacketConn) packet.SingPacketConn { + return NewNetPacketConn(pc).(packet.SingPacketConn) +} + +type EnhanceSingPacketConn struct { + *EnhancePacketConn + singPacketConn +} + +func NewEnhanceSingPacketConn(pc packet.EnhanceSingPacketConn) packet.EnhanceSingPacketConn { + return NewNetPacketConn(pc).(packet.EnhanceSingPacketConn) +} + +var _ packet.EnhanceSingPacketConn = (*EnhanceSingPacketConn)(nil) + +type singReadResult struct { + buffer *buf.Buffer + destination M.Socksaddr +} + +type singPacketConn struct { + netPacketConn *NetPacketConn + singPacketConn packet.SingPacketConn +} + +func (c *singPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { + select { + case result := <-c.netPacketConn.resultCh: + if result != nil { + destination = result.destination + err = result.err + buffer.Resize(result.buffer.Start(), 0) + n := copy(buffer.FreeBytes(), result.buffer.Bytes()) + buffer.Truncate(n) + result.buffer.Advance(n) + if result.buffer.IsEmpty() { + result.buffer.Release() + } + c.netPacketConn.resultCh <- nil // finish cache read + return + } else { + c.netPacketConn.resultCh <- nil + break + } + case <-c.netPacketConn.pipeDeadline.wait(): + return M.Socksaddr{}, os.ErrDeadlineExceeded + } + + if c.netPacketConn.disablePipe.Load() { + return c.singPacketConn.ReadPacket(buffer) + } else if c.netPacketConn.deadline.Load().IsZero() { + c.netPacketConn.inRead.Store(true) + defer c.netPacketConn.inRead.Store(false) + destination, err = c.singPacketConn.ReadPacket(buffer) + return + } + + <-c.netPacketConn.resultCh + go c.pipeReadPacket(buffer.Cap(), buffer.Start()) + + return c.ReadPacket(buffer) +} + +func (c *singPacketConn) pipeReadPacket(bufLen int, bufStart int) { + buffer := buf.NewSize(bufLen) + buffer.Advance(bufStart) + destination, err := c.singPacketConn.ReadPacket(buffer) + c.netPacketConn.resultCh <- &readResult{ + singReadResult: singReadResult{ + buffer: buffer, + destination: destination, + }, + err: err, + } +} + +func (c *singPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { + return c.singPacketConn.WritePacket(buffer, destination) +} diff --git a/common/net/packet.go b/common/net/packet.go index d01c9efe..865590ce 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -11,8 +11,10 @@ import ( type EnhancePacketConn = packet.EnhancePacketConn var NewEnhancePacketConn = packet.NewEnhancePacketConn -var NewDeadlinePacketConn = deadline.NewPacketConn +var NewDeadlineNetPacketConn = deadline.NewNetPacketConn var NewDeadlineEnhancePacketConn = deadline.NewEnhancePacketConn +var NewDeadlineSingPacketConn = deadline.NewSingPacketConn +var NewDeadlineEnhanceSingPacketConn = deadline.NewEnhanceSingPacketConn type threadSafePacketConn struct { EnhancePacketConn diff --git a/common/net/packet/packet.go b/common/net/packet/packet.go index 6329803b..6c9542c1 100644 --- a/common/net/packet/packet.go +++ b/common/net/packet/packet.go @@ -6,9 +6,13 @@ import ( "github.com/Dreamacro/clash/common/pool" ) +type WaitReadFrom interface { + WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) +} + type EnhancePacketConn interface { net.PacketConn - WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) + WaitReadFrom } func NewEnhancePacketConn(pc net.PacketConn) EnhancePacketConn { diff --git a/common/net/packet/packet_sing.go b/common/net/packet/packet_sing.go index 9be1a4a1..daa352c8 100644 --- a/common/net/packet/packet_sing.go +++ b/common/net/packet/packet_sing.go @@ -11,6 +11,11 @@ import ( type SingPacketConn = N.NetPacketConn +type EnhanceSingPacketConn interface { + N.NetPacketConn + EnhancePacketConn +} + type enhanceSingPacketConn struct { N.NetPacketConn readWaiter N.PacketReadWaiter From b047ca02942c8e6d154f400331725f0ee805b43d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 20 May 2023 11:44:11 +0800 Subject: [PATCH 288/530] chore: packet deadline support CreateReadWaiter interface --- common/net/deadline/packet.go | 51 +++++----- common/net/deadline/packet_enhance.go | 56 ++++++----- common/net/deadline/packet_sing.go | 134 +++++++++++++++++++++----- 3 files changed, 171 insertions(+), 70 deletions(-) diff --git a/common/net/deadline/packet.go b/common/net/deadline/packet.go index f68aadaf..bcf2db9d 100644 --- a/common/net/deadline/packet.go +++ b/common/net/deadline/packet.go @@ -3,6 +3,7 @@ package deadline import ( "net" "os" + "runtime" "time" "github.com/Dreamacro/clash/common/atomic" @@ -13,8 +14,6 @@ type readResult struct { data []byte addr net.Addr err error - enhanceReadResult - singReadResult } type NetPacketConn struct { @@ -23,14 +22,14 @@ type NetPacketConn struct { pipeDeadline pipeDeadline disablePipe atomic.Bool inRead atomic.Bool - resultCh chan *readResult + resultCh chan any } func NewNetPacketConn(pc net.PacketConn) net.PacketConn { npc := &NetPacketConn{ PacketConn: pc, pipeDeadline: makePipeDeadline(), - resultCh: make(chan *readResult, 1), + resultCh: make(chan any, 1), } npc.resultCh <- nil if enhancePC, isEnhance := pc.(packet.EnhancePacketConn); isEnhance { @@ -65,20 +64,28 @@ func NewNetPacketConn(pc net.PacketConn) net.PacketConn { } func (c *NetPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - select { - case result := <-c.resultCh: - if result != nil { - n = copy(p, result.data) - addr = result.addr - err = result.err - c.resultCh <- nil // finish cache read - return - } else { - c.resultCh <- nil - break +FOR: + for { + select { + case result := <-c.resultCh: + if result != nil { + if result, ok := result.(*readResult); ok { + n = copy(p, result.data) + addr = result.addr + err = result.err + c.resultCh <- nil // finish cache read + return + } + c.resultCh <- result // another type of read + runtime.Gosched() // allowing other goroutines to run + continue FOR + } else { + c.resultCh <- nil + break FOR + } + case <-c.pipeDeadline.wait(): + return 0, nil, os.ErrDeadlineExceeded } - case <-c.pipeDeadline.wait(): - return 0, nil, os.ErrDeadlineExceeded } if c.disablePipe.Load() { @@ -100,11 +107,11 @@ func (c *NetPacketConn) pipeReadFrom(size int) { buffer := make([]byte, size) n, addr, err := c.PacketConn.ReadFrom(buffer) buffer = buffer[:n] - c.resultCh <- &readResult{ - data: buffer, - addr: addr, - err: err, - } + result := &readResult{} + result.data = buffer + result.addr = addr + result.err = err + c.resultCh <- result } func (c *NetPacketConn) SetReadDeadline(t time.Time) error { diff --git a/common/net/deadline/packet_enhance.go b/common/net/deadline/packet_enhance.go index 589e1447..5b7d767f 100644 --- a/common/net/deadline/packet_enhance.go +++ b/common/net/deadline/packet_enhance.go @@ -3,6 +3,7 @@ package deadline import ( "net" "os" + "runtime" "github.com/Dreamacro/clash/common/net/packet" ) @@ -19,7 +20,10 @@ func NewEnhancePacketConn(pc packet.EnhancePacketConn) packet.EnhancePacketConn } type enhanceReadResult struct { - put func() + data []byte + put func() + addr net.Addr + err error } type enhancePacketConn struct { @@ -28,21 +32,29 @@ type enhancePacketConn struct { } func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { - select { - case result := <-c.netPacketConn.resultCh: - if result != nil { - data = result.data - put = result.put - addr = result.addr - err = result.err - c.netPacketConn.resultCh <- nil // finish cache read - return - } else { - c.netPacketConn.resultCh <- nil - break +FOR: + for { + select { + case result := <-c.netPacketConn.resultCh: + if result != nil { + if result, ok := result.(*enhanceReadResult); ok { + data = result.data + put = result.put + addr = result.addr + err = result.err + c.netPacketConn.resultCh <- nil // finish cache read + return + } + c.netPacketConn.resultCh <- result // another type of read + runtime.Gosched() // allowing other goroutines to run + continue FOR + } else { + c.netPacketConn.resultCh <- nil + break FOR + } + case <-c.netPacketConn.pipeDeadline.wait(): + return nil, nil, nil, os.ErrDeadlineExceeded } - case <-c.netPacketConn.pipeDeadline.wait(): - return nil, nil, nil, os.ErrDeadlineExceeded } if c.netPacketConn.disablePipe.Load() { @@ -62,12 +74,10 @@ func (c *enhancePacketConn) WaitReadFrom() (data []byte, put func(), addr net.Ad func (c *enhancePacketConn) pipeWaitReadFrom() { data, put, addr, err := c.enhancePacketConn.WaitReadFrom() - c.netPacketConn.resultCh <- &readResult{ - data: data, - enhanceReadResult: enhanceReadResult{ - put: put, - }, - addr: addr, - err: err, - } + result := &enhanceReadResult{} + result.data = data + result.put = put + result.addr = addr + result.err = err + c.netPacketConn.resultCh <- result } diff --git a/common/net/deadline/packet_sing.go b/common/net/deadline/packet_sing.go index f69022ab..a3da34f4 100644 --- a/common/net/deadline/packet_sing.go +++ b/common/net/deadline/packet_sing.go @@ -2,10 +2,13 @@ package deadline import ( "os" + "runtime" "github.com/Dreamacro/clash/common/net/packet" "github.com/sagernet/sing/common/buf" + "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" ) type SingPacketConn struct { @@ -33,6 +36,7 @@ var _ packet.EnhanceSingPacketConn = (*EnhanceSingPacketConn)(nil) type singReadResult struct { buffer *buf.Buffer destination M.Socksaddr + err error } type singPacketConn struct { @@ -41,26 +45,34 @@ type singPacketConn struct { } func (c *singPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { - select { - case result := <-c.netPacketConn.resultCh: - if result != nil { - destination = result.destination - err = result.err - buffer.Resize(result.buffer.Start(), 0) - n := copy(buffer.FreeBytes(), result.buffer.Bytes()) - buffer.Truncate(n) - result.buffer.Advance(n) - if result.buffer.IsEmpty() { - result.buffer.Release() +FOR: + for { + select { + case result := <-c.netPacketConn.resultCh: + if result != nil { + if result, ok := result.(*singReadResult); ok { + destination = result.destination + err = result.err + buffer.Resize(result.buffer.Start(), 0) + n := copy(buffer.FreeBytes(), result.buffer.Bytes()) + buffer.Truncate(n) + result.buffer.Advance(n) + if result.buffer.IsEmpty() { + result.buffer.Release() + } + c.netPacketConn.resultCh <- nil // finish cache read + return + } + c.netPacketConn.resultCh <- result // another type of read + runtime.Gosched() // allowing other goroutines to run + continue FOR + } else { + c.netPacketConn.resultCh <- nil + break FOR } - c.netPacketConn.resultCh <- nil // finish cache read - return - } else { - c.netPacketConn.resultCh <- nil - break + case <-c.netPacketConn.pipeDeadline.wait(): + return M.Socksaddr{}, os.ErrDeadlineExceeded } - case <-c.netPacketConn.pipeDeadline.wait(): - return M.Socksaddr{}, os.ErrDeadlineExceeded } if c.netPacketConn.disablePipe.Load() { @@ -82,15 +94,87 @@ func (c *singPacketConn) pipeReadPacket(bufLen int, bufStart int) { buffer := buf.NewSize(bufLen) buffer.Advance(bufStart) destination, err := c.singPacketConn.ReadPacket(buffer) - c.netPacketConn.resultCh <- &readResult{ - singReadResult: singReadResult{ - buffer: buffer, - destination: destination, - }, - err: err, - } + result := &singReadResult{} + result.destination = destination + result.err = err + c.netPacketConn.resultCh <- result } func (c *singPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { return c.singPacketConn.WritePacket(buffer, destination) } + +func (c *singPacketConn) CreateReadWaiter() (N.PacketReadWaiter, bool) { + prw, isReadWaiter := bufio.CreatePacketReadWaiter(c.singPacketConn) + if isReadWaiter { + return &singPacketReadWaiter{ + netPacketConn: c.netPacketConn, + packetReadWaiter: prw, + }, true + } + return nil, false +} + +var _ N.PacketReadWaiter = (*singPacketReadWaiter)(nil) + +type singPacketReadWaiter struct { + netPacketConn *NetPacketConn + packetReadWaiter N.PacketReadWaiter +} + +type singWaitReadResult singReadResult + +func (c *singPacketReadWaiter) InitializeReadWaiter(newBuffer func() *buf.Buffer) { + c.packetReadWaiter.InitializeReadWaiter(newBuffer) +} + +func (c *singPacketReadWaiter) WaitReadPacket() (destination M.Socksaddr, err error) { +FOR: + for { + select { + case result := <-c.netPacketConn.resultCh: + if result != nil { + if result, ok := result.(*singWaitReadResult); ok { + destination = result.destination + err = result.err + c.netPacketConn.resultCh <- nil // finish cache read + return + } + c.netPacketConn.resultCh <- result // another type of read + runtime.Gosched() // allowing other goroutines to run + continue FOR + } else { + c.netPacketConn.resultCh <- nil + break FOR + } + case <-c.netPacketConn.pipeDeadline.wait(): + return M.Socksaddr{}, os.ErrDeadlineExceeded + } + } + + if c.netPacketConn.disablePipe.Load() { + return c.packetReadWaiter.WaitReadPacket() + } else if c.netPacketConn.deadline.Load().IsZero() { + c.netPacketConn.inRead.Store(true) + defer c.netPacketConn.inRead.Store(false) + destination, err = c.packetReadWaiter.WaitReadPacket() + return + } + + <-c.netPacketConn.resultCh + go c.pipeWaitReadPacket() + + return c.WaitReadPacket() +} + +func (c *singPacketReadWaiter) pipeWaitReadPacket() { + destination, err := c.packetReadWaiter.WaitReadPacket() + result := &singWaitReadResult{} + result.destination = destination + result.err = err + c.netPacketConn.resultCh <- result +} + +func (c *singPacketReadWaiter) Upstream() any { + return c.packetReadWaiter +} From d4e4f6d2d7939eae182680a7d83096bb0828c3f1 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 20 May 2023 16:57:42 +0800 Subject: [PATCH 289/530] chore: rebuild ref and threadSafe packetConn --- common/net/packet.go | 29 ++---------- common/net/packet/packet_sing.go | 24 +++++----- common/net/packet/ref.go | 75 ++++++++++++++++++++++++++++++++ common/net/packet/ref_sing.go | 26 +++++++++++ common/net/packet/thread.go | 36 +++++++++++++++ common/net/packet/thread_sing.go | 24 ++++++++++ common/net/refconn.go | 61 -------------------------- 7 files changed, 176 insertions(+), 99 deletions(-) create mode 100644 common/net/packet/ref.go create mode 100644 common/net/packet/ref_sing.go create mode 100644 common/net/packet/thread.go create mode 100644 common/net/packet/thread_sing.go diff --git a/common/net/packet.go b/common/net/packet.go index 865590ce..9afe86b0 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -1,9 +1,6 @@ package net import ( - "net" - "sync" - "github.com/Dreamacro/clash/common/net/deadline" "github.com/Dreamacro/clash/common/net/packet" ) @@ -11,30 +8,10 @@ import ( type EnhancePacketConn = packet.EnhancePacketConn var NewEnhancePacketConn = packet.NewEnhancePacketConn +var NewThreadSafePacketConn = packet.NewThreadSafePacketConn +var NewRefPacketConn = packet.NewRefPacketConn + var NewDeadlineNetPacketConn = deadline.NewNetPacketConn var NewDeadlineEnhancePacketConn = deadline.NewEnhancePacketConn var NewDeadlineSingPacketConn = deadline.NewSingPacketConn var NewDeadlineEnhanceSingPacketConn = deadline.NewEnhanceSingPacketConn - -type threadSafePacketConn struct { - EnhancePacketConn - access sync.Mutex -} - -func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { - c.access.Lock() - defer c.access.Unlock() - return c.EnhancePacketConn.WriteTo(b, addr) -} - -func (c *threadSafePacketConn) Upstream() any { - return c.EnhancePacketConn -} - -func (c *threadSafePacketConn) ReaderReplaceable() bool { - return true -} - -func NewThreadSafePacketConn(pc net.PacketConn) net.PacketConn { - return &threadSafePacketConn{EnhancePacketConn: NewEnhancePacketConn(pc)} -} diff --git a/common/net/packet/packet_sing.go b/common/net/packet/packet_sing.go index daa352c8..cfcf5ed0 100644 --- a/common/net/packet/packet_sing.go +++ b/common/net/packet/packet_sing.go @@ -12,13 +12,13 @@ import ( type SingPacketConn = N.NetPacketConn type EnhanceSingPacketConn interface { - N.NetPacketConn + SingPacketConn EnhancePacketConn } type enhanceSingPacketConn struct { - N.NetPacketConn - readWaiter N.PacketReadWaiter + SingPacketConn + packetReadWaiter N.PacketReadWaiter } func (c *enhanceSingPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { @@ -28,12 +28,12 @@ func (c *enhanceSingPacketConn) WaitReadFrom() (data []byte, put func(), addr ne buff = buf.NewPacket() // do not use stack buffer return buff } - if c.readWaiter != nil { - c.readWaiter.InitializeReadWaiter(newBuffer) - defer c.readWaiter.InitializeReadWaiter(nil) - dest, err = c.readWaiter.WaitReadPacket() + if c.packetReadWaiter != nil { + c.packetReadWaiter.InitializeReadWaiter(newBuffer) + defer c.packetReadWaiter.InitializeReadWaiter(nil) + dest, err = c.packetReadWaiter.WaitReadPacket() } else { - dest, err = c.NetPacketConn.ReadPacket(newBuffer()) + dest, err = c.SingPacketConn.ReadPacket(newBuffer()) } if dest.IsFqdn() { addr = dest @@ -59,7 +59,7 @@ func (c *enhanceSingPacketConn) WaitReadFrom() (data []byte, put func(), addr ne } func (c *enhanceSingPacketConn) Upstream() any { - return c.NetPacketConn + return c.SingPacketConn } func (c *enhanceSingPacketConn) WriterReplaceable() bool { @@ -70,10 +70,10 @@ func (c *enhanceSingPacketConn) ReaderReplaceable() bool { return true } -func newEnhanceSingPacketConn(conn N.NetPacketConn) *enhanceSingPacketConn { - epc := &enhanceSingPacketConn{NetPacketConn: conn} +func newEnhanceSingPacketConn(conn SingPacketConn) *enhanceSingPacketConn { + epc := &enhanceSingPacketConn{SingPacketConn: conn} if readWaiter, isReadWaiter := bufio.CreatePacketReadWaiter(conn); isReadWaiter { - epc.readWaiter = readWaiter + epc.packetReadWaiter = readWaiter } return epc } diff --git a/common/net/packet/ref.go b/common/net/packet/ref.go new file mode 100644 index 00000000..a562b2e2 --- /dev/null +++ b/common/net/packet/ref.go @@ -0,0 +1,75 @@ +package packet + +import ( + "net" + "runtime" + "time" +) + +type refPacketConn struct { + pc EnhancePacketConn + ref any +} + +func (c *refPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + defer runtime.KeepAlive(c.ref) + return c.pc.WaitReadFrom() +} + +func (c *refPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { + defer runtime.KeepAlive(c.ref) + return c.pc.ReadFrom(p) +} + +func (c *refPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { + defer runtime.KeepAlive(c.ref) + return c.pc.WriteTo(p, addr) +} + +func (c *refPacketConn) Close() error { + defer runtime.KeepAlive(c.ref) + return c.pc.Close() +} + +func (c *refPacketConn) LocalAddr() net.Addr { + defer runtime.KeepAlive(c.ref) + return c.pc.LocalAddr() +} + +func (c *refPacketConn) SetDeadline(t time.Time) error { + defer runtime.KeepAlive(c.ref) + return c.pc.SetDeadline(t) +} + +func (c *refPacketConn) SetReadDeadline(t time.Time) error { + defer runtime.KeepAlive(c.ref) + return c.pc.SetReadDeadline(t) +} + +func (c *refPacketConn) SetWriteDeadline(t time.Time) error { + defer runtime.KeepAlive(c.ref) + return c.pc.SetWriteDeadline(t) +} + +func (c *refPacketConn) Upstream() any { + return c.pc +} + +func (c *refPacketConn) ReaderReplaceable() bool { // Relay() will handle reference + return true +} + +func (c *refPacketConn) WriterReplaceable() bool { // Relay() will handle reference + return true +} + +func NewRefPacketConn(pc net.PacketConn, ref any) EnhancePacketConn { + rPC := &refPacketConn{pc: NewEnhancePacketConn(pc), ref: ref} + if singPC, isSingPC := pc.(SingPacketConn); isSingPC { + return &refSingPacketConn{ + refPacketConn: rPC, + singPacketConn: singPC, + } + } + return rPC +} diff --git a/common/net/packet/ref_sing.go b/common/net/packet/ref_sing.go new file mode 100644 index 00000000..2ca955fa --- /dev/null +++ b/common/net/packet/ref_sing.go @@ -0,0 +1,26 @@ +package packet + +import ( + "runtime" + + "github.com/sagernet/sing/common/buf" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type refSingPacketConn struct { + *refPacketConn + singPacketConn SingPacketConn +} + +var _ N.NetPacketConn = (*refSingPacketConn)(nil) + +func (c *refSingPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { + defer runtime.KeepAlive(c.ref) + return c.singPacketConn.WritePacket(buffer, destination) +} + +func (c *refSingPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { + defer runtime.KeepAlive(c.ref) + return c.singPacketConn.ReadPacket(buffer) +} diff --git a/common/net/packet/thread.go b/common/net/packet/thread.go new file mode 100644 index 00000000..14d64233 --- /dev/null +++ b/common/net/packet/thread.go @@ -0,0 +1,36 @@ +package packet + +import ( + "net" + "sync" +) + +type threadSafePacketConn struct { + EnhancePacketConn + access sync.Mutex +} + +func (c *threadSafePacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { + c.access.Lock() + defer c.access.Unlock() + return c.EnhancePacketConn.WriteTo(b, addr) +} + +func (c *threadSafePacketConn) Upstream() any { + return c.EnhancePacketConn +} + +func (c *threadSafePacketConn) ReaderReplaceable() bool { + return true +} + +func NewThreadSafePacketConn(pc net.PacketConn) EnhancePacketConn { + tsPC := &threadSafePacketConn{EnhancePacketConn: NewEnhancePacketConn(pc)} + if singPC, isSingPC := pc.(SingPacketConn); isSingPC { + return &threadSafeSingPacketConn{ + threadSafePacketConn: tsPC, + singPacketConn: singPC, + } + } + return tsPC +} diff --git a/common/net/packet/thread_sing.go b/common/net/packet/thread_sing.go new file mode 100644 index 00000000..0869a512 --- /dev/null +++ b/common/net/packet/thread_sing.go @@ -0,0 +1,24 @@ +package packet + +import ( + "github.com/sagernet/sing/common/buf" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type threadSafeSingPacketConn struct { + *threadSafePacketConn + singPacketConn SingPacketConn +} + +var _ N.NetPacketConn = (*threadSafeSingPacketConn)(nil) + +func (c *threadSafeSingPacketConn) WritePacket(buffer *buf.Buffer, destination M.Socksaddr) error { + c.access.Lock() + defer c.access.Unlock() + return c.singPacketConn.WritePacket(buffer, destination) +} + +func (c *threadSafeSingPacketConn) ReadPacket(buffer *buf.Buffer) (destination M.Socksaddr, err error) { + return c.singPacketConn.ReadPacket(buffer) +} diff --git a/common/net/refconn.go b/common/net/refconn.go index 0f32ebc1..5caaebc8 100644 --- a/common/net/refconn.go +++ b/common/net/refconn.go @@ -80,64 +80,3 @@ var _ ExtendedConn = (*refConn)(nil) func NewRefConn(conn net.Conn, ref any) net.Conn { return &refConn{conn: NewExtendedConn(conn), ref: ref} } - -type refPacketConn struct { - pc EnhancePacketConn - ref any -} - -func (pc *refPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { - defer runtime.KeepAlive(pc.ref) - return pc.pc.WaitReadFrom() -} - -func (pc *refPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - defer runtime.KeepAlive(pc.ref) - return pc.pc.ReadFrom(p) -} - -func (pc *refPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { - defer runtime.KeepAlive(pc.ref) - return pc.pc.WriteTo(p, addr) -} - -func (pc *refPacketConn) Close() error { - defer runtime.KeepAlive(pc.ref) - return pc.pc.Close() -} - -func (pc *refPacketConn) LocalAddr() net.Addr { - defer runtime.KeepAlive(pc.ref) - return pc.pc.LocalAddr() -} - -func (pc *refPacketConn) SetDeadline(t time.Time) error { - defer runtime.KeepAlive(pc.ref) - return pc.pc.SetDeadline(t) -} - -func (pc *refPacketConn) SetReadDeadline(t time.Time) error { - defer runtime.KeepAlive(pc.ref) - return pc.pc.SetReadDeadline(t) -} - -func (pc *refPacketConn) SetWriteDeadline(t time.Time) error { - defer runtime.KeepAlive(pc.ref) - return pc.pc.SetWriteDeadline(t) -} - -func (pc *refPacketConn) Upstream() any { - return pc.pc -} - -func (pc *refPacketConn) ReaderReplaceable() bool { // Relay() will handle reference - return true -} - -func (pc *refPacketConn) WriterReplaceable() bool { // Relay() will handle reference - return true -} - -func NewRefPacketConn(pc net.PacketConn, ref any) net.PacketConn { - return &refPacketConn{pc: NewEnhancePacketConn(pc), ref: ref} -} From 546b2bc24bcca696f47704c96a85dc501c57d872 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 20 May 2023 17:00:43 +0800 Subject: [PATCH 290/530] chore: Decrease UoT read memory --- go.mod | 4 ++++ go.sum | 12 ++++------- transport/trojan/trojan.go | 41 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index a55cc3d8..40a92438 100644 --- a/go.mod +++ b/go.mod @@ -104,3 +104,7 @@ require ( golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect golang.org/x/tools v0.6.0 // indirect ) + +replace github.com/sagernet/sing => github.com/h1jk/sing v0.0.0-20230519121640-6db84f45244d + +replace github.com/sagernet/sing-vmess => github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899 diff --git a/go.sum b/go.sum index 4a7601b8..0e9e38a7 100644 --- a/go.sum +++ b/go.sum @@ -65,6 +65,8 @@ 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/h1jk/sing v0.0.0-20230519121640-6db84f45244d h1:ih6tNzl1uxuuX+Naz2qAPqSS20E6jfXFmcvyDRAy8rY= +github.com/h1jk/sing v0.0.0-20230519121640-6db84f45244d/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= 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= @@ -102,6 +104,8 @@ github.com/metacubex/sing-shadowsocks2 v0.0.0-20230519030442-556ef530768f h1:aWg github.com/metacubex/sing-shadowsocks2 v0.0.0-20230519030442-556ef530768f/go.mod h1:jVDD4N22bDPPKA73NvB7aqdlLWiAwv8D+jx7HwhcWak= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= +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-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= @@ -141,16 +145,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 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.20230519030052-49166ac42700 h1:NTiK4CtFIzD+OZkjR2/jP8IZJ/S8gKhiOoeU2ycXKDg= -github.com/sagernet/sing v0.2.5-0.20230519030052-49166ac42700/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.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-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= 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= @@ -239,10 +237,8 @@ golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.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= diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 8b4146c6..90700491 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -13,6 +13,7 @@ import ( "net/http" "sync" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" @@ -20,6 +21,7 @@ import ( "github.com/Dreamacro/clash/transport/vless" "github.com/Dreamacro/clash/transport/vmess" + M "github.com/sagernet/sing/common/metadata" xtls "github.com/xtls/go" ) @@ -303,6 +305,8 @@ func New(option *Option) *Trojan { return &Trojan{option, hexSha224([]byte(option.Password))} } +var _ N.EnhancePacketConn = (*PacketConn)(nil) + type PacketConn struct { net.Conn remain int @@ -350,6 +354,43 @@ func (pc *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { return n, addr, nil } +func (pc *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + pc.mux.Lock() + defer pc.mux.Unlock() + + destination, err := M.SocksaddrSerializer.ReadAddrPort(pc.Conn) + if err != nil { + return nil, nil, nil, err + } + addr = destination.UDPAddr() + + data = pool.Get(pool.UDPBufferSize) + put = func() { + _ = pool.Put(data) + } + + _, err = io.ReadFull(pc.Conn, data[:2+2]) // u16be length + CR LF + if err != nil { + put() + return nil, nil, nil, err + } + length := binary.BigEndian.Uint16(data) + + if length > 0 { + data = data[:length] + _, err = io.ReadFull(pc.Conn, data) + if err != nil { + put() + return nil, nil, nil, err + } + } else { + put() + return nil, nil, addr, nil + } + + return +} + func hexSha224(data []byte) []byte { buf := make([]byte, 56) hash := sha256.New224() From 984bf27d9b0bd1193acc1921652e18c9e1b10aea Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 20 May 2023 18:35:04 +0800 Subject: [PATCH 291/530] chore: using internal socks5.ReadAddr0 in trojan --- listener/shadowsocks/tcp.go | 2 +- transport/socks5/socks5.go | 44 +++++++++++++++++++++++++++++++++++++ transport/trojan/trojan.go | 3 +-- 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index 6884b960..febf87c3 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -103,7 +103,7 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions conn = l.pickCipher.StreamConn(conn) conn = N.NewDeadlineConn(conn) // embed ss can't handle readDeadline correctly - target, err := socks5.ReadAddr(conn, make([]byte, socks5.MaxAddrLen)) + target, err := socks5.ReadAddr0(conn) if err != nil { _ = conn.Close() return diff --git a/transport/socks5/socks5.go b/transport/socks5/socks5.go index 7d4f11ae..6f95cce9 100644 --- a/transport/socks5/socks5.go +++ b/transport/socks5/socks5.go @@ -299,6 +299,50 @@ func ReadAddr(r io.Reader, b []byte) (Addr, error) { return nil, ErrAddressNotSupported } +func ReadAddr0(r io.Reader) (Addr, error) { + aType, err := ReadByte(r) // read 1st byte for address type + if err != nil { + return nil, err + } + + switch aType { + case AtypDomainName: + var domainLength byte + domainLength, err = ReadByte(r) // read 2nd byte for domain length + if err != nil { + return nil, err + } + b := make([]byte, 1+1+uint16(domainLength)+2) + _, err = io.ReadFull(r, b[2:]) + b[0] = aType + b[1] = domainLength + return b, err + case AtypIPv4: + var b [1 + net.IPv4len + 2]byte + _, err = io.ReadFull(r, b[1:]) + b[0] = aType + return b[:], err + case AtypIPv6: + var b [1 + net.IPv6len + 2]byte + _, err = io.ReadFull(r, b[1:]) + b[0] = aType + return b[:], err + } + + return nil, ErrAddressNotSupported +} + +func ReadByte(reader io.Reader) (byte, error) { + if br, isBr := reader.(io.ByteReader); isBr { + return br.ReadByte() + } + var b [1]byte + if _, err := io.ReadFull(reader, b[:]); err != nil { + return 0, err + } + return b[0], nil +} + // SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed. func SplitAddr(b []byte) Addr { addrLen := 1 diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 90700491..d37026c1 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -21,7 +21,6 @@ import ( "github.com/Dreamacro/clash/transport/vless" "github.com/Dreamacro/clash/transport/vmess" - M "github.com/sagernet/sing/common/metadata" xtls "github.com/xtls/go" ) @@ -358,7 +357,7 @@ func (pc *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, er pc.mux.Lock() defer pc.mux.Unlock() - destination, err := M.SocksaddrSerializer.ReadAddrPort(pc.Conn) + destination, err := socks5.ReadAddr0(pc.Conn) if err != nil { return nil, nil, nil, err } From 654e76d91e6c20b8da1bc0e44eb9e9f737b1d590 Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 26 May 2023 20:11:06 +0800 Subject: [PATCH 292/530] refactor: Move vision implementation to a new package --- transport/vless/conn.go | 305 +----------------- transport/vless/vision/conn.go | 274 ++++++++++++++++ transport/vless/{ => vision}/filter.go | 2 +- .../vless/{vision.go => vision/padding.go} | 6 +- transport/vless/vision/vision.go | 70 ++++ transport/vless/xtls.go | 5 - 6 files changed, 362 insertions(+), 300 deletions(-) create mode 100644 transport/vless/vision/conn.go rename transport/vless/{ => vision}/filter.go (99%) rename transport/vless/{vision.go => vision/padding.go} (94%) create mode 100644 transport/vless/vision/vision.go diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 9289afcf..9e2e5e89 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -1,25 +1,18 @@ package vless import ( - "bytes" - "crypto/subtle" - gotls "crypto/tls" "encoding/binary" "errors" "fmt" "io" "net" - "reflect" "sync" - "unsafe" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" - tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/log" + "github.com/Dreamacro/clash/transport/vless/vision" "github.com/gofrs/uuid/v5" - utls "github.com/sagernet/utls" xtls "github.com/xtls/go" "google.golang.org/protobuf/proto" ) @@ -36,33 +29,10 @@ type Conn struct { handshakeMutex sync.Mutex needHandshake bool err error - - tlsConn net.Conn - input *bytes.Reader - rawInput *bytes.Buffer - - packetsToFilter int - isTLS bool - isTLS12orAbove bool - enableXTLS bool - cipher uint16 - remainingServerHello uint16 - readRemainingContent int - readRemainingPadding int - readProcess bool - readFilterUUID bool - readLastCommand byte - writeFilterApplicationData bool - writeDirect bool } func (vc *Conn) Read(b []byte) (int, error) { if vc.received { - if vc.readProcess { - buffer := buf.With(b) - err := vc.ReadBuffer(buffer) - return buffer.Len(), err - } return vc.ExtendedReader.Read(b) } @@ -70,106 +40,11 @@ func (vc *Conn) Read(b []byte) (int, error) { return 0, err } vc.received = true - return vc.Read(b) + return vc.ExtendedReader.Read(b) } func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { if vc.received { - toRead := buffer.FreeBytes() - if vc.readRemainingContent > 0 { - if vc.readRemainingContent < buffer.FreeLen() { - toRead = toRead[:vc.readRemainingContent] - } - n, err := vc.ExtendedReader.Read(toRead) - buffer.Truncate(n) - vc.readRemainingContent -= n - vc.FilterTLS(toRead) - return err - } - if vc.readRemainingPadding > 0 { - _, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding)) - if err != nil { - return err - } - vc.readRemainingPadding = 0 - } - if vc.readProcess { - switch vc.readLastCommand { - case commandPaddingContinue: - //if vc.isTLS || vc.packetsToFilter > 0 { - headerUUIDLen := 0 - if vc.readFilterUUID { - headerUUIDLen = uuid.Size - } - var header []byte - if need := headerUUIDLen + paddingHeaderLen; buffer.FreeLen() < need { - header = make([]byte, need) - } else { - header = buffer.FreeBytes()[:need] - } - _, err := io.ReadFull(vc.ExtendedReader, header) - if err != nil { - return err - } - pos := 0 - if vc.readFilterUUID { - vc.readFilterUUID = false - pos = uuid.Size - if subtle.ConstantTimeCompare(vc.id.Bytes(), header[:uuid.Size]) != 1 { - err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", - uuid.FromBytesOrNil(header[:uuid.Size]).String()) - log.Errorln(err.Error()) - return err - } - } - vc.readLastCommand = header[pos] - vc.readRemainingContent = int(binary.BigEndian.Uint16(header[pos+1:])) - vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[pos+3:])) - log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d", - vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding) - return vc.ReadBuffer(buffer) - //} - case commandPaddingEnd: - vc.readProcess = false - return vc.ReadBuffer(buffer) - case commandPaddingDirect: - needReturn := false - if vc.input != nil { - _, err := buffer.ReadFrom(vc.input) - if err != nil { - return err - } - if vc.input.Len() == 0 { - needReturn = true - vc.input = nil - } else { // buffer is full - return nil - } - } - if vc.rawInput != nil { - _, err := buffer.ReadFrom(vc.rawInput) - if err != nil { - return err - } - needReturn = true - if vc.rawInput.Len() == 0 { - vc.rawInput = nil - } - } - if vc.input == nil && vc.rawInput == nil { - vc.readProcess = false - vc.ExtendedReader = N.NewExtendedReader(vc.Conn) - log.Debugln("XTLS Vision direct read start") - } - if needReturn { - return nil - } - default: - err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand) - log.Debugln(err.Error()) - return err - } - } return vc.ExtendedReader.ReadBuffer(buffer) } @@ -177,7 +52,7 @@ func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { return err } vc.received = true - return vc.ReadBuffer(buffer) + return vc.ExtendedReader.ReadBuffer(buffer) } func (vc *Conn) Write(p []byte) (int, error) { @@ -200,18 +75,6 @@ func (vc *Conn) Write(p []byte) (int, error) { vc.handshakeMutex.Unlock() } - if vc.writeFilterApplicationData { - _buffer := buf.StackNew() - defer buf.KeepAlive(_buffer) - buffer := buf.Dup(_buffer) - defer buffer.Release() - buffer.Write(p) - err := vc.WriteBuffer(buffer) - if err != nil { - return 0, err - } - return len(p), nil - } return vc.ExtendedWriter.Write(p) } @@ -232,63 +95,6 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) error { vc.handshakeMutex.Unlock() } - if vc.writeFilterApplicationData { - buffer2 := ReshapeBuffer(buffer) - defer buffer2.Release() - vc.FilterTLS(buffer.Bytes()) - command := commandPaddingContinue - if !vc.isTLS { - command = commandPaddingEnd - - // disable XTLS - //vc.readProcess = false - vc.writeFilterApplicationData = false - vc.packetsToFilter = 0 - } else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { - command = commandPaddingEnd - if vc.enableXTLS { - command = commandPaddingDirect - vc.writeDirect = true - } - vc.writeFilterApplicationData = false - } - ApplyPadding(buffer, command, nil, vc.isTLS) - err := vc.ExtendedWriter.WriteBuffer(buffer) - if err != nil { - return err - } - if vc.writeDirect { - vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) - log.Debugln("XTLS Vision direct write start") - //time.Sleep(5 * time.Millisecond) - } - if buffer2 != nil { - if vc.writeDirect || !vc.isTLS { - return vc.ExtendedWriter.WriteBuffer(buffer2) - } - vc.FilterTLS(buffer2.Bytes()) - command = commandPaddingContinue - if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { - command = commandPaddingEnd - if vc.enableXTLS { - command = commandPaddingDirect - vc.writeDirect = true - } - vc.writeFilterApplicationData = false - } - ApplyPadding(buffer2, command, nil, vc.isTLS) - err = vc.ExtendedWriter.WriteBuffer(buffer2) - if vc.writeDirect { - vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) - log.Debugln("XTLS Vision direct write start") - //time.Sleep(10 * time.Millisecond) - } - } - return err - } - /*if vc.writeDirect { - log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len()) - }*/ return vc.ExtendedWriter.WriteBuffer(buffer) } @@ -300,10 +106,9 @@ func (vc *Conn) sendRequest(p []byte) bool { return true } } - isVision := vc.IsXTLSVisionEnabled() var buffer *buf.Buffer - if isVision { + if vc.IsXTLSVisionEnabled() { _buffer := buf.StackNew() defer buf.KeepAlive(_buffer) buffer = buf.Dup(_buffer) @@ -350,50 +155,14 @@ func (vc *Conn) sendRequest(p []byte) bool { ) } - if isVision && !vc.dst.UDP && !vc.dst.Mux { - if len(p) == 0 { - WriteWithPadding(buffer, nil, commandPaddingContinue, vc.id, vc.isTLS) - } else { - vc.FilterTLS(p) - //if vc.isTLS { - WriteWithPadding(buffer, p, commandPaddingContinue, vc.id, vc.isTLS) - //} else { - // buf.Must(buf.Error(buffer.Write(p))) - // - // // disable XTLS - // vc.readProcess = false - // vc.writeFilterApplicationData = false - // vc.packetsToFilter = 0 - //} - } - } else { - buf.Must(buf.Error(buffer.Write(p))) - } + buf.Must(buf.Error(buffer.Write(p))) _, vc.err = vc.ExtendedWriter.Write(buffer.Bytes()) - if vc.err != nil { - return true - } - if isVision { - switch underlying := vc.tlsConn.(type) { - case *gotls.Conn: - if underlying.ConnectionState().Version != gotls.VersionTLS13 { - vc.err = ErrNotTLS13 - } - case *utls.UConn: - if underlying.ConnectionState().Version != utls.VersionTLS13 { - vc.err = ErrNotTLS13 - } - default: - vc.err = fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, vc.addons.Flow) - } - vc.tlsConn = nil - } return true } func (vc *Conn) recvResponse() error { - var buffer [1]byte + var buffer [2]byte _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) if vc.err != nil { return vc.err @@ -403,12 +172,7 @@ func (vc *Conn) recvResponse() error { return errors.New("unexpected response version") } - _, vc.err = io.ReadFull(vc.ExtendedReader, buffer[:]) - if vc.err != nil { - return vc.err - } - - length := int64(buffer[0]) + length := int64(buffer[1]) if length != 0 { // addon data length > 0 io.CopyN(io.Discard, vc.ExtendedReader, length) // just discard } @@ -416,18 +180,8 @@ func (vc *Conn) recvResponse() error { return nil } -func (vc *Conn) FrontHeadroom() int { - if vc.IsXTLSVisionEnabled() { - return paddingHeaderLen - } - return 0 -} - func (vc *Conn) Upstream() any { - if vc.tlsConn == nil { - return vc.Conn - } - return vc.tlsConn + return vc.Conn } func (vc *Conn) NeedHandshake() bool { @@ -439,7 +193,7 @@ func (vc *Conn) IsXTLSVisionEnabled() bool { } // newConn return a Conn instance -func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { +func newConn(conn net.Conn, client *Client, dst *DstAddr) (net.Conn, error) { c := &Conn{ ExtendedReader: N.NewExtendedReader(conn), ExtendedWriter: N.NewExtendedWriter(conn), @@ -468,43 +222,12 @@ func newConn(conn net.Conn, client *Client, dst *DstAddr) (*Conn, error) { return nil, fmt.Errorf("failed to use %s, maybe \"security\" is not \"xtls\"", client.Addons.Flow) } case XRV: - c.packetsToFilter = 6 - c.readProcess = true - c.readFilterUUID = true - c.writeFilterApplicationData = true - c.addons = client.Addons - var t reflect.Type - var p unsafe.Pointer - switch underlying := conn.(type) { - case *gotls.Conn: - //log.Debugln("type tls") - c.Conn = underlying.NetConn() - c.tlsConn = underlying - t = reflect.TypeOf(underlying).Elem() - p = unsafe.Pointer(underlying) - case *utls.UConn: - //log.Debugln("type *utls.UConn") - c.Conn = underlying.NetConn() - c.tlsConn = underlying - t = reflect.TypeOf(underlying.Conn).Elem() - p = unsafe.Pointer(underlying.Conn) - case *tlsC.UConn: - //log.Debugln("type *tlsC.UConn") - c.Conn = underlying.NetConn() - c.tlsConn = underlying.UConn - t = reflect.TypeOf(underlying.Conn).Elem() - //log.Debugln("t:%v", t) - p = unsafe.Pointer(underlying.Conn) - default: - return nil, fmt.Errorf(`failed to use %s, maybe "security" is not "tls" or "utls"`, client.Addons.Flow) + visionConn, err := vision.NewConn(c, c.id) + if err != nil { + return nil, err } - i, _ := t.FieldByName("input") - r, _ := t.FieldByName("rawInput") - c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset)) - c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset)) - //if _, ok := c.Conn.(*net.TCPConn); !ok { - // log.Debugln("XTLS underlying conn is not *net.TCPConn, got %T", c.Conn) - //} + c.addons = client.Addons + return visionConn, nil } } diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go new file mode 100644 index 00000000..650d094d --- /dev/null +++ b/transport/vless/vision/conn.go @@ -0,0 +1,274 @@ +package vision + +import ( + "bytes" + "crypto/subtle" + gotls "crypto/tls" + "encoding/binary" + "fmt" + "io" + "net" + + "github.com/Dreamacro/clash/common/buf" + N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/log" + + "github.com/gofrs/uuid/v5" + utls "github.com/sagernet/utls" +) + +var ( + _ N.ExtendedConn = (*Conn)(nil) +) + +type Conn struct { + net.Conn + N.ExtendedReader + N.ExtendedWriter + upstream net.Conn + userUUID *uuid.UUID + + tlsConn net.Conn + input *bytes.Reader + rawInput *bytes.Buffer + + needHandshake bool + packetsToFilter int + isTLS bool + isTLS12orAbove bool + enableXTLS bool + cipher uint16 + remainingServerHello uint16 + readRemainingContent int + readRemainingPadding int + readProcess bool + readFilterUUID bool + readLastCommand byte + writeFilterApplicationData bool + writeDirect bool +} + +func (vc *Conn) Read(b []byte) (int, error) { + if vc.readProcess { + buffer := buf.With(b) + err := vc.ReadBuffer(buffer) + return buffer.Len(), err + } + return vc.ExtendedReader.Read(b) +} + +func (vc *Conn) ReadBuffer(buffer *buf.Buffer) error { + toRead := buffer.FreeBytes() + if vc.readRemainingContent > 0 { + if vc.readRemainingContent < buffer.FreeLen() { + toRead = toRead[:vc.readRemainingContent] + } + n, err := vc.ExtendedReader.Read(toRead) + buffer.Truncate(n) + vc.readRemainingContent -= n + vc.FilterTLS(toRead) + return err + } + if vc.readRemainingPadding > 0 { + _, err := io.CopyN(io.Discard, vc.ExtendedReader, int64(vc.readRemainingPadding)) + if err != nil { + return err + } + vc.readRemainingPadding = 0 + } + if vc.readProcess { + switch vc.readLastCommand { + case commandPaddingContinue: + //if vc.isTLS || vc.packetsToFilter > 0 { + headerUUIDLen := 0 + if vc.readFilterUUID { + headerUUIDLen = uuid.Size + } + var header []byte + if need := headerUUIDLen + PaddingHeaderLen - uuid.Size; buffer.FreeLen() < need { + header = make([]byte, need) + } else { + header = buffer.FreeBytes()[:need] + } + _, err := io.ReadFull(vc.ExtendedReader, header) + if err != nil { + return err + } + if vc.readFilterUUID { + vc.readFilterUUID = false + if subtle.ConstantTimeCompare(vc.userUUID.Bytes(), header[:uuid.Size]) != 1 { + err = fmt.Errorf("XTLS Vision server responded unknown UUID: %s", + uuid.FromBytesOrNil(header[:uuid.Size]).String()) + log.Errorln(err.Error()) + return err + } + header = header[uuid.Size:] + } + vc.readRemainingPadding = int(binary.BigEndian.Uint16(header[3:])) + vc.readRemainingContent = int(binary.BigEndian.Uint16(header[1:])) + vc.readLastCommand = header[0] + log.Debugln("XTLS Vision read padding: command=%d, payloadLen=%d, paddingLen=%d", + vc.readLastCommand, vc.readRemainingContent, vc.readRemainingPadding) + return vc.ReadBuffer(buffer) + //} + case commandPaddingEnd: + vc.readProcess = false + return vc.ReadBuffer(buffer) + case commandPaddingDirect: + needReturn := false + if vc.input != nil { + _, err := buffer.ReadFrom(vc.input) + if err != nil { + return err + } + if vc.input.Len() == 0 { + needReturn = true + vc.input = nil + } else { // buffer is full + return nil + } + } + if vc.rawInput != nil { + _, err := buffer.ReadFrom(vc.rawInput) + if err != nil { + return err + } + needReturn = true + if vc.rawInput.Len() == 0 { + vc.rawInput = nil + } + } + if vc.input == nil && vc.rawInput == nil { + vc.readProcess = false + vc.ExtendedReader = N.NewExtendedReader(vc.Conn) + log.Debugln("XTLS Vision direct read start") + } + if needReturn { + return nil + } + default: + err := fmt.Errorf("XTLS Vision read unknown command: %d", vc.readLastCommand) + log.Debugln(err.Error()) + return err + } + } + return vc.ExtendedReader.ReadBuffer(buffer) +} + +func (vc *Conn) Write(p []byte) (int, error) { + if vc.writeFilterApplicationData { + _buffer := buf.StackNew() + defer buf.KeepAlive(_buffer) + buffer := buf.Dup(_buffer) + defer buffer.Release() + buffer.Write(p) + err := vc.WriteBuffer(buffer) + if err != nil { + return 0, err + } + return len(p), nil + } + return vc.ExtendedWriter.Write(p) +} + +func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { + if vc.needHandshake { + vc.needHandshake = false + if buffer.IsEmpty() { + ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, false) + } else { + vc.FilterTLS(buffer.Bytes()) + ApplyPadding(buffer, commandPaddingContinue, vc.userUUID, vc.isTLS) + } + err = vc.ExtendedWriter.WriteBuffer(buffer) + if err != nil { + buffer.Release() + return err + } + switch underlying := vc.tlsConn.(type) { + case *gotls.Conn: + if underlying.ConnectionState().Version != gotls.VersionTLS13 { + buffer.Release() + return ErrNotTLS13 + } + case *utls.UConn: + if underlying.ConnectionState().Version != utls.VersionTLS13 { + buffer.Release() + return ErrNotTLS13 + } + } + vc.tlsConn = nil + return nil + } + + if vc.writeFilterApplicationData { + buffer2 := ReshapeBuffer(buffer) + defer buffer2.Release() + vc.FilterTLS(buffer.Bytes()) + command := commandPaddingContinue + if !vc.isTLS { + command = commandPaddingEnd + + // disable XTLS + //vc.readProcess = false + vc.writeFilterApplicationData = false + vc.packetsToFilter = 0 + } else if buffer.Len() > 6 && bytes.Equal(buffer.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { + command = commandPaddingEnd + if vc.enableXTLS { + command = commandPaddingDirect + vc.writeDirect = true + } + vc.writeFilterApplicationData = false + } + ApplyPadding(buffer, command, nil, vc.isTLS) + err = vc.ExtendedWriter.WriteBuffer(buffer) + if err != nil { + return err + } + if vc.writeDirect { + vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) + log.Debugln("XTLS Vision direct write start") + //time.Sleep(5 * time.Millisecond) + } + if buffer2 != nil { + if vc.writeDirect || !vc.isTLS { + return vc.ExtendedWriter.WriteBuffer(buffer2) + } + vc.FilterTLS(buffer2.Bytes()) + command = commandPaddingContinue + if buffer2.Len() > 6 && bytes.Equal(buffer2.To(3), tlsApplicationDataStart) || vc.packetsToFilter <= 0 { + command = commandPaddingEnd + if vc.enableXTLS { + command = commandPaddingDirect + vc.writeDirect = true + } + vc.writeFilterApplicationData = false + } + ApplyPadding(buffer2, command, nil, vc.isTLS) + err = vc.ExtendedWriter.WriteBuffer(buffer2) + if vc.writeDirect { + vc.ExtendedWriter = N.NewExtendedWriter(vc.Conn) + log.Debugln("XTLS Vision direct write start") + //time.Sleep(10 * time.Millisecond) + } + } + return err + } + /*if vc.writeDirect { + log.Debugln("XTLS Vision Direct write, payloadLen=%d", buffer.Len()) + }*/ + return vc.ExtendedWriter.WriteBuffer(buffer) +} + +func (vc *Conn) FrontHeadroom() int { + return PaddingHeaderLen +} + +func (vc *Conn) NeedHandshake() bool { + return vc.needHandshake +} + +func (vc *Conn) Upstream() any { + return vc.upstream +} diff --git a/transport/vless/filter.go b/transport/vless/vision/filter.go similarity index 99% rename from transport/vless/filter.go rename to transport/vless/vision/filter.go index f577be7a..e070de35 100644 --- a/transport/vless/filter.go +++ b/transport/vless/vision/filter.go @@ -1,4 +1,4 @@ -package vless +package vision import ( "bytes" diff --git a/transport/vless/vision.go b/transport/vless/vision/padding.go similarity index 94% rename from transport/vless/vision.go rename to transport/vless/vision/padding.go index 5649dde4..d5a230d1 100644 --- a/transport/vless/vision.go +++ b/transport/vless/vision/padding.go @@ -1,4 +1,4 @@ -package vless +package vision import ( "bytes" @@ -12,7 +12,7 @@ import ( ) const ( - paddingHeaderLen = 1 + 2 + 2 // =5 + PaddingHeaderLen = uuid.Size + 1 + 2 + 2 // =21 commandPaddingContinue byte = 0x00 commandPaddingEnd byte = 0x01 @@ -67,7 +67,7 @@ func ApplyPadding(buffer *buf.Buffer, command byte, userUUID *uuid.UUID, padding } func ReshapeBuffer(buffer *buf.Buffer) *buf.Buffer { - if buffer.Len() <= buf.BufferSize-paddingHeaderLen { + if buffer.Len() <= buf.BufferSize-PaddingHeaderLen { return nil } cutAt := bytes.LastIndex(buffer.Bytes(), tlsApplicationDataStart) diff --git a/transport/vless/vision/vision.go b/transport/vless/vision/vision.go new file mode 100644 index 00000000..3b52dd4b --- /dev/null +++ b/transport/vless/vision/vision.go @@ -0,0 +1,70 @@ +// Package vision implements VLESS flow `xtls-rprx-vision` introduced by Xray-core. +package vision + +import ( + "bytes" + gotls "crypto/tls" + "errors" + "fmt" + "net" + "reflect" + "unsafe" + + N "github.com/Dreamacro/clash/common/net" + tlsC "github.com/Dreamacro/clash/component/tls" + + "github.com/gofrs/uuid/v5" + "github.com/sagernet/sing/common" + utls "github.com/sagernet/utls" +) + +var ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") + +type connWithUpstream interface { + net.Conn + common.WithUpstream +} + +func NewConn(conn connWithUpstream, userUUID *uuid.UUID) (*Conn, error) { + c := &Conn{ + ExtendedReader: N.NewExtendedReader(conn), + ExtendedWriter: N.NewExtendedWriter(conn), + upstream: conn, + userUUID: userUUID, + packetsToFilter: 6, + needHandshake: true, + readProcess: true, + readFilterUUID: true, + writeFilterApplicationData: true, + } + var t reflect.Type + var p unsafe.Pointer + switch underlying := conn.Upstream().(type) { + case *gotls.Conn: + //log.Debugln("type tls") + c.Conn = underlying.NetConn() + c.tlsConn = underlying + t = reflect.TypeOf(underlying).Elem() + p = unsafe.Pointer(underlying) + case *utls.UConn: + //log.Debugln("type *utls.UConn") + c.Conn = underlying.NetConn() + c.tlsConn = underlying + t = reflect.TypeOf(underlying.Conn).Elem() + p = unsafe.Pointer(underlying.Conn) + case *tlsC.UConn: + //log.Debugln("type *tlsC.UConn") + c.Conn = underlying.NetConn() + c.tlsConn = underlying.UConn + t = reflect.TypeOf(underlying.Conn).Elem() + //log.Debugln("t:%v", t) + p = unsafe.Pointer(underlying.Conn) + default: + return nil, fmt.Errorf(`failed to use vision, maybe "security" is not "tls" or "utls"`) + } + i, _ := t.FieldByName("input") + r, _ := t.FieldByName("rawInput") + c.input = (*bytes.Reader)(unsafe.Add(p, i.Offset)) + c.rawInput = (*bytes.Buffer)(unsafe.Add(p, r.Offset)) + return c, nil +} diff --git a/transport/vless/xtls.go b/transport/vless/xtls.go index 09929fc3..071e6e8f 100644 --- a/transport/vless/xtls.go +++ b/transport/vless/xtls.go @@ -2,17 +2,12 @@ package vless import ( "context" - "errors" "net" tlsC "github.com/Dreamacro/clash/component/tls" xtls "github.com/xtls/go" ) -var ( - ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") -) - type XTLSConfig struct { Host string SkipCertVerify bool From 4971b9d8046713226ede50d939316e82c5343da8 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 27 May 2023 10:14:02 +0800 Subject: [PATCH 293/530] chore: Add vision splice support --- go.mod | 2 +- go.sum | 4 ++-- transport/vless/vision/conn.go | 32 +++++++++++++++++++++++++++++++- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 40a92438..e5b4882f 100644 --- a/go.mod +++ b/go.mod @@ -105,6 +105,6 @@ require ( golang.org/x/tools v0.6.0 // indirect ) -replace github.com/sagernet/sing => github.com/h1jk/sing v0.0.0-20230519121640-6db84f45244d +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230526162852-6afe73474070 replace github.com/sagernet/sing-vmess => github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899 diff --git a/go.sum b/go.sum index 0e9e38a7..bee79cc9 100644 --- a/go.sum +++ b/go.sum @@ -65,8 +65,6 @@ 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/h1jk/sing v0.0.0-20230519121640-6db84f45244d h1:ih6tNzl1uxuuX+Naz2qAPqSS20E6jfXFmcvyDRAy8rY= -github.com/h1jk/sing v0.0.0-20230519121640-6db84f45244d/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= 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= @@ -98,6 +96,8 @@ github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+ 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/sing v0.0.0-20230526162852-6afe73474070 h1:AT/Qfe9MvCxyrI9uybcXcVDLDEqR6+9ZK7a7pgis9xQ= +github.com/metacubex/sing v0.0.0-20230526162852-6afe73474070/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-20230519030442-556ef530768f h1:aWgVMoAm5V2Ur9key6L//mUSBrVMl/zw/4GDG4ZjyZI= diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go index 650d094d..23721c0b 100644 --- a/transport/vless/vision/conn.go +++ b/transport/vless/vision/conn.go @@ -262,7 +262,10 @@ func (vc *Conn) WriteBuffer(buffer *buf.Buffer) (err error) { } func (vc *Conn) FrontHeadroom() int { - return PaddingHeaderLen + if vc.readFilterUUID { + return PaddingHeaderLen + } + return PaddingHeaderLen - uuid.Size } func (vc *Conn) NeedHandshake() bool { @@ -270,5 +273,32 @@ func (vc *Conn) NeedHandshake() bool { } func (vc *Conn) Upstream() any { + if vc.writeDirect || + vc.readLastCommand == commandPaddingDirect { + return vc.Conn + } return vc.upstream } + +func (vc *Conn) ReaderPossiblyReplaceable() bool { + return vc.readProcess +} + +func (vc *Conn) ReaderReplaceable() bool { + if !vc.readProcess && + vc.readLastCommand == commandPaddingDirect { + return true + } + return false +} + +func (vc *Conn) WriterPossiblyReplaceable() bool { + return vc.writeFilterApplicationData +} + +func (vc *Conn) WriterReplaceable() bool { + if vc.writeDirect { + return true + } + return false +} From 73140ab826109c1c6737ae762994a8d21ffdc6e2 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 27 May 2023 13:43:41 +0800 Subject: [PATCH 294/530] fix: udp panic when server return a domain name --- constant/metadata.go | 11 ++++++----- tunnel/connection.go | 29 +++++++++++++++++------------ tunnel/tunnel.go | 4 ++-- 3 files changed, 25 insertions(+), 19 deletions(-) diff --git a/constant/metadata.go b/constant/metadata.go index 1c344d5d..198c447d 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -205,15 +205,16 @@ func (m *Metadata) Pure() *Metadata { return m } +func (m *Metadata) AddrPort() netip.AddrPort { + port, _ := strconv.ParseUint(m.DstPort, 10, 16) + return netip.AddrPortFrom(m.DstIP.Unmap(), uint16(port)) +} + func (m *Metadata) UDPAddr() *net.UDPAddr { if m.NetWork != UDP || !m.DstIP.IsValid() { return nil } - port, _ := strconv.ParseUint(m.DstPort, 10, 16) - return &net.UDPAddr{ - IP: m.DstIP.AsSlice(), - Port: int(port), - } + return net.UDPAddrFromAddrPort(m.AddrPort()) } func (m *Metadata) String() string { diff --git a/tunnel/connection.go b/tunnel/connection.go index 321c7d06..b130f79a 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, oAddr, fAddr netip.Addr) { +func handleUDPToLocal(packet C.UDPPacket, pc N.EnhancePacketConn, key string, oAddrPort netip.AddrPort, fAddr netip.Addr) { defer func() { _ = pc.Close() closeAllLocalCoon(key) @@ -40,18 +40,23 @@ func handleUDPToLocal(packet C.UDPPacket, pc N.EnhancePacketConn, key string, oA return } - fromUDPAddr := from.(*net.UDPAddr) - _fromUDPAddr := *fromUDPAddr - fromUDPAddr = &_fromUDPAddr // make a copy - if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok { - fromAddr = fromAddr.Unmap() - if fAddr.IsValid() && (oAddr.Unmap() == fromAddr) { - fromAddr = fAddr.Unmap() - } - fromUDPAddr.IP = fromAddr.AsSlice() - if fromAddr.Is4() { - fromUDPAddr.Zone = "" // only ipv6 can have the zone + fromUDPAddr, isUDPAddr := from.(*net.UDPAddr) + if isUDPAddr { + _fromUDPAddr := *fromUDPAddr + fromUDPAddr = &_fromUDPAddr // make a copy + if fromAddr, ok := netip.AddrFromSlice(fromUDPAddr.IP); ok { + fromAddr = fromAddr.Unmap() + if fAddr.IsValid() && (oAddrPort.Addr() == fromAddr) { // oAddrPort was Unmapped + fromAddr = fAddr.Unmap() + } + fromUDPAddr.IP = fromAddr.AsSlice() + if fromAddr.Is4() { + 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 = packet.WriteBack(data, fromUDPAddr) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index a4a473e9..4e00aca2 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -383,10 +383,10 @@ func handleUDPConn(packet C.PacketAdapter) { log.Infoln("[UDP] %s --> %s doesn't match any rule using DIRECT", metadata.SourceDetail(), metadata.RemoteAddress()) } - oAddr := metadata.DstIP + oAddrPort := metadata.AddrPort() natTable.Set(key, pc) - go handleUDPToLocal(packet, pc, key, oAddr, fAddr) + go handleUDPToLocal(packet, pc, key, oAddrPort, fAddr) handle() }() From f44ba26f0c321d3e84388a71e8858079428c93eb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 28 May 2023 08:50:02 +0800 Subject: [PATCH 295/530] chore: switch ss uot default back to version 1 --- adapter/outbound/shadowsocks.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index e6c74592..2edc7080 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -304,7 +304,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { switch option.UDPOverTCPVersion { case uot.Version, uot.LegacyVersion: case 0: - option.UDPOverTCPVersion = uot.Version + option.UDPOverTCPVersion = uot.LegacyVersion default: return nil, fmt.Errorf("ss %s unknown udp over tcp protocol version: %d", addr, option.UDPOverTCPVersion) } From 92f71fd25fb6c87735c38abee6e0d3565eb05d12 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 28 May 2023 09:33:42 +0800 Subject: [PATCH 296/530] chore: add WaitReadFrom support in hyPacketConn --- adapter/outbound/hysteria.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 6024ea10..2d5b90ac 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -318,6 +318,17 @@ func (c *hyPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { return } +func (c *hyPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + b, addrStr, err := c.UDPConn.ReadFrom() + if err != nil { + return + } + data = b + put = func() {} + addr = M.ParseSocksaddr(addrStr).UDPAddr() + return +} + func (c *hyPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { err = c.UDPConn.WriteTo(p, M.SocksaddrFromNet(addr).String()) if err != nil { From 7aae781569b9cb1fd3b7048bc5704021e381582a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 28 May 2023 15:22:08 +0800 Subject: [PATCH 297/530] chore: add WaitReadFrom support in quicStreamPacketConn --- adapter/outbound/hysteria.go | 3 ++- common/net/packet.go | 2 ++ common/net/packet/packet.go | 2 ++ transport/tuic/conn.go | 16 ++++++++++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 2d5b90ac..161a4546 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -19,6 +19,7 @@ import ( "github.com/metacubex/quic-go/congestion" M "github.com/sagernet/sing/common/metadata" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" tlsC "github.com/Dreamacro/clash/component/tls" @@ -324,7 +325,7 @@ func (c *hyPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, e return } data = b - put = func() {} + put = N.NilPut addr = M.ParseSocksaddr(addrStr).UDPAddr() return } diff --git a/common/net/packet.go b/common/net/packet.go index 9afe86b0..e949ecf2 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -6,7 +6,9 @@ import ( ) type EnhancePacketConn = packet.EnhancePacketConn +type WaitReadFrom = packet.WaitReadFrom +var NilPut = packet.NilPut var NewEnhancePacketConn = packet.NewEnhancePacketConn var NewThreadSafePacketConn = packet.NewThreadSafePacketConn var NewRefPacketConn = packet.NewRefPacketConn diff --git a/common/net/packet/packet.go b/common/net/packet/packet.go index 6c9542c1..a3f1dd72 100644 --- a/common/net/packet/packet.go +++ b/common/net/packet/packet.go @@ -10,6 +10,8 @@ type WaitReadFrom interface { WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) } +func NilPut() {} + type EnhancePacketConn interface { net.PacketConn WaitReadFrom diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index 567f6ce5..d46a3556 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -197,6 +197,22 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err return } +func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + if q.inputConn != nil { + var packet Packet + packet, err = ReadPacket(q.inputConn) + if err != nil { + return + } + data = packet.DATA + put = N.NilPut + addr = packet.ADDR.UDPAddr() + } else { + err = net.ErrClosed + } + return +} + func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err error) { if q.udpRelayMode != "quic" && len(p) > q.maxUdpRelayPacketSize { return 0, quic.ErrMessageTooLarge(q.maxUdpRelayPacketSize) From 9c2972afb066adaedfe5b65e581dbe7505d941aa Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 28 May 2023 17:19:57 +0800 Subject: [PATCH 298/530] chore: add `IN-USER` and `IN-NAME` rules --- adapter/inbound/addition.go | 6 +++++ constant/metadata.go | 1 + constant/rule.go | 12 ++++++--- listener/sing/context.go | 20 +++++++++++++++ listener/sing/sing.go | 15 ++---------- rules/common/in_name.go | 49 +++++++++++++++++++++++++++++++++++++ rules/common/in_type.go | 4 +-- rules/common/in_user.go | 49 +++++++++++++++++++++++++++++++++++++ rules/parser.go | 4 +++ 9 files changed, 142 insertions(+), 18 deletions(-) create mode 100644 rules/common/in_name.go create mode 100644 rules/common/in_user.go diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 5966e784..47307ed7 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -16,6 +16,12 @@ func WithInName(name string) Addition { } } +func WithInUser(user string) Addition { + return func(metadata *C.Metadata) { + metadata.InUser = user + } +} + func WithSpecialRules(specialRules string) Addition { return func(metadata *C.Metadata) { metadata.SpecialRules = specialRules diff --git a/constant/metadata.go b/constant/metadata.go index 198c447d..edc58aec 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -133,6 +133,7 @@ type Metadata struct { InIP netip.Addr `json:"inboundIP"` InPort string `json:"inboundPort"` InName string `json:"inboundName"` + InUser string `json:"inboundUser"` Host string `json:"host"` DNSMode DNSMode `json:"dnsMode"` Uid uint32 `json:"uid"` diff --git a/constant/rule.go b/constant/rule.go index 28c629a0..906f3cef 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -14,12 +14,14 @@ const ( SrcPort DstPort InPort + InUser + InName + InType Process ProcessPath RuleSet Network Uid - INTYPE SubRules MATCH AND @@ -55,6 +57,12 @@ func (rt RuleType) String() string { return "DstPort" case InPort: return "InPort" + case InUser: + return "InUser" + case InName: + return "InName" + case InType: + return "InType" case Process: return "Process" case ProcessPath: @@ -67,8 +75,6 @@ func (rt RuleType) String() string { return "Network" case Uid: return "Uid" - case INTYPE: - return "InType" case SubRules: return "SubRules" case AND: diff --git a/listener/sing/context.go b/listener/sing/context.go index f7aed851..a500e4a4 100644 --- a/listener/sing/context.go +++ b/listener/sing/context.go @@ -2,8 +2,11 @@ package sing import ( "context" + "golang.org/x/exp/slices" "github.com/Dreamacro/clash/adapter/inbound" + + "github.com/sagernet/sing/common/auth" ) type contextKey string @@ -22,3 +25,20 @@ func getAdditions(ctx context.Context) []inbound.Addition { } return nil } + +func combineAdditions(ctx context.Context, additions []inbound.Addition) []inbound.Addition { + additionsCloned := false + if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { + additions = slices.Clone(additions) + additionsCloned = true + additions = append(additions, ctxAdditions...) + } + if user, ok := auth.UserFromContext[string](ctx); ok { + if !additionsCloned { + additions = slices.Clone(additions) + additionsCloned = true + } + additions = append(additions, inbound.WithInUser(user)) + } + return additions +} diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 9bf52e9c..c60bbe67 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -3,7 +3,6 @@ package sing import ( "context" "errors" - "golang.org/x/exp/slices" "net" "net/netip" "sync" @@ -74,11 +73,6 @@ func UpstreamMetadata(metadata M.Metadata) M.Metadata { } func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { - additions := h.Additions - if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { - additions = slices.Clone(additions) - additions = append(additions, ctxAdditions...) - } switch metadata.Destination.Fqdn { case mux.Destination.Fqdn: return mux.HandleConnection(ctx, h, log.SingLogger, conn, UpstreamMetadata(metadata)) @@ -103,16 +97,11 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta if deadline.NeedAdditionalReadDeadline(conn) { conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline } - h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, additions...) + h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, combineAdditions(ctx, h.Additions)...) return nil } func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network.PacketConn, metadata M.Metadata) error { - additions := h.Additions - if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { - additions = slices.Clone(additions) - additions = append(additions, ctxAdditions...) - } if deadline.NeedAdditionalReadDeadline(conn) { conn = deadline.NewFallbackPacketConn(bufio.NewNetPacketConn(conn)) // conn from sing should check NeedAdditionalReadDeadline } @@ -162,7 +151,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. buff: buff, } select { - case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, additions...): + case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...): default: } } diff --git a/rules/common/in_name.go b/rules/common/in_name.go new file mode 100644 index 00000000..1e2abe15 --- /dev/null +++ b/rules/common/in_name.go @@ -0,0 +1,49 @@ +package common + +import ( + "fmt" + C "github.com/Dreamacro/clash/constant" + "strings" +) + +type InName struct { + *Base + names []string + adapter string + payload string +} + +func (u *InName) Match(metadata *C.Metadata) (bool, string) { + for _, name := range u.names { + if metadata.InName == name { + return true, u.adapter + } + } + return false, "" +} + +func (u *InName) RuleType() C.RuleType { + return C.InName +} + +func (u *InName) Adapter() string { + return u.adapter +} + +func (u *InName) Payload() string { + return u.payload +} + +func NewInName(iNames, adapter string) (*InName, error) { + names := strings.Split(iNames, "/") + if len(names) == 0 { + return nil, fmt.Errorf("in name couldn't be empty") + } + + return &InName{ + Base: &Base{}, + names: names, + adapter: adapter, + payload: iNames, + }, nil +} diff --git a/rules/common/in_type.go b/rules/common/in_type.go index 520c9594..453045d8 100644 --- a/rules/common/in_type.go +++ b/rules/common/in_type.go @@ -23,7 +23,7 @@ func (u *InType) Match(metadata *C.Metadata) (bool, string) { } func (u *InType) RuleType() C.RuleType { - return C.INTYPE + return C.InType } func (u *InType) Adapter() string { @@ -37,7 +37,7 @@ func (u *InType) Payload() string { func NewInType(iTypes, adapter string) (*InType, error) { types := strings.Split(iTypes, "/") if len(types) == 0 { - return nil, fmt.Errorf("in type could be empty") + return nil, fmt.Errorf("in type couldn't be empty") } tps, err := parseInTypes(types) diff --git a/rules/common/in_user.go b/rules/common/in_user.go new file mode 100644 index 00000000..24f4b2e5 --- /dev/null +++ b/rules/common/in_user.go @@ -0,0 +1,49 @@ +package common + +import ( + "fmt" + C "github.com/Dreamacro/clash/constant" + "strings" +) + +type InUser struct { + *Base + users []string + adapter string + payload string +} + +func (u *InUser) Match(metadata *C.Metadata) (bool, string) { + for _, user := range u.users { + if metadata.InUser == user { + return true, u.adapter + } + } + return false, "" +} + +func (u *InUser) RuleType() C.RuleType { + return C.InUser +} + +func (u *InUser) Adapter() string { + return u.adapter +} + +func (u *InUser) Payload() string { + return u.payload +} + +func NewInUser(iUsers, adapter string) (*InUser, error) { + users := strings.Split(iUsers, "/") + if len(users) == 0 { + return nil, fmt.Errorf("in user couldn't be empty") + } + + return &InUser{ + Base: &Base{}, + users: users, + adapter: adapter, + payload: iUsers, + }, nil +} diff --git a/rules/parser.go b/rules/parser.go index 1a336225..df790bc3 100644 --- a/rules/parser.go +++ b/rules/parser.go @@ -47,6 +47,10 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string] parsed, parseErr = RC.NewUid(payload, target) case "IN-TYPE": parsed, parseErr = RC.NewInType(payload, target) + case "IN-USER": + parsed, parseErr = RC.NewInUser(payload, target) + case "IN-NAME": + parsed, parseErr = RC.NewInName(payload, target) case "SUB-RULE": parsed, parseErr = logic.NewSubRule(payload, target, subRules, ParseRule) case "AND": From 097f3e250c7f7cf301446e1bbcb799564c6cceff Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 28 May 2023 20:14:57 +0800 Subject: [PATCH 299/530] chore: slightly improve quic-bbr performance --- transport/tuic/congestion/bbr_sender.go | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index 99164362..17368386 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -17,17 +17,12 @@ const ( InitialMaxDatagramSize = 1252 InitialPacketSizeIPv4 = 1252 InitialPacketSizeIPv6 = 1232 - InitialCongestionWindow = 10 + InitialCongestionWindow = 32 DefaultBBRMaxCongestionWindow = 10000 ) -const ( - initialMinCongestionWindow = 4 - minInitialPacketSize = 1200 -) - func GetInitialPacketSize(addr net.Addr) congestion.ByteCount { - maxSize := congestion.ByteCount(minInitialPacketSize) + maxSize := congestion.ByteCount(1200) // If this is not a UDP address, we don't know anything about the MTU. // Use the minimum size of an Initial packet as the max packet size. if udpAddr, ok := addr.(*net.UDPAddr); ok { @@ -37,7 +32,7 @@ func GetInitialPacketSize(addr net.Addr) congestion.ByteCount { maxSize = InitialPacketSizeIPv6 } } - return maxSize + return congestion.ByteCount(maxSize) } var ( @@ -45,8 +40,8 @@ var ( // Default initial rtt used before any samples are received. InitialRtt = 100 * time.Millisecond - // The gain used for the STARTUP, equal to 2/ln(2). - DefaultHighGain = 2.89 + // The gain used for the STARTUP, equal to 4*ln(2). + DefaultHighGain = 2.77 // The gain used in STARTUP after loss has been detected. // 1.5 is enough to allow for 25% exogenous loss and still observe a 25% growth @@ -281,7 +276,7 @@ func (b *bbrSender) maxCongestionWindow() congestion.ByteCount { } func (b *bbrSender) minCongestionWindow() congestion.ByteCount { - return b.maxDatagramSize * initialMinCongestionWindow + return b.maxDatagramSize * b.initialCongestionWindow } func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { From 8e88e0b9f5c0ba04564ee70d0cd2b0c4da75d8eb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 28 May 2023 22:51:26 +0800 Subject: [PATCH 300/530] chore: add WaitReadFrom support in ssr --- adapter/outbound/hysteria.go | 2 - adapter/outbound/shadowsocks.go | 34 ---------- adapter/outbound/shadowsocksr.go | 68 +++++++++++++++++++- common/net/packet.go | 1 - common/net/packet/packet.go | 2 - go.mod | 2 +- go.sum | 4 +- listener/shadowsocks/udp.go | 21 +++--- listener/shadowsocks/utils.go | 7 +- transport/shadowsocks/core/cipher.go | 11 ++-- transport/shadowsocks/shadowaead/packet.go | 30 +++++++-- transport/shadowsocks/shadowstream/packet.go | 30 +++++++-- transport/ssr/protocol/auth_aes128_sha1.go | 5 +- transport/ssr/protocol/auth_chain_a.go | 5 +- transport/ssr/protocol/auth_sha1_v4.go | 3 +- transport/ssr/protocol/origin.go | 4 +- transport/ssr/protocol/packet.go | 24 ++++++- transport/ssr/protocol/protocol.go | 4 +- transport/trojan/trojan.go | 12 +++- transport/tuic/conn.go | 1 - 20 files changed, 182 insertions(+), 88 deletions(-) diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 161a4546..7da4975d 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -19,7 +19,6 @@ import ( "github.com/metacubex/quic-go/congestion" M "github.com/sagernet/sing/common/metadata" - N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" tlsC "github.com/Dreamacro/clash/component/tls" @@ -325,7 +324,6 @@ func (c *hyPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, e return } data = b - put = N.NilPut addr = M.ParseSocksaddr(addrStr).UDPAddr() return } diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 2edc7080..32558eac 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -16,7 +16,6 @@ import ( "github.com/Dreamacro/clash/transport/restls" obfs "github.com/Dreamacro/clash/transport/simple-obfs" shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls" - "github.com/Dreamacro/clash/transport/socks5" v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" restlsC "github.com/3andne/restls-client-go" @@ -330,36 +329,3 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { restlsConfig: restlsConfig, }, nil } - -type ssPacketConn struct { - net.PacketConn - rAddr net.Addr -} - -func (spc *ssPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { - packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) - if err != nil { - return - } - return spc.PacketConn.WriteTo(packet[3:], spc.rAddr) -} - -func (spc *ssPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, _, e := spc.PacketConn.ReadFrom(b) - if e != nil { - return 0, nil, e - } - - addr := socks5.SplitAddr(b[:n]) - if addr == nil { - return 0, nil, errors.New("parse addr error") - } - - udpAddr := addr.UDPAddr() - if udpAddr == nil { - return 0, nil, errors.New("parse addr error") - } - - copy(b, b[len(addr):]) - return n - len(addr), udpAddr, e -} diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index d33d6586..07778032 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -2,16 +2,19 @@ package outbound import ( "context" + "errors" "fmt" "net" "strconv" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/shadowsocks/core" "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" + "github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/ssr/obfs" "github.com/Dreamacro/clash/transport/ssr/protocol" ) @@ -110,9 +113,9 @@ func (ssr *ShadowSocksR) ListenPacketWithDialer(ctx context.Context, dialer C.Di return nil, err } - pc = ssr.cipher.PacketConn(pc) - pc = ssr.protocol.PacketConn(pc) - return newPacketConn(&ssPacketConn{PacketConn: pc, rAddr: addr}, ssr), nil + epc := ssr.cipher.PacketConn(N.NewEnhancePacketConn(pc)) + epc = ssr.protocol.PacketConn(epc) + return newPacketConn(&ssrPacketConn{EnhancePacketConn: epc, rAddr: addr}, ssr), nil } // SupportWithDialer implements C.ProxyAdapter @@ -188,3 +191,62 @@ func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { protocol: protocol, }, nil } + +type ssrPacketConn struct { + N.EnhancePacketConn + rAddr net.Addr +} + +func (spc *ssrPacketConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { + packet, err := socks5.EncodeUDPPacket(socks5.ParseAddrToSocksAddr(addr), b) + if err != nil { + return + } + return spc.EnhancePacketConn.WriteTo(packet[3:], spc.rAddr) +} + +func (spc *ssrPacketConn) ReadFrom(b []byte) (int, net.Addr, error) { + n, _, e := spc.EnhancePacketConn.ReadFrom(b) + if e != nil { + return 0, nil, e + } + + addr := socks5.SplitAddr(b[:n]) + if addr == nil { + return 0, nil, errors.New("parse addr error") + } + + udpAddr := addr.UDPAddr() + if udpAddr == nil { + return 0, nil, errors.New("parse addr error") + } + + copy(b, b[len(addr):]) + return n - len(addr), udpAddr, e +} + +func (spc *ssrPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, _, err = spc.EnhancePacketConn.WaitReadFrom() + if err != nil { + return nil, nil, nil, err + } + + _addr := socks5.SplitAddr(data) + if _addr == nil { + if put != nil { + put() + } + return nil, nil, nil, errors.New("parse addr error") + } + + addr = _addr.UDPAddr() + if addr == nil { + if put != nil { + put() + } + return nil, nil, nil, errors.New("parse addr error") + } + + data = data[len(_addr):] + return +} diff --git a/common/net/packet.go b/common/net/packet.go index e949ecf2..fc562c42 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -8,7 +8,6 @@ import ( type EnhancePacketConn = packet.EnhancePacketConn type WaitReadFrom = packet.WaitReadFrom -var NilPut = packet.NilPut var NewEnhancePacketConn = packet.NewEnhancePacketConn var NewThreadSafePacketConn = packet.NewThreadSafePacketConn var NewRefPacketConn = packet.NewRefPacketConn diff --git a/common/net/packet/packet.go b/common/net/packet/packet.go index a3f1dd72..6c9542c1 100644 --- a/common/net/packet/packet.go +++ b/common/net/packet/packet.go @@ -10,8 +10,6 @@ type WaitReadFrom interface { WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) } -func NilPut() {} - type EnhancePacketConn interface { net.PacketConn WaitReadFrom diff --git a/go.mod b/go.mod index e5b4882f..b203dd40 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c - github.com/metacubex/sing-shadowsocks2 v0.0.0-20230519030442-556ef530768f + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230528144023-05418c94ed2d github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a github.com/miekg/dns v1.1.54 diff --git a/go.sum b/go.sum index bee79cc9..25448530 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,8 @@ github.com/metacubex/sing v0.0.0-20230526162852-6afe73474070 h1:AT/Qfe9MvCxyrI9u github.com/metacubex/sing v0.0.0-20230526162852-6afe73474070/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-20230519030442-556ef530768f h1:aWgVMoAm5V2Ur9key6L//mUSBrVMl/zw/4GDG4ZjyZI= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230519030442-556ef530768f/go.mod h1:jVDD4N22bDPPKA73NvB7aqdlLWiAwv8D+jx7HwhcWak= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230528144023-05418c94ed2d h1:lWbWl3pZA1x8TgYDw07jo1u5RtbBRIlxuJDV4FW0WeQ= +github.com/metacubex/sing-shadowsocks2 v0.0.0-20230528144023-05418c94ed2d/go.mod h1:jVDD4N22bDPPKA73NvB7aqdlLWiAwv8D+jx7HwhcWak= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899 h1:iRfcuztp7REfmOyasSlCL/pqNWfUDMTJ2CwbGpxpeks= diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index ef67d4e8..4efafa60 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/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" @@ -29,19 +29,20 @@ func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UD } sl := &UDPListener{l, false} - conn := pickCipher.PacketConn(l) + conn := pickCipher.PacketConn(N.NewEnhancePacketConn(l)) go func() { for { - buf := pool.Get(pool.UDPBufferSize) - n, remoteAddr, err := conn.ReadFrom(buf) + data, put, remoteAddr, err := conn.WaitReadFrom() if err != nil { - pool.Put(buf) + if put != nil { + put() + } if sl.closed { break } continue } - handleSocksUDP(conn, in, buf[:n], remoteAddr) + handleSocksUDP(conn, in, data, put, remoteAddr) } }() @@ -57,11 +58,13 @@ func (l *UDPListener) LocalAddr() net.Addr { return l.packetConn.LocalAddr() } -func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, addr net.Addr) { +func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, put func(), addr net.Addr) { tgtAddr := socks5.SplitAddr(buf) if tgtAddr == nil { // Unresolved UDP packet, return buffer to the pool - pool.Put(buf) + if put != nil { + put() + } return } target := socks5.ParseAddr(tgtAddr.String()) @@ -71,7 +74,7 @@ func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, ad pc: pc, rAddr: addr, payload: payload, - bufRef: buf, + put: put, } select { case in <- inbound.NewPacket(target, packet, C.SHADOWSOCKS): diff --git a/listener/shadowsocks/utils.go b/listener/shadowsocks/utils.go index 2e9fd003..c34c5cd0 100644 --- a/listener/shadowsocks/utils.go +++ b/listener/shadowsocks/utils.go @@ -6,7 +6,6 @@ import ( "net" "net/url" - "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/transport/socks5" ) @@ -14,7 +13,7 @@ type packet struct { pc net.PacketConn rAddr net.Addr payload []byte - bufRef []byte + put func() } func (c *packet) Data() []byte { @@ -37,7 +36,9 @@ func (c *packet) LocalAddr() net.Addr { } func (c *packet) Drop() { - pool.Put(c.bufRef) + if c.put != nil { + c.put() + } } func (c *packet) InAddr() net.Addr { diff --git a/transport/shadowsocks/core/cipher.go b/transport/shadowsocks/core/cipher.go index 7f4f7f71..cd30360c 100644 --- a/transport/shadowsocks/core/cipher.go +++ b/transport/shadowsocks/core/cipher.go @@ -7,6 +7,7 @@ import ( "sort" "strings" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" ) @@ -21,7 +22,7 @@ type StreamConnCipher interface { } type PacketConnCipher interface { - PacketConn(net.PacketConn) net.PacketConn + PacketConn(N.EnhancePacketConn) N.EnhancePacketConn } // ErrCipherNotSupported occurs when a cipher is not supported (likely because of security concerns). @@ -128,7 +129,7 @@ type AeadCipher struct { } func (aead *AeadCipher) StreamConn(c net.Conn) net.Conn { return shadowaead.NewConn(c, aead) } -func (aead *AeadCipher) PacketConn(c net.PacketConn) net.PacketConn { +func (aead *AeadCipher) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return shadowaead.NewPacketConn(c, aead) } @@ -139,7 +140,7 @@ type StreamCipher struct { } func (ciph *StreamCipher) StreamConn(c net.Conn) net.Conn { return shadowstream.NewConn(c, ciph) } -func (ciph *StreamCipher) PacketConn(c net.PacketConn) net.PacketConn { +func (ciph *StreamCipher) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return shadowstream.NewPacketConn(c, ciph) } @@ -147,8 +148,8 @@ func (ciph *StreamCipher) PacketConn(c net.PacketConn) net.PacketConn { type dummy struct{} -func (dummy) StreamConn(c net.Conn) net.Conn { return c } -func (dummy) PacketConn(c net.PacketConn) net.PacketConn { return c } +func (dummy) StreamConn(c net.Conn) net.Conn { return c } +func (dummy) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return c } // key-derivation function from original Shadowsocks func Kdf(password string, keyLen int) []byte { diff --git a/transport/shadowsocks/shadowaead/packet.go b/transport/shadowsocks/shadowaead/packet.go index 7043ead7..e84ac570 100644 --- a/transport/shadowsocks/shadowaead/packet.go +++ b/transport/shadowsocks/shadowaead/packet.go @@ -6,6 +6,7 @@ import ( "io" "net" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" ) @@ -57,15 +58,15 @@ func Unpack(dst, pkt []byte, ciph Cipher) ([]byte, error) { } type PacketConn struct { - net.PacketConn + N.EnhancePacketConn Cipher } const maxPacketSize = 64 * 1024 -// NewPacketConn wraps a net.PacketConn with cipher -func NewPacketConn(c net.PacketConn, ciph Cipher) *PacketConn { - return &PacketConn{PacketConn: c, Cipher: ciph} +// NewPacketConn wraps an N.EnhancePacketConn with cipher +func NewPacketConn(c N.EnhancePacketConn, ciph Cipher) *PacketConn { + return &PacketConn{EnhancePacketConn: c, Cipher: ciph} } // WriteTo encrypts b and write to addr using the embedded PacketConn. @@ -76,13 +77,13 @@ func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { if err != nil { return 0, err } - _, err = c.PacketConn.WriteTo(buf, addr) + _, err = c.EnhancePacketConn.WriteTo(buf, addr) return len(b), err } // ReadFrom reads from the embedded PacketConn and decrypts into b. func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, addr, err := c.PacketConn.ReadFrom(b) + n, addr, err := c.EnhancePacketConn.ReadFrom(b) if err != nil { return n, addr, err } @@ -93,3 +94,20 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { copy(b, bb) return len(bb), addr, err } + +func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, addr, err = c.EnhancePacketConn.WaitReadFrom() + if err != nil { + return + } + data, err = Unpack(data[c.Cipher.SaltSize():], data, c) + if err != nil { + if put != nil { + put() + } + data = nil + put = nil + return + } + return +} diff --git a/transport/shadowsocks/shadowstream/packet.go b/transport/shadowsocks/shadowstream/packet.go index 0b46dea1..f0bf43ef 100644 --- a/transport/shadowsocks/shadowstream/packet.go +++ b/transport/shadowsocks/shadowstream/packet.go @@ -6,6 +6,7 @@ import ( "io" "net" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" ) @@ -43,13 +44,13 @@ func Unpack(dst, pkt []byte, s Cipher) ([]byte, error) { } type PacketConn struct { - net.PacketConn + N.EnhancePacketConn Cipher } -// NewPacketConn wraps a net.PacketConn with stream cipher encryption/decryption. -func NewPacketConn(c net.PacketConn, ciph Cipher) *PacketConn { - return &PacketConn{PacketConn: c, Cipher: ciph} +// NewPacketConn wraps an N.EnhancePacketConn with stream cipher encryption/decryption. +func NewPacketConn(c N.EnhancePacketConn, ciph Cipher) *PacketConn { + return &PacketConn{EnhancePacketConn: c, Cipher: ciph} } const maxPacketSize = 64 * 1024 @@ -61,12 +62,12 @@ func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { if err != nil { return 0, err } - _, err = c.PacketConn.WriteTo(buf, addr) + _, err = c.EnhancePacketConn.WriteTo(buf, addr) return len(b), err } func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, addr, err := c.PacketConn.ReadFrom(b) + n, addr, err := c.EnhancePacketConn.ReadFrom(b) if err != nil { return n, addr, err } @@ -77,3 +78,20 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { copy(b, bb) return len(bb), addr, err } + +func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, addr, err = c.EnhancePacketConn.WaitReadFrom() + if err != nil { + return + } + data, err = Unpack(data[c.IVSize():], data, c) + if err != nil { + if put != nil { + put() + } + data = nil + put = nil + return + } + return +} diff --git a/transport/ssr/protocol/auth_aes128_sha1.go b/transport/ssr/protocol/auth_aes128_sha1.go index 4de48151..e2f0e143 100644 --- a/transport/ssr/protocol/auth_aes128_sha1.go +++ b/transport/ssr/protocol/auth_aes128_sha1.go @@ -8,6 +8,7 @@ import ( "strconv" "strings" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/ssr/tools" @@ -82,13 +83,13 @@ func (a *authAES128) StreamConn(c net.Conn, iv []byte) net.Conn { return &Conn{Conn: c, Protocol: p} } -func (a *authAES128) PacketConn(c net.PacketConn) net.PacketConn { +func (a *authAES128) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { p := &authAES128{ Base: a.Base, authAES128Function: a.authAES128Function, userData: a.userData, } - return &PacketConn{PacketConn: c, Protocol: p} + return &PacketConn{EnhancePacketConn: c, Protocol: p} } func (a *authAES128) Decode(dst, src *bytes.Buffer) error { diff --git a/transport/ssr/protocol/auth_chain_a.go b/transport/ssr/protocol/auth_chain_a.go index 6b12ab9b..23efb390 100644 --- a/transport/ssr/protocol/auth_chain_a.go +++ b/transport/ssr/protocol/auth_chain_a.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/shadowsocks/core" @@ -83,13 +84,13 @@ func (a *authChainA) StreamConn(c net.Conn, iv []byte) net.Conn { return &Conn{Conn: c, Protocol: p} } -func (a *authChainA) PacketConn(c net.PacketConn) net.PacketConn { +func (a *authChainA) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { p := &authChainA{ Base: a.Base, salt: a.salt, userData: a.userData, } - return &PacketConn{PacketConn: c, Protocol: p} + return &PacketConn{EnhancePacketConn: c, Protocol: p} } func (a *authChainA) Decode(dst, src *bytes.Buffer) error { diff --git a/transport/ssr/protocol/auth_sha1_v4.go b/transport/ssr/protocol/auth_sha1_v4.go index 9e814ac2..26039181 100644 --- a/transport/ssr/protocol/auth_sha1_v4.go +++ b/transport/ssr/protocol/auth_sha1_v4.go @@ -7,6 +7,7 @@ import ( "hash/crc32" "net" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" "github.com/Dreamacro/clash/transport/ssr/tools" @@ -35,7 +36,7 @@ func (a *authSHA1V4) StreamConn(c net.Conn, iv []byte) net.Conn { return &Conn{Conn: c, Protocol: p} } -func (a *authSHA1V4) PacketConn(c net.PacketConn) net.PacketConn { +func (a *authSHA1V4) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return c } diff --git a/transport/ssr/protocol/origin.go b/transport/ssr/protocol/origin.go index 80fdfa9a..52525a2f 100644 --- a/transport/ssr/protocol/origin.go +++ b/transport/ssr/protocol/origin.go @@ -3,6 +3,8 @@ package protocol import ( "bytes" "net" + + N "github.com/Dreamacro/clash/common/net" ) type origin struct{} @@ -13,7 +15,7 @@ func newOrigin(b *Base) Protocol { return &origin{} } func (o *origin) StreamConn(c net.Conn, iv []byte) net.Conn { return c } -func (o *origin) PacketConn(c net.PacketConn) net.PacketConn { return c } +func (o *origin) PacketConn(c N.EnhancePacketConn) N.EnhancePacketConn { return c } func (o *origin) Decode(dst, src *bytes.Buffer) error { dst.ReadFrom(src) diff --git a/transport/ssr/protocol/packet.go b/transport/ssr/protocol/packet.go index 249db70a..988ff75d 100644 --- a/transport/ssr/protocol/packet.go +++ b/transport/ssr/protocol/packet.go @@ -3,11 +3,12 @@ package protocol import ( "net" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" ) type PacketConn struct { - net.PacketConn + N.EnhancePacketConn Protocol } @@ -18,12 +19,12 @@ func (c *PacketConn) WriteTo(b []byte, addr net.Addr) (int, error) { if err != nil { return 0, err } - _, err = c.PacketConn.WriteTo(buf.Bytes(), addr) + _, err = c.EnhancePacketConn.WriteTo(buf.Bytes(), addr) return len(b), err } func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { - n, addr, err := c.PacketConn.ReadFrom(b) + n, addr, err := c.EnhancePacketConn.ReadFrom(b) if err != nil { return n, addr, err } @@ -34,3 +35,20 @@ func (c *PacketConn) ReadFrom(b []byte) (int, net.Addr, error) { copy(b, decoded) return len(decoded), addr, nil } + +func (c *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { + data, put, addr, err = c.EnhancePacketConn.WaitReadFrom() + if err != nil { + return + } + data, err = c.DecodePacket(data) + if err != nil { + if put != nil { + put() + } + data = nil + put = nil + return + } + return +} diff --git a/transport/ssr/protocol/protocol.go b/transport/ssr/protocol/protocol.go index 5b86ecb9..1c27da48 100644 --- a/transport/ssr/protocol/protocol.go +++ b/transport/ssr/protocol/protocol.go @@ -6,6 +6,8 @@ import ( "fmt" "net" + N "github.com/Dreamacro/clash/common/net" + "github.com/zhangyunhao116/fastrand" ) @@ -22,7 +24,7 @@ var ( type Protocol interface { StreamConn(net.Conn, []byte) net.Conn - PacketConn(net.PacketConn) net.PacketConn + PacketConn(N.EnhancePacketConn) N.EnhancePacketConn Decode(dst, src *bytes.Buffer) error Encode(buf *bytes.Buffer, b []byte) error DecodePacket([]byte) ([]byte, error) diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index d37026c1..abe21f34 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -370,7 +370,9 @@ func (pc *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, er _, err = io.ReadFull(pc.Conn, data[:2+2]) // u16be length + CR LF if err != nil { - put() + if put != nil { + put() + } return nil, nil, nil, err } length := binary.BigEndian.Uint16(data) @@ -379,11 +381,15 @@ func (pc *PacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, er data = data[:length] _, err = io.ReadFull(pc.Conn, data) if err != nil { - put() + if put != nil { + put() + } return nil, nil, nil, err } } else { - put() + if put != nil { + put() + } return nil, nil, addr, nil } diff --git a/transport/tuic/conn.go b/transport/tuic/conn.go index d46a3556..f226746d 100644 --- a/transport/tuic/conn.go +++ b/transport/tuic/conn.go @@ -205,7 +205,6 @@ func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net return } data = packet.DATA - put = N.NilPut addr = packet.ADDR.UDPAddr() } else { err = net.ErrClosed From 36539bb6705a213c3b75b59a1c8474c965ec2eee Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 30 May 2023 07:59:55 +0800 Subject: [PATCH 301/530] fix: sing-ss2's Reader not set buffer end --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index b203dd40..864f6121 100644 --- a/go.mod +++ b/go.mod @@ -22,7 +22,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 github.com/metacubex/sing-shadowsocks v0.2.2-0.20230509230448-a5157cc00a1c - github.com/metacubex/sing-shadowsocks2 v0.0.0-20230528144023-05418c94ed2d + github.com/metacubex/sing-shadowsocks2 v0.0.0-20230529235701-a238874242ca github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376 github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a github.com/miekg/dns v1.1.54 diff --git a/go.sum b/go.sum index 25448530..75975620 100644 --- a/go.sum +++ b/go.sum @@ -100,8 +100,8 @@ github.com/metacubex/sing v0.0.0-20230526162852-6afe73474070 h1:AT/Qfe9MvCxyrI9u github.com/metacubex/sing v0.0.0-20230526162852-6afe73474070/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-20230528144023-05418c94ed2d h1:lWbWl3pZA1x8TgYDw07jo1u5RtbBRIlxuJDV4FW0WeQ= -github.com/metacubex/sing-shadowsocks2 v0.0.0-20230528144023-05418c94ed2d/go.mod h1:jVDD4N22bDPPKA73NvB7aqdlLWiAwv8D+jx7HwhcWak= +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.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= github.com/metacubex/sing-vmess v0.1.5-0.20230520082358-78b126617899 h1:iRfcuztp7REfmOyasSlCL/pqNWfUDMTJ2CwbGpxpeks= From 41af94ea66c2e9a4c347d70b4e63784bc79201ae Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 30 May 2023 20:21:51 +0800 Subject: [PATCH 302/530] fix: deadline reader cause panic --- common/net/deadline/packet_sing.go | 11 ++++------- go.mod | 4 ++-- go.sum | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/common/net/deadline/packet_sing.go b/common/net/deadline/packet_sing.go index a3da34f4..f41f3f5b 100644 --- a/common/net/deadline/packet_sing.go +++ b/common/net/deadline/packet_sing.go @@ -53,9 +53,7 @@ FOR: if result, ok := result.(*singReadResult); ok { destination = result.destination err = result.err - buffer.Resize(result.buffer.Start(), 0) - n := copy(buffer.FreeBytes(), result.buffer.Bytes()) - buffer.Truncate(n) + n, _ := buffer.Write(result.buffer.Bytes()) result.buffer.Advance(n) if result.buffer.IsEmpty() { result.buffer.Release() @@ -85,14 +83,13 @@ FOR: } <-c.netPacketConn.resultCh - go c.pipeReadPacket(buffer.Cap(), buffer.Start()) + go c.pipeReadPacket(buffer.FreeLen()) return c.ReadPacket(buffer) } -func (c *singPacketConn) pipeReadPacket(bufLen int, bufStart int) { - buffer := buf.NewSize(bufLen) - buffer.Advance(bufStart) +func (c *singPacketConn) pipeReadPacket(pLen int) { + buffer := buf.NewSize(pLen) destination, err := c.singPacketConn.ReadPacket(buffer) result := &singReadResult{} result.destination = destination diff --git a/go.mod b/go.mod index 864f6121..3cafaabe 100644 --- a/go.mod +++ b/go.mod @@ -30,7 +30,7 @@ require ( 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.20230519030052-49166ac42700 + 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-vmess v0.1.5-0.20230417103030-8c3070ae3fb3 @@ -105,6 +105,6 @@ require ( golang.org/x/tools v0.6.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230526162852-6afe73474070 +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 diff --git a/go.sum b/go.sum index 75975620..49d31b80 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/metacubex/gvisor v0.0.0-20230417114019-3c3ee672d60c h1:D62872jiuzC6b+ 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/sing v0.0.0-20230526162852-6afe73474070 h1:AT/Qfe9MvCxyrI9uybcXcVDLDEqR6+9ZK7a7pgis9xQ= -github.com/metacubex/sing v0.0.0-20230526162852-6afe73474070/go.mod h1:Ta8nHnDLAwqySzKhGoKk4ZIB+vJ3GTKj7UPrWYvM+4w= +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= From 1120c8185d11c884cab88b61ca8c9412a4080f19 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Tue, 30 May 2023 20:52:28 +0800 Subject: [PATCH 303/530] chore: Use API to create windows firewall rule --- adapter/outbound/wireguard.go | 2 +- go.mod | 9 +++++---- go.sum | 19 ++++++++++--------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 38b5aa02..c12321f3 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -67,7 +67,7 @@ type WireGuardPeerOption struct { PublicKey string `proxy:"public-key,omitempty"` PreSharedKey string `proxy:"pre-shared-key,omitempty"` Reserved []uint8 `proxy:"reserved,omitempty"` - AllowedIPs []string `proxy:"allowed_ips,omitempty"` + AllowedIPs []string `proxy:"allowed-ips,omitempty"` } type wgSingDialer struct { diff --git a/go.mod b/go.mod index 3cafaabe..b79f8e70 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/quic-go v0.33.3-0.20230510010206-687b537b6a58 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.20230509224930-30065d4b6376 + github.com/metacubex/sing-tun v0.1.5-0.20230530125750-171afb2dfd8e github.com/metacubex/sing-wireguard v0.0.0-20230426030325-41db09ae771a github.com/miekg/dns v1.1.54 github.com/mroth/weightedrand/v2 v2.0.1 @@ -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 @@ -89,6 +89,7 @@ require ( github.com/quic-go/qtls-go1-20 v0.1.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 github.com/shoenig/go-m1cpu v0.1.5 // indirect github.com/sina-ghaderi/poly1305 v0.0.0-20220724002748-c5926b03988b // indirect github.com/sina-ghaderi/rabaead v0.0.0-20220730151906-ab6e06b96e8c // indirect @@ -96,12 +97,12 @@ require ( 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/vishvananda/netns v0.0.4 // indirect github.com/yusufpapurcu/wmi v1.2.2 // 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.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 49d31b80..11d98c03 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= @@ -102,8 +102,8 @@ 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.20230509224930-30065d4b6376 h1:zKNsbFQyleMFAP7NJYRew9sEMJuniuODH3V0FdWnEtk= -github.com/metacubex/sing-tun v0.1.5-0.20230509224930-30065d4b6376/go.mod h1:BMfG00enVf90/CzcdX9PK3Dymgl7BZqHXJfexEyB7Cc= +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-wireguard v0.0.0-20230426030325-41db09ae771a h1:cWKym33Qvl6HA3hj4/YuYD8hHyqQPb47wT5cJRAPgco= @@ -159,6 +159,8 @@ 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/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= @@ -190,8 +192,8 @@ 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/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/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1YX8= +github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= 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= @@ -230,7 +232,6 @@ 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= @@ -247,8 +248,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 7fa3d3aa0b8111f3f9c9305d1245b67f700f7737 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 1 Jun 2023 12:36:53 +0800 Subject: [PATCH 304/530] chore: cleanup system dns code --- dns/system.go | 22 +++---------------- dns/system_posix.go | 27 +++++++++++++++++++++++ dns/system_windows.go | 51 +++++++++++-------------------------------- 3 files changed, 43 insertions(+), 57 deletions(-) create mode 100644 dns/system_posix.go diff --git a/dns/system.go b/dns/system.go index 2e52f90f..f5ab0efb 100644 --- a/dns/system.go +++ b/dns/system.go @@ -1,37 +1,21 @@ -//go:build !windows - package dns import ( - "fmt" - "os" - "regexp" -) - -var ( - // nameserver xxx.xxx.xxx.xxx - nameserverPattern = regexp.MustCompile(`nameserver\s+(?P\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`) + "net" ) func loadSystemResolver() (clients []dnsClient, err error) { - content, err := os.ReadFile("/etc/resolv.conf") + nameservers, err := dnsReadConfig() if err != nil { - err = fmt.Errorf("failed to read /etc/resolv.conf: %w", err) return } - nameservers := make([]string, 0) - for _, line := range nameserverPattern.FindAllStringSubmatch(string(content), -1) { - addr := line[1] - nameservers = append(nameservers, addr) - } if len(nameservers) == 0 { - err = fmt.Errorf("no nameserver found in /etc/resolv.conf") return } servers := make([]NameServer, 0, len(nameservers)) for _, addr := range nameservers { servers = append(servers, NameServer{ - Addr: fmt.Sprintf("%s:%d", addr, 53), + Addr: net.JoinHostPort(addr, "53"), Net: "udp", }) } diff --git a/dns/system_posix.go b/dns/system_posix.go new file mode 100644 index 00000000..d486b4fb --- /dev/null +++ b/dns/system_posix.go @@ -0,0 +1,27 @@ +//go:build !windows + +package dns + +import ( + "fmt" + "os" + "regexp" +) + +var ( + // nameserver xxx.xxx.xxx.xxx + nameserverPattern = regexp.MustCompile(`nameserver\s+(?P\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})`) +) + +func dnsReadConfig() (servers []string, err error) { + content, err := os.ReadFile("/etc/resolv.conf") + if err != nil { + err = fmt.Errorf("failed to read /etc/resolv.conf: %w", err) + return + } + for _, line := range nameserverPattern.FindAllStringSubmatch(string(content), -1) { + addr := line[1] + servers = append(servers, addr) + } + return +} diff --git a/dns/system_windows.go b/dns/system_windows.go index 2e0aa237..47c1ebaa 100644 --- a/dns/system_windows.go +++ b/dns/system_windows.go @@ -3,7 +3,6 @@ package dns import ( - "fmt" "net" "os" "syscall" @@ -12,34 +11,10 @@ import ( "golang.org/x/sys/windows" ) -type dnsConfig struct { - servers []string // server addresses (in host:port form) to use -} - -func loadSystemResolver() (clients []dnsClient, err error) { - content, err := dnsReadConfig() - if err != nil { - err = fmt.Errorf("failed to read system DNS: %w", err) - } - nameservers := content.servers - if len(nameservers) == 0 { - return - } - servers := make([]NameServer, 0, len(nameservers)) - for _, addr := range nameservers { - servers = append(servers, NameServer{ - Addr: addr, - Net: "udp", - }) - } - return transform(servers, nil), nil -} - -func dnsReadConfig() (conf *dnsConfig, err error) { - conf = &dnsConfig{} +func dnsReadConfig() (servers []string, err error) { aas, err := adapterAddresses() if err != nil { - return conf, err + return } for _, aa := range aas { for dns := aa.FirstDnsServerAddress; dns != nil; dns = dns.Next { @@ -52,23 +27,23 @@ func dnsReadConfig() (conf *dnsConfig, err error) { case *syscall.SockaddrInet4: ip = net.IPv4(sa.Addr[0], sa.Addr[1], sa.Addr[2], sa.Addr[3]) case *syscall.SockaddrInet6: - //ip = make(net.IP, net.IPv6len) - //copy(ip, sa.Addr[:]) - //if ip[0] == 0xfe && ip[1] == 0xc0 { - // // Ignore these fec0/10 ones. Windows seems to - // // populate them as defaults on its misc rando - // // interfaces. - // continue - //} - continue + ip = make(net.IP, net.IPv6len) + copy(ip, sa.Addr[:]) + if ip[0] == 0xfe && ip[1] == 0xc0 { + // Ignore these fec0/10 ones. Windows seems to + // populate them as defaults on its misc rando + // interfaces. + continue + } + //continue default: // Unexpected type. continue } - conf.servers = append(conf.servers, net.JoinHostPort(ip.String(), "53")) + servers = append(servers, ip.String()) } } - return conf, nil + return } // adapterAddresses returns a list of IP adapter and address From 9b6e56a65e99c9636fea62dfb1b78d5521072b37 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 1 Jun 2023 16:25:02 +0800 Subject: [PATCH 305/530] 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 306/530] 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 307/530] 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 308/530] 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 309/530] 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 310/530] 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 311/530] 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 312/530] 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 313/530] [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 314/530] 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 315/530] 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 316/530] 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 317/530] 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 318/530] 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 319/530] 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 320/530] 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 321/530] 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 322/530] 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 323/530] 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 324/530] 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 325/530] 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 326/530] 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 327/530] 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 328/530] 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 329/530] 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 330/530] 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 331/530] 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 332/530] 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 333/530] 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 334/530] 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 335/530] 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 336/530] 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 337/530] 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 338/530] 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 339/530] 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 340/530] 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 341/530] 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 342/530] 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 343/530] 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 344/530] 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 345/530] 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 346/530] 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 347/530] 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 348/530] 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 349/530] 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 350/530] 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 351/530] 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 352/530] 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 353/530] 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 354/530] 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 355/530] 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 356/530] 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 357/530] 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 358/530] 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 359/530] 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 360/530] 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 361/530] 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 362/530] 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 363/530] 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 364/530] 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 365/530] 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 366/530] 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 367/530] 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 368/530] 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 369/530] 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 370/530] 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 371/530] 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 372/530] 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 373/530] 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 374/530] 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 375/530] 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 376/530] 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 377/530] 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 378/530] 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 379/530] 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 380/530] 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 381/530] 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 382/530] 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 383/530] 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= From f89ecd97d60fff44285a2de8e3742c0b560fb9c3 Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 14 Aug 2023 15:11:33 +0800 Subject: [PATCH 384/530] feat: Converter unofficial TUIC share link support --- common/convert/converter.go | 41 +++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/common/convert/converter.go b/common/convert/converter.go index b67918db..1f1b086d 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -67,6 +67,47 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { proxies = append(proxies, hysteria) + case "tuic": + // A temporary unofficial TUIC share link standard + // Modified from https://github.com/daeuniverse/dae/discussions/182 + // Changes: + // 1. Support TUICv4, just replace uuid:password with token + // 2. Remove `allow_insecure` field + urlTUIC, err := url.Parse(line) + if err != nil { + continue + } + query := urlTUIC.Query() + + tuic := make(map[string]any, 20) + tuic["name"] = uniqueName(names, urlTUIC.Fragment) + tuic["type"] = scheme + tuic["server"] = urlTUIC.Hostname() + tuic["port"] = urlTUIC.Port() + tuic["udp"] = true + password, v5 := urlTUIC.User.Password() + if v5 { + tuic["uuid"] = urlTUIC.User.Username() + tuic["password"] = password + } else { + tuic["token"] = urlTUIC.User.Username() + } + if cc := query.Get("congestion_control"); cc != "" { + tuic["congestion-controller"] = cc + } + if alpn := query.Get("alpn"); alpn != "" { + tuic["alpn"] = strings.Split(alpn, ",") + } + if sni := query.Get("sni"); sni != "" { + tuic["sni"] = sni + } + if query.Get("disable_sni") == "1" { + tuic["disable-sni"] = true + } + if udpRelayMode := query.Get("udp_relay_mode"); udpRelayMode != "" { + tuic["udp-relay-mode"] = udpRelayMode + } + case "trojan": urlTrojan, err := url.Parse(line) if err != nil { From ed09df4e133ec355c8c01bdfc68f453fce2ea9f7 Mon Sep 17 00:00:00 2001 From: H1JK Date: Mon, 14 Aug 2023 15:48:13 +0800 Subject: [PATCH 385/530] fix: TLS ALPN support --- adapter/outbound/vless.go | 2 ++ adapter/outbound/vmess.go | 3 +++ common/buf/sing.go | 7 ------- common/convert/converter.go | 14 +++++++++++--- common/convert/v.go | 5 +++-- transport/gun/utils.go | 26 +++++++++++++++++++++----- 6 files changed, 40 insertions(+), 17 deletions(-) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 83ce4e57..2456c2c3 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -57,6 +57,7 @@ type VlessOption struct { UUID string `proxy:"uuid"` Flow string `proxy:"flow,omitempty"` TLS bool `proxy:"tls,omitempty"` + ALPN []string `proxy:"alpn,omitempty"` UDP bool `proxy:"udp,omitempty"` PacketAddr bool `proxy:"packet-addr,omitempty"` XUDP bool `proxy:"xudp,omitempty"` @@ -211,6 +212,7 @@ func (v *Vless) streamTLSConn(ctx context.Context, conn net.Conn, isH2 bool) (ne FingerPrint: v.option.Fingerprint, ClientFingerprint: v.option.ClientFingerprint, Reality: v.realityConfig, + NextProtos: v.option.ALPN, } if isH2 { diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 8a94c082..7495d8a3 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -52,6 +52,7 @@ type VmessOption struct { UDP bool `proxy:"udp,omitempty"` Network string `proxy:"network,omitempty"` TLS bool `proxy:"tls,omitempty"` + ALPN []string `proxy:"alpn,omitempty"` SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` Fingerprint string `proxy:"fingerprint,omitempty"` ServerName string `proxy:"servername,omitempty"` @@ -149,6 +150,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M SkipCertVerify: v.option.SkipCertVerify, ClientFingerprint: v.option.ClientFingerprint, Reality: v.realityConfig, + NextProtos: v.option.ALPN, } if v.option.ServerName != "" { @@ -205,6 +207,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M SkipCertVerify: v.option.SkipCertVerify, ClientFingerprint: v.option.ClientFingerprint, Reality: v.realityConfig, + NextProtos: v.option.ALPN, } if v.option.ServerName != "" { diff --git a/common/buf/sing.go b/common/buf/sing.go index 4585bf74..d204ba11 100644 --- a/common/buf/sing.go +++ b/common/buf/sing.go @@ -14,13 +14,6 @@ var NewSize = buf.NewSize var With = buf.With var As = buf.As -var KeepAlive = common.KeepAlive - -//go:norace -func Dup[T any](obj T) T { - return common.Dup(obj) -} - var ( Must = common.Must Error = common.Error diff --git a/common/convert/converter.go b/common/convert/converter.go index 1f1b086d..ddc5c944 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -50,7 +50,9 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { hysteria["port"] = urlHysteria.Port() hysteria["sni"] = query.Get("peer") hysteria["obfs"] = query.Get("obfs") - hysteria["alpn"] = []string{query.Get("alpn")} + if alpn := query.Get("alpn"); alpn != "" { + hysteria["alpn"] = strings.Split(alpn, ",") + } hysteria["auth_str"] = query.Get("auth") hysteria["protocol"] = query.Get("protocol") up := query.Get("up") @@ -127,10 +129,12 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { trojan["udp"] = true trojan["skip-cert-verify"], _ = strconv.ParseBool(query.Get("allowInsecure")) - sni := query.Get("sni") - if sni != "" { + if sni := query.Get("sni"); sni != "" { trojan["sni"] = sni } + if alpn := query.Get("alpn"); alpn != "" { + trojan["alpn"] = strings.Split(alpn, ",") + } network := strings.ToLower(query.Get("type")) if network != "" { @@ -258,6 +262,9 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { if strings.HasSuffix(tls, "tls") { vmess["tls"] = true } + if alpn, ok := values["alpn"].(string); ok { + vmess["alpn"] = strings.Split(alpn, ",") + } } switch network { @@ -373,6 +380,7 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { } } proxies = append(proxies, ss) + case "ssr": dcBuf, err := encRaw.DecodeString(body) if err != nil { diff --git a/common/convert/v.go b/common/convert/v.go index 23949aab..2d8cf732 100644 --- a/common/convert/v.go +++ b/common/convert/v.go @@ -24,8 +24,6 @@ func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy m proxy["port"] = url.Port() proxy["uuid"] = url.User.Username() proxy["udp"] = true - proxy["skip-cert-verify"] = false - proxy["tls"] = false tls := strings.ToLower(query.Get("security")) if strings.HasSuffix(tls, "tls") || tls == "reality" { proxy["tls"] = true @@ -34,6 +32,9 @@ func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy m } else { proxy["client-fingerprint"] = fingerprint } + if alpn := query.Get("alpn"); alpn != "" { + proxy["alpn"] = strings.Split(alpn, ",") + } } if sni := query.Get("sni"); sni != "" { proxy["servername"] = sni diff --git a/transport/gun/utils.go b/transport/gun/utils.go index e5f6e019..e4a66315 100644 --- a/transport/gun/utils.go +++ b/transport/gun/utils.go @@ -1,10 +1,26 @@ package gun func UVarintLen(x uint64) int { - i := 0 - for x >= 0x80 { - x >>= 7 - i++ + switch { + case x < 1<<(7*1): + return 1 + case x < 1<<(7*2): + return 2 + case x < 1<<(7*3): + return 3 + case x < 1<<(7*4): + return 4 + case x < 1<<(7*5): + return 5 + case x < 1<<(7*6): + return 6 + case x < 1<<(7*7): + return 7 + case x < 1<<(7*8): + return 8 + case x < 1<<(7*9): + return 9 + default: + return 10 } - return i + 1 } From 03b02525897e5f06990a8677a86c2546ae3045f2 Mon Sep 17 00:00:00 2001 From: 3andne <52860475+3andne@users.noreply.github.com> Date: Tue, 15 Aug 2023 20:41:58 -0700 Subject: [PATCH 386/530] feat: bump restls to v0.1.6 (utls v1.4.3) (#692) * feat: bump restls to v0.1.5 (utls v1.4.3) * fix: rm dependency go-quic --- adapter/outbound/shadowsocks.go | 3 +-- go.mod | 5 +++-- go.sum | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index c1481622..0f46cf79 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -19,7 +19,7 @@ import ( v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" restlsC "github.com/3andne/restls-client-go" - "github.com/metacubex/sing-shadowsocks2" + shadowsocks "github.com/metacubex/sing-shadowsocks2" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/uot" ) @@ -294,7 +294,6 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } restlsConfig, err = restlsC.NewRestlsConfig(restlsOpt.Host, restlsOpt.Password, restlsOpt.VersionHint, restlsOpt.RestlsScript, option.ClientFingerprint) - restlsConfig.SessionTicketsDisabled = true if err != nil { return nil, fmt.Errorf("ss %s initialize restls-plugin error: %w", addr, err) } diff --git a/go.mod b/go.mod index 3167d9ea..9f8da5a4 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/Dreamacro/clash go 1.20 require ( - github.com/3andne/restls-client-go v0.1.4 + github.com/3andne/restls-client-go v0.1.6 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da github.com/cilium/ebpf v0.11.0 github.com/coreos/go-iptables v0.7.0 @@ -64,6 +64,7 @@ require ( github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/golang/mock v1.6.0 // indirect @@ -72,7 +73,7 @@ require ( github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect github.com/hashicorp/yamux v0.1.1 // indirect github.com/josharian/native v1.1.0 // indirect - github.com/klauspost/compress v1.15.15 // indirect + github.com/klauspost/compress v1.16.7 // 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-20230611153922-78842f086475 // indirect diff --git a/go.sum b/go.sum index a90f4dba..63d633e1 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,5 @@ -github.com/3andne/restls-client-go v0.1.4 h1:kLNC2aSRHPlEVYmTj6EOqJoorCpobEe2toMRSfBF7FU= -github.com/3andne/restls-client-go v0.1.4/go.mod h1:04CGbRk1BwBiEDles8b5mlKgTqIwE5MqF7JDloJV47I= +github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08= +github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY= github.com/RyuaNerin/go-krypto v1.0.2 h1:9KiZrrBs+tDrQ66dNy4nrX6SzntKtSKdm0wKHhdB4WM= github.com/RyuaNerin/go-krypto v1.0.2/go.mod h1:17LzMeJCgzGTkPH3TmfzRnEJ/yA7ErhTPp9sxIqONtA= github.com/Yawning/aez v0.0.0-20211027044916-e49e68abd344 h1:cDVUiFo+npB0ZASqnw4q90ylaVAbnYyx0JYqK4YcGok= @@ -35,6 +35,8 @@ 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/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= +github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= 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= @@ -74,8 +76,8 @@ github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtL github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w= github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA= 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/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 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= From 574efb4526bd518c12236840238c39041fec286d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 16 Aug 2023 21:30:12 +0800 Subject: [PATCH 387/530] chore: Update dependencies --- adapter/outbound/wireguard.go | 2 +- go.mod | 14 +++++++------- go.sum | 25 ++++++++++++------------- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index e6738596..c1050ac6 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -302,7 +302,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { if err != nil { return nil, E.Cause(err, "create WireGuard device") } - outbound.device = device.NewDevice(outbound.tunDevice, outbound.bind, &device.Logger{ + outbound.device = device.NewDevice(context.Background(), outbound.tunDevice, outbound.bind, &device.Logger{ Verbosef: func(format string, args ...interface{}) { log.SingLogger.Debug(fmt.Sprintf("[WG](%s) %s", option.Name, fmt.Sprintf(format, args...))) }, diff --git a/go.mod b/go.mod index 9f8da5a4..15babf72 100644 --- a/go.mod +++ b/go.mod @@ -26,16 +26,16 @@ 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.2 + github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.9 - github.com/sagernet/sing-mux v0.1.2 + github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a + github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9 + github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 - github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 + github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f github.com/samber/lo v1.38.1 github.com/shirou/gopsutil/v3 v3.23.7 github.com/sirupsen/logrus v1.9.3 @@ -44,7 +44,7 @@ require ( go.etcd.io/bbolt v1.3.7 go.uber.org/automaxprocs v1.5.3 golang.org/x/crypto v0.12.0 - golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b + golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb golang.org/x/net v0.14.0 golang.org/x/sync v0.3.0 golang.org/x/sys v0.11.0 @@ -103,4 +103,4 @@ require ( golang.org/x/tools v0.9.1 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230714010500-e24664dc75a7 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230816132220-60e73ba2f50f diff --git a/go.sum b/go.sum index 63d633e1..a1c16de2 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ 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.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 v0.0.0-20230816132220-60e73ba2f50f h1:rtZaKvzyfIDCciywrYP2mWN3fVL409xfU/VIVddnTbg= +github.com/metacubex/sing v0.0.0-20230816132220-60e73ba2f50f/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= 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= @@ -110,8 +110,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.2 h1:A8wJRUBcfguGl6oOQHI8fy5P4ViGRT9hdQdlG/7RiXo= -github.com/mroth/weightedrand/v2 v2.0.2/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= +github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= +github.com/mroth/weightedrand/v2 v2.1.0/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= @@ -141,18 +141,18 @@ 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.2 h1:av2/m6e+Gh+ECTuJZqYCjJz55BNkot0VyRMkREqyF/g= -github.com/sagernet/sing-mux v0.1.2/go.mod h1:r2V8AlOzXaRCHXK7fILCUGzuI2iILweTaG8C5xlpHxo= +github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c h1:35/FowAvt3Z62mck0TXzVc4jS5R5CWq62qcV2P1cp0I= +github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY= 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= -github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= +github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGVnWH5A8eR7JhNnIV3rGQmBxA7cw6Q= +github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= -github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo= -github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0= +github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho= +github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk= 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= @@ -207,8 +207,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.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/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= +golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/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= @@ -239,7 +239,6 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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/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= From db68d55a0eaf24664ec8853918bf3d2ddf6623f5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 17 Aug 2023 22:33:07 +0800 Subject: [PATCH 388/530] fix: sing-vmess panic --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 15babf72..6fe21a39 100644 --- a/go.mod +++ b/go.mod @@ -103,4 +103,4 @@ require ( golang.org/x/tools v0.9.1 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230816132220-60e73ba2f50f +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579 diff --git a/go.sum b/go.sum index a1c16de2..07e0bacd 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ 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.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-20230816132220-60e73ba2f50f h1:rtZaKvzyfIDCciywrYP2mWN3fVL409xfU/VIVddnTbg= -github.com/metacubex/sing v0.0.0-20230816132220-60e73ba2f50f/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= +github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579 h1:dE1dBB6CTzNdSMFTE5OCHvzHLewiqiA1nhD+7egtvAc= +github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= 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= From b8a60261efb2ebe9f5a1df95f52e9669aa20e28c Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 18 Aug 2023 22:17:07 +0800 Subject: [PATCH 389/530] chore: restore unselected clear selected node in outboundgoup/URLtest when getGroupDelay triggered --- hub/route/groups.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/hub/route/groups.go b/hub/route/groups.go index e5b61fb5..c82207f0 100644 --- a/hub/route/groups.go +++ b/hub/route/groups.go @@ -9,6 +9,7 @@ import ( "time" "github.com/Dreamacro/clash/adapter" + "github.com/Dreamacro/clash/adapter/outboundgroup" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/tunnel" @@ -57,6 +58,11 @@ func getGroupDelay(w http.ResponseWriter, r *http.Request) { return } + if proxy.(*adapter.Proxy).Type() == C.URLTest { + URLTestGroup := proxy.(*adapter.Proxy).ProxyAdapter.(*outboundgroup.URLTest) + URLTestGroup.ForceSet("") + } + query := r.URL.Query() url := query.Get("url") timeout, err := strconv.ParseInt(query.Get("timeout"), 10, 32) @@ -77,7 +83,6 @@ func getGroupDelay(w http.ResponseWriter, r *http.Request) { defer cancel() dm, err := group.URLTest(ctx, url, expectedStatus) - if err != nil { render.Status(r, http.StatusGatewayTimeout) render.JSON(w, r, newError(err.Error())) From 1181fd456077b68aaa4ffbacef6626f807638bc5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 21 Aug 2023 12:37:39 +0800 Subject: [PATCH 390/530] feat: add `udp-over-stream` for tuic only work with meta tuic server or sing-box 1.4.0-beta.6 --- adapter/outbound/tuic.go | 41 ++++++++++++++++++++++++++++++++++++++++ docs/config.yaml | 5 +++++ listener/sing/sing.go | 29 +++++++++++++++++++++++++++- listener/tuic/server.go | 22 ++++++++++++++++++++- 4 files changed, 95 insertions(+), 2 deletions(-) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index c10a853a..4d826912 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -6,6 +6,7 @@ import ( "crypto/tls" "encoding/hex" "encoding/pem" + "errors" "fmt" "math" "net" @@ -15,12 +16,15 @@ import ( "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" + "github.com/Dreamacro/clash/component/resolver" 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" + M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing/common/uot" ) type Tuic struct { @@ -59,6 +63,9 @@ type TuicOption struct { DisableMTUDiscovery bool `proxy:"disable-mtu-discovery,omitempty"` MaxDatagramFrameSize int `proxy:"max-datagram-frame-size,omitempty"` SNI string `proxy:"sni,omitempty"` + + UDPOverStream bool `proxy:"udp-over-stream,omitempty"` + UDPOverStreamVersion int `proxy:"udp-over-stream-version,omitempty"` } // DialContext implements C.ProxyAdapter @@ -82,6 +89,32 @@ func (t *Tuic) ListenPacketContext(ctx context.Context, metadata *C.Metadata, op // ListenPacketWithDialer implements C.ProxyAdapter func (t *Tuic) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, metadata *C.Metadata) (_ C.PacketConn, err error) { + if t.option.UDPOverStream { + uotDestination := uot.RequestDestination(uint8(t.option.UDPOverStreamVersion)) + uotMetadata := *metadata + uotMetadata.Host = uotDestination.Fqdn + uotMetadata.DstPort = uotDestination.Port + c, err := t.DialContextWithDialer(ctx, dialer, &uotMetadata) + if err != nil { + return nil, err + } + + // tuic uos use stream-oriented udp with a special address, so we need a net.UDPAddr + if !metadata.Resolved() { + ip, err := resolver.ResolveIP(ctx, metadata.Host) + if err != nil { + return nil, errors.New("can't resolve ip") + } + metadata.DstIP = ip + } + + destination := M.SocksaddrFromNet(metadata.UDPAddr()) + if t.option.UDPOverStreamVersion == uot.LegacyVersion { + return newPacketConn(uot.NewConn(c, uot.Request{Destination: destination}), t), nil + } else { + return newPacketConn(uot.NewLazyConn(c, uot.Request{Destination: destination}), t), nil + } + } pc, err := t.client.ListenPacketWithDialer(ctx, metadata, dialer, t.dialWithDialer) if err != nil { return nil, err @@ -239,6 +272,14 @@ func NewTuic(option TuicOption) (*Tuic, error) { tlsConfig.InsecureSkipVerify = true // tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config } + switch option.UDPOverStreamVersion { + case uot.Version, uot.LegacyVersion: + case 0: + option.UDPOverStreamVersion = uot.LegacyVersion + default: + return nil, fmt.Errorf("tuic %s unknown udp over stream protocol version: %d", addr, option.UDPOverStreamVersion) + } + t := &Tuic{ Base: &Base{ name: option.Name, diff --git a/docs/config.yaml b/docs/config.yaml index 6ae3910e..62cd0c58 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -681,6 +681,11 @@ proxies: # socks5 # skip-cert-verify: true # max-open-streams: 20 # default 100, too many open streams may hurt performance # sni: example.com + # + # meta和sing-box私有扩展,将ss-uot用于udp中继,开启此选项后udp-relay-mode将失效 + # 警告,与原版tuic不兼容!!! + # udp-over-stream: false + # udp-over-stream-version: 1 # ShadowsocksR # The supported ciphers (encryption methods): all stream ciphers in ss diff --git a/listener/sing/sing.go b/listener/sing/sing.go index f59fd613..d5731bbf 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -72,7 +72,27 @@ func UpstreamMetadata(metadata M.Metadata) M.Metadata { } } -func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { +func ConvertMetadata(metadata *C.Metadata) M.Metadata { + return M.Metadata{ + Protocol: metadata.Type.String(), + Source: M.SocksaddrFrom(metadata.SrcIP, metadata.SrcPort), + Destination: M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort), + } +} + +func (h *ListenerHandler) IsSpecialFqdn(fqdn string) bool { + switch fqdn { + case mux.Destination.Fqdn: + case vmess.MuxDestination.Fqdn: + case uot.MagicAddress: + case uot.LegacyMagicAddress: + default: + return false + } + return true +} + +func (h *ListenerHandler) ParseSpecialFqdn(ctx context.Context, conn net.Conn, metadata M.Metadata) error { switch metadata.Destination.Fqdn { case mux.Destination.Fqdn: return mux.HandleConnection(ctx, h, log.SingLogger, conn, UpstreamMetadata(metadata)) @@ -89,6 +109,13 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta metadata.Destination = M.Socksaddr{Addr: netip.IPv4Unspecified()} return h.NewPacketConnection(ctx, uot.NewConn(conn, uot.Request{}), metadata) } + return errors.New("not special fqdn") +} + +func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, metadata M.Metadata) error { + if h.IsSpecialFqdn(metadata.Destination.Fqdn) { + return h.ParseSpecialFqdn(ctx, conn, metadata) + } target := socks5.ParseAddr(metadata.Destination.String()) wg := &sync.WaitGroup{} defer wg.Wait() // this goroutine must exit after conn.Close() diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 76996b27..125c53e1 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -1,6 +1,7 @@ package tuic import ( + "context" "crypto/tls" "net" "strings" @@ -11,6 +12,7 @@ import ( "github.com/Dreamacro/clash/common/sockopt" C "github.com/Dreamacro/clash/constant" LC "github.com/Dreamacro/clash/listener/config" + "github.com/Dreamacro/clash/listener/sing" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" "github.com/Dreamacro/clash/transport/tuic" @@ -36,6 +38,12 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet inbound.WithSpecialRules(""), } } + h := &sing.ListenerHandler{ + TcpIn: tcpIn, + UdpIn: udpIn, + Type: C.TUIC, + Additions: additions, + } cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) if err != nil { return nil, err @@ -86,7 +94,19 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet newAdditions = slices.Clone(additions) newAdditions = append(newAdditions, _additions...) } - tcpIn <- inbound.NewSocket(addr, conn, C.TUIC, newAdditions...) + connCtx := inbound.NewSocket(addr, conn, C.TUIC, newAdditions...) + metadata := sing.ConvertMetadata(connCtx.Metadata()) + if h.IsSpecialFqdn(metadata.Destination.Fqdn) { + go func() { // ParseSpecialFqdn will block, so open a new goroutine + _ = h.ParseSpecialFqdn( + sing.WithAdditions(context.Background(), newAdditions...), + conn, + metadata, + ) + }() + return nil + } + tcpIn <- connCtx return nil } handleUdpFn := func(addr socks5.Addr, packet C.UDPPacket, _additions ...inbound.Addition) error { From 3a9fc39cd9caded275d64a0b0d3421e35bc4eb17 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 21 Aug 2023 16:18:56 +0800 Subject: [PATCH 391/530] chore: update quic-go to 0.38.0 --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 6fe21a39..d51b9b22 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.20230809092428-5acf8eb2de86 + github.com/metacubex/quic-go v0.38.1-0.20230821081539-517fdb17fb28 github.com/metacubex/sing-shadowsocks v0.2.4 github.com/metacubex/sing-shadowsocks2 v0.1.3 github.com/metacubex/sing-tun v0.1.11 @@ -83,7 +83,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.1 // indirect + github.com/quic-go/qtls-go1-20 v0.3.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 07e0bacd..0256657b 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.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/quic-go v0.38.1-0.20230821081539-517fdb17fb28 h1:ggSo4B1LDH9ZIROoUibxlrUpi7YCMri7HMXn4aNQkiM= +github.com/metacubex/quic-go v0.38.1-0.20230821081539-517fdb17fb28/go.mod h1:SthFvvoqgrEUgIxQXRnqdUAAYQECBavkhl7iA0geVd8= github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579 h1:dE1dBB6CTzNdSMFTE5OCHvzHLewiqiA1nhD+7egtvAc= github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= github.com/metacubex/sing-shadowsocks v0.2.4 h1:Gc99Z17JVif1PKKq1pjqhSmc2kvHUgk+AqxOstCzhQ0= @@ -134,8 +134,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.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg= -github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= +github.com/quic-go/qtls-go1-20 v0.3.2/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 0a7b7894bd450bf9c262fb1ea891efd1a71f5979 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 24 Aug 2023 23:33:03 +0800 Subject: [PATCH 392/530] feat: proxies support `direct` type --- adapter/outbound/direct.go | 20 ++++++++++++++++++++ adapter/parser.go | 7 +++++++ 2 files changed, 27 insertions(+) diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index 94b59cd0..af183b52 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -12,6 +12,11 @@ type Direct struct { *Base } +type DirectOption struct { + BasicOption + Name string `proxy:"name"` +} + // DialContext implements C.ProxyAdapter func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { opts = append(opts, dialer.WithResolver(resolver.DefaultResolver)) @@ -40,6 +45,21 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, return newPacketConn(pc, d), nil } +func NewDirectWithOption(option DirectOption) *Direct { + return &Direct{ + Base: &Base{ + name: option.Name, + tp: C.Direct, + udp: true, + tfo: option.TFO, + mpTcp: option.MPTCP, + iface: option.Interface, + rmark: option.RoutingMark, + prefer: C.NewDNSPrefer(option.IPVersion), + }, + } +} + func NewDirect() *Direct { return &Direct{ Base: &Base{ diff --git a/adapter/parser.go b/adapter/parser.go index a561a1ed..78e287f9 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -106,6 +106,13 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { break } proxy, err = outbound.NewTuic(*tuicOption) + case "direct": + directOption := &outbound.DirectOption{} + err = decoder.Decode(mapping, directOption) + if err != nil { + break + } + proxy = outbound.NewDirectWithOption(*directOption) default: return nil, fmt.Errorf("unsupport proxy type: %s", proxyType) } From 630a17cf90f111d06dcada8fe9f7615a5488758b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 26 Aug 2023 21:19:53 +0800 Subject: [PATCH 393/530] chore: cleanup codes --- common/cache/lrucache.go | 11 ++++------- common/picker/picker_test.go | 10 +++------- common/queue/queue.go | 11 ++++------- component/resource/fetcher.go | 25 +++++++++++-------------- 4 files changed, 22 insertions(+), 35 deletions(-) diff --git a/common/cache/lrucache.go b/common/cache/lrucache.go index 1373b0be..2f9d3e79 100644 --- a/common/cache/lrucache.go +++ b/common/cache/lrucache.go @@ -7,6 +7,8 @@ import ( "time" "github.com/Dreamacro/clash/common/generics/list" + + "github.com/samber/lo" ) // Option is part of Functional Options Pattern @@ -87,7 +89,7 @@ func (c *LruCache[K, V]) Get(key K) (V, bool) { el := c.get(key) if el == nil { - return getZero[V](), false + return lo.Empty[V](), false } value := el.value @@ -119,7 +121,7 @@ func (c *LruCache[K, V]) GetWithExpire(key K) (V, time.Time, bool) { el := c.get(key) if el == nil { - return getZero[V](), time.Time{}, false + return lo.Empty[V](), time.Time{}, false } return el.value, time.Unix(el.expires, 0), true @@ -259,8 +261,3 @@ type entry[K comparable, V any] struct { value V expires int64 } - -func getZero[T any]() T { - var result T - return result -} diff --git a/common/picker/picker_test.go b/common/picker/picker_test.go index 17b823cb..4c1c9ebe 100644 --- a/common/picker/picker_test.go +++ b/common/picker/picker_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/samber/lo" "github.com/stretchr/testify/assert" ) @@ -15,7 +16,7 @@ func sleepAndSend[T any](ctx context.Context, delay int, input T) func() (T, err case <-timer.C: return input, nil case <-ctx.Done(): - return getZero[T](), ctx.Err() + return lo.Empty[T](), ctx.Err() } } } @@ -35,11 +36,6 @@ func TestPicker_Timeout(t *testing.T) { picker.Go(sleepAndSend(ctx, 20, 1)) number := picker.Wait() - assert.Equal(t, number, getZero[int]()) + assert.Equal(t, number, lo.Empty[int]()) assert.NotNil(t, picker.Error()) } - -func getZero[T any]() T { - var result T - return result -} diff --git a/common/queue/queue.go b/common/queue/queue.go index 4755cb35..cb58e2f5 100644 --- a/common/queue/queue.go +++ b/common/queue/queue.go @@ -2,6 +2,8 @@ package queue import ( "sync" + + "github.com/samber/lo" ) // Queue is a simple concurrent safe queue @@ -24,7 +26,7 @@ func (q *Queue[T]) Put(items ...T) { // Pop returns the head of items. func (q *Queue[T]) Pop() T { if len(q.items) == 0 { - return GetZero[T]() + return lo.Empty[T]() } q.lock.Lock() @@ -37,7 +39,7 @@ func (q *Queue[T]) Pop() T { // Last returns the last of item. func (q *Queue[T]) Last() T { if len(q.items) == 0 { - return GetZero[T]() + return lo.Empty[T]() } q.lock.RLock() @@ -69,8 +71,3 @@ func New[T any](hint int64) *Queue[T] { items: make([]T, 0, hint), } } - -func GetZero[T any]() T { - var result T - return result -} diff --git a/component/resource/fetcher.go b/component/resource/fetcher.go index 4b905c7f..c92687b1 100644 --- a/component/resource/fetcher.go +++ b/component/resource/fetcher.go @@ -9,6 +9,8 @@ import ( types "github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/log" + + "github.com/samber/lo" ) var ( @@ -65,7 +67,7 @@ func (f *Fetcher[V]) Initial() (V, error) { } if err != nil { - return getZero[V](), err + return lo.Empty[V](), err } var contents V @@ -85,18 +87,18 @@ func (f *Fetcher[V]) Initial() (V, error) { if err != nil { if !isLocal { - return getZero[V](), err + return lo.Empty[V](), err } // parse local file error, fallback to remote buf, err = f.vehicle.Read() if err != nil { - return getZero[V](), err + return lo.Empty[V](), err } contents, err = f.parser(buf) if err != nil { - return getZero[V](), err + return lo.Empty[V](), err } isLocal = false @@ -104,7 +106,7 @@ func (f *Fetcher[V]) Initial() (V, error) { if f.vehicle.Type() != types.File && !isLocal { if err := safeWrite(f.vehicle.Path(), buf); err != nil { - return getZero[V](), err + return lo.Empty[V](), err } } @@ -121,7 +123,7 @@ func (f *Fetcher[V]) Initial() (V, error) { func (f *Fetcher[V]) Update() (V, bool, error) { buf, err := f.vehicle.Read() if err != nil { - return getZero[V](), false, err + return lo.Empty[V](), false, err } now := time.Now() @@ -129,17 +131,17 @@ func (f *Fetcher[V]) Update() (V, bool, error) { if bytes.Equal(f.hash[:], hash[:]) { f.UpdatedAt = &now _ = os.Chtimes(f.vehicle.Path(), now, now) - return getZero[V](), true, nil + return lo.Empty[V](), true, nil } contents, err := f.parser(buf) if err != nil { - return getZero[V](), false, err + return lo.Empty[V](), false, err } if f.vehicle.Type() != types.File { if err := safeWrite(f.vehicle.Path(), buf); err != nil { - return getZero[V](), false, err + return lo.Empty[V](), false, err } } @@ -210,8 +212,3 @@ func NewFetcher[V any](name string, interval time.Duration, vehicle types.Vehicl interval: interval, } } - -func getZero[V any]() V { - var result V - return result -} From 9536372cfbfd9439ff4870462626f21b302257ed Mon Sep 17 00:00:00 2001 From: Alpha <61853980+AlphaGHX@users.noreply.github.com> Date: Wed, 30 Aug 2023 15:49:28 +0800 Subject: [PATCH 394/530] fix: call shutdown before restart (#709) --- hub/route/restart.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hub/route/restart.go b/hub/route/restart.go index 6c3f27f3..cae21844 100644 --- a/hub/route/restart.go +++ b/hub/route/restart.go @@ -8,7 +8,7 @@ import ( "runtime" "syscall" - "github.com/Dreamacro/clash/listener" + "github.com/Dreamacro/clash/hub/executor" "github.com/Dreamacro/clash/log" "github.com/go-chi/chi/v5" @@ -44,7 +44,7 @@ func restart(w http.ResponseWriter, r *http.Request) { func runRestart(execPath string) { var err error - listener.Cleanup(false) + executor.Shutdown() if runtime.GOOS == "windows" { cmd := exec.Command(execPath, os.Args[1:]...) log.Infoln("restarting: %q %q", execPath, os.Args[1:]) From d09937520089061d002fded006a35494bd7a41f4 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 30 Aug 2023 15:52:41 +0800 Subject: [PATCH 395/530] chore: rename func name --- hub/route/restart.go | 4 ++-- hub/route/upgrade.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hub/route/restart.go b/hub/route/restart.go index cae21844..a907021f 100644 --- a/hub/route/restart.go +++ b/hub/route/restart.go @@ -39,10 +39,10 @@ func restart(w http.ResponseWriter, r *http.Request) { // The background context is used because the underlying functions wrap it // with timeout and shut down the server, which handles current request. It // also should be done in a separate goroutine for the same reason. - go runRestart(execPath) + go restartExecutable(execPath) } -func runRestart(execPath string) { +func restartExecutable(execPath string) { var err error executor.Shutdown() if runtime.GOOS == "windows" { diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index a58f224c..5e75bc8b 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -41,5 +41,5 @@ func upgrade(w http.ResponseWriter, r *http.Request) { f.Flush() } - go runRestart(execPath) + go restartExecutable(execPath) } From 86cf1dd54bace6dae826444698e612184444a22f Mon Sep 17 00:00:00 2001 From: Mitt <10653144+MittWillson@users.noreply.github.com> Date: Tue, 29 Aug 2023 12:23:16 +0000 Subject: [PATCH 396/530] fix: dualStack confusing error on ipv4 failed connect --- component/dialer/dialer.go | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 89c7564a..2bc5b66c 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -162,8 +162,11 @@ func concurrentDualStackDialContext(ctx context.Context, network string, ips []n func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) { ipv4s, ipv6s := resolver.SortationAddr(ips) - preferIPVersion := opt.prefer + if len(ipv4s) == 0 && len(ipv6s) == 0 { + return nil, ErrorNoIpAddress + } + preferIPVersion := opt.prefer fallbackTicker := time.NewTicker(fallbackTimeout) defer fallbackTicker.Stop() results := make(chan dialResult) @@ -182,11 +185,21 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, }() result.Conn, result.error = dialFn(ctx, network, ips, port, opt) } - go racer(ipv4s, preferIPVersion != 6) - go racer(ipv6s, preferIPVersion != 4) + + var wait int + if len(ipv4s) != 0 { + wait++ + go racer(ipv4s, preferIPVersion != 6) + } + + if len(ipv6s) != 0 { + wait++ + go racer(ipv6s, preferIPVersion != 4) + } + var fallback dialResult var errs []error - for i := 0; i < 2; { + for i := 0; i < wait; { select { case <-fallbackTicker.C: if fallback.error == nil && fallback.Conn != nil { From 414d8f21626b464b9e223c39ca2090203af3e31c Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Wed, 30 Aug 2023 17:07:49 +0800 Subject: [PATCH 397/530] chore: use WaitGroup in dualStackDialContext --- component/dialer/dialer.go | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 2bc5b66c..0cfa1b6c 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -169,10 +169,15 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, preferIPVersion := opt.prefer fallbackTicker := time.NewTicker(fallbackTimeout) defer fallbackTicker.Stop() + results := make(chan dialResult) returned := make(chan struct{}) defer close(returned) + + var wg sync.WaitGroup + racer := func(ips []netip.Addr, isPrimary bool) { + defer wg.Done() result := dialResult{isPrimary: isPrimary} defer func() { select { @@ -186,27 +191,35 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, result.Conn, result.error = dialFn(ctx, network, ips, port, opt) } - var wait int if len(ipv4s) != 0 { - wait++ + wg.Add(1) go racer(ipv4s, preferIPVersion != 6) } if len(ipv6s) != 0 { - wait++ + wg.Add(1) go racer(ipv6s, preferIPVersion != 4) } + go func() { + wg.Wait() + close(results) + }() + var fallback dialResult var errs []error - for i := 0; i < wait; { + +loop: + for { select { case <-fallbackTicker.C: if fallback.error == nil && fallback.Conn != nil { return fallback.Conn, nil } - case res := <-results: - i++ + case res, ok := <-results: + if !ok { + break loop + } if res.error == nil { if res.isPrimary { return res.Conn, nil @@ -221,6 +234,7 @@ func dualStackDialContext(ctx context.Context, dialFn dialFunc, network string, } } } + if fallback.error == nil && fallback.Conn != nil { return fallback.Conn, nil } From 54fee7bd3a57ddd589a96f80b893b8524a9adf4f Mon Sep 17 00:00:00 2001 From: YanceyChiew <35898533+YanceyChiew@users.noreply.github.com> Date: Tue, 15 Aug 2023 09:10:41 +0800 Subject: [PATCH 398/530] Improve: nicer tun info for RESTful api Let the restful api still get TunConf even when tun is off. Otherwise the api will return the default values, instead of the values that actually take effect after enable. * Due to this problem, yacd changes the displayed value back to gvisor immediately after the user selects tun stack. --- hub/executor/executor.go | 2 +- listener/listener.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index f4cda47a..6d542f60 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -129,7 +129,7 @@ func GetGeneral() *config.General { RedirPort: ports.RedirPort, TProxyPort: ports.TProxyPort, MixedPort: ports.MixedPort, - Tun: listener.GetTunConf(), + Tun: listener.LastTunConf, TuicServer: listener.GetTuicConf(), ShadowSocksConfig: ports.ShadowSocksConfig, VmessConfig: ports.VmessConfig, diff --git a/listener/listener.go b/listener/listener.go index 8f0088db..7b513fa7 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -516,6 +516,7 @@ func ReCreateTun(tunConf LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.Pack defer func() { if err != nil { log.Errorln("Start TUN listening error: %s", err.Error()) + tunConf.Enable = false Cleanup(false) } }() From 9ceaf20584830db6f0548f2e2e08bcbf988d5c58 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 31 Aug 2023 19:56:20 +0800 Subject: [PATCH 399/530] fix: concurrent map writes #707 --- adapter/adapter.go | 102 ++++++++++++++++++++++++++------------------- 1 file changed, 58 insertions(+), 44 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 6cc79c3a..c7351061 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -10,6 +10,7 @@ import ( "net/netip" "net/url" "strconv" + "sync" "time" "github.com/Dreamacro/clash/common/atomic" @@ -36,7 +37,7 @@ type Proxy struct { history *queue.Queue[C.DelayHistory] alive *atomic.Bool url string - extra map[string]*extraProxyState + extra sync.Map } // Alive implements C.Proxy @@ -46,10 +47,8 @@ func (p *Proxy) Alive() bool { // 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() - } + if state, ok := p.extra.Load(url); ok { + return state.(*extraProxyState).alive.Load() } return p.alive.Load() @@ -88,16 +87,16 @@ func (p *Proxy) DelayHistory() []C.DelayHistory { for _, item := range queueM { histories = append(histories, item) } + 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 state, ok := p.extra.Load(url); ok { + queueM = state.(*extraProxyState).history.Copy() } if queueM == nil { @@ -112,19 +111,25 @@ 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 testUrl, option := range p.extra { - histories := []C.DelayHistory{} - queueM := option.history.Copy() - for _, item := range queueM { - histories = append(histories, item) - } + extraHistory := map[string][]C.DelayHistory{} - extra[testUrl] = histories + p.extra.Range(func(k, v interface{}) bool { + + testUrl := k.(string) + state := v.(*extraProxyState) + + histories := []C.DelayHistory{} + queueM := state.history.Copy() + + for _, item := range queueM { + histories = append(histories, item) } - } - return extra + + extraHistory[testUrl] = histories + + return true + }) + return extraHistory } // LastDelay return last history record. if proxy is not alive, return the max value of uint16. @@ -149,11 +154,9 @@ func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { 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 state, ok := p.extra.Load(url); ok { + alive = state.(*extraProxyState).alive.Load() + history = state.(*extraProxyState).history.Last() } if !alive { @@ -214,23 +217,19 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In record.Delay = t } - if p.extra == nil { - p.extra = map[string]*extraProxyState{} - } - - state, ok := p.extra[url] + state, ok := p.extra.Load(url) if !ok { state = &extraProxyState{ history: queue.New[C.DelayHistory](defaultHistoriesNum), alive: atomic.NewBool(true), } - p.extra[url] = state + p.extra.Store(url, state) } - state.alive.Store(alive) - state.history.Put(record) - if state.history.Len() > defaultHistoriesNum { - state.history.Pop() + state.(*extraProxyState).alive.Store(alive) + state.(*extraProxyState).history.Put(record) + if state.(*extraProxyState).history.Len() > defaultHistoriesNum { + state.(*extraProxyState).history.Pop() } default: log.Debugln("health check result will be discarded, url: %s alive: %t, delay: %d", url, alive, t) @@ -307,7 +306,12 @@ 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{ + ProxyAdapter: adapter, + history: queue.New[C.DelayHistory](defaultHistoriesNum), + alive: atomic.NewBool(true), + url: "", + extra: sync.Map{}} } func urlToMetadata(rawURL string) (addr C.Metadata, err error) { @@ -350,14 +354,24 @@ func (p *Proxy) determineFinalStoreType(store C.DelayHistoryStoreType, url strin 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 - } + length := 0 + p.extra.Range(func(_, _ interface{}) bool { + length++ + return length < 2*C.DefaultMaxHealthCheckUrlNum + }) + + if length == 0 { + return C.ExtraHistory } + + _, ok := p.extra.Load(url) + if ok { + return C.ExtraHistory + } + + if length < 2*C.DefaultMaxHealthCheckUrlNum { + return C.ExtraHistory + } + return store } From cbdf33c42c1795c85a52b886cee163438a3d8f1e Mon Sep 17 00:00:00 2001 From: "riolu.rs" Date: Fri, 1 Sep 2023 03:11:35 +0800 Subject: [PATCH 400/530] feat: ntp service --- adapter/outbound/vmess.go | 2 + component/tls/reality.go | 3 +- config/config.go | 43 +++++++++++++++ go.mod | 1 + go.sum | 29 ++++++++++ hub/executor/executor.go | 12 +++++ listener/sing_shadowsocks/server.go | 4 +- listener/sing_vmess/server.go | 3 +- ntp/service.go | 84 +++++++++++++++++++++++++++++ 9 files changed, 177 insertions(+), 4 deletions(-) create mode 100644 ntp/service.go diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 7495d8a3..0fa0b1d9 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -18,6 +18,7 @@ import ( "github.com/Dreamacro/clash/component/resolver" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" + "github.com/Dreamacro/clash/ntp" "github.com/Dreamacro/clash/transport/gun" clashVMess "github.com/Dreamacro/clash/transport/vmess" @@ -416,6 +417,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { if option.AuthenticatedLength { options = append(options, vmess.ClientWithAuthenticatedLength()) } + options = append(options, vmess.ClientWithTimeFunc(ntp.Now)) client, err := vmess.NewClient(option.UUID, security, option.AlterID, options...) if err != nil { return nil, err diff --git a/component/tls/reality.go b/component/tls/reality.go index 265c584e..c995af0a 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -22,6 +22,7 @@ import ( "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/log" + "github.com/Dreamacro/clash/ntp" utls "github.com/sagernet/utls" "github.com/zhangyunhao116/fastrand" @@ -70,7 +71,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string rawSessionID[i] = 0 } - binary.BigEndian.PutUint64(hello.SessionId, uint64(time.Now().Unix())) + binary.BigEndian.PutUint64(hello.SessionId, uint64(ntp.Now().Unix())) copy(hello.SessionId[8:], realityConfig.ShortID[:]) hello.SessionId[0] = 1 diff --git a/config/config.go b/config/config.go index cb30999b..3db51776 100644 --- a/config/config.go +++ b/config/config.go @@ -87,6 +87,14 @@ type Controller struct { Secret string `json:"-"` } +// NTP config +type NTP struct { + Enable bool `yaml:"enable"` + Server string `yaml:"server"` + Port int `yaml:"port"` + Interval int `yaml:"interval"` +} + // DNS config type DNS struct { Enable bool `yaml:"enable"` @@ -151,6 +159,7 @@ type Experimental struct { type Config struct { General *General IPTables *IPTables + NTP *NTP DNS *DNS Experimental *Experimental Hosts *trie.DomainTrie[resolver.HostValue] @@ -167,6 +176,13 @@ type Config struct { TLS *TLS } +type RawNTP struct { + Enable bool `yaml:"enable"` + Server string `yaml:"server"` + ServerPort int `yaml:"server-port"` + Interval int `yaml:"interval"` +} + type RawDNS struct { Enable bool `yaml:"enable"` PreferH3 bool `yaml:"prefer-h3"` @@ -269,6 +285,7 @@ type RawConfig struct { ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` RuleProvider map[string]map[string]any `yaml:"rule-providers"` Hosts map[string]any `yaml:"hosts"` + NTP RawNTP `yaml:"ntp"` DNS RawDNS `yaml:"dns"` Tun RawTun `yaml:"tun"` TuicServer RawTuicServer `yaml:"tuic-server"` @@ -493,6 +510,9 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } config.Hosts = hosts + ntpCfg := paresNTP(rawCfg) + config.NTP = ntpCfg + dnsCfg, err := parseDNS(rawCfg, hosts, rules, ruleProviders) if err != nil { return nil, err @@ -1132,6 +1152,29 @@ func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainM return sites, nil } +func paresNTP(rawCfg *RawConfig) *NTP { + var server = "time.apple.com" + var port = 123 + var interval = 30 + cfg := rawCfg.NTP + if len(cfg.Server) != 0 { + server = cfg.Server + } + if cfg.ServerPort != 0 { + port = cfg.ServerPort + } + if cfg.Interval != 0 { + interval = cfg.Interval + } + ntpCfg := &NTP{ + Enable: cfg.Enable, + Server: server, + Port: port, + Interval: interval, + } + return ntpCfg +} + func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) { cfg := rawCfg.DNS if cfg.Enable && len(cfg.NameServer) == 0 { diff --git a/go.mod b/go.mod index d51b9b22..00fd802b 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/3andne/restls-client-go v0.1.6 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da + github.com/beevik/ntp v1.3.0 github.com/cilium/ebpf v0.11.0 github.com/coreos/go-iptables v0.7.0 github.com/dlclark/regexp2 v1.10.0 diff --git a/go.sum b/go.sum index 0256657b..84b13831 100644 --- a/go.sum +++ b/go.sum @@ -10,6 +10,8 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/beevik/ntp v1.3.0 h1:/w5VhpW5BGKS37vFm1p9oVk/t4HnnkKZAZIubHM6F7Q= +github.com/beevik/ntp v1.3.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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= @@ -193,6 +195,7 @@ github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1 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/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 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= @@ -205,6 +208,8 @@ 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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= 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-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= @@ -212,15 +217,24 @@ golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N0 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= 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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.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= @@ -234,17 +248,30 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w 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= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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.8.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/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/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.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= @@ -253,6 +280,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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +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= diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 6d542f60..d5ca4afb 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -2,11 +2,15 @@ package executor import ( "fmt" + "github.com/Dreamacro/clash/ntp" + "net" "net/netip" "os" "runtime" + "strconv" "strings" "sync" + "time" "github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter/inbound" @@ -92,6 +96,7 @@ func ApplyConfig(cfg *config.Config, force bool) { updateSniffer(cfg.Sniffer) updateHosts(cfg.Hosts) updateGeneral(cfg.General) + updateNTP(cfg.NTP) updateDNS(cfg.DNS, cfg.RuleProviders, cfg.General.IPv6) updateListeners(cfg.General, cfg.Listeners, force) updateIPTables(cfg) @@ -178,6 +183,13 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList func updateExperimental(c *config.Config) { } +func updateNTP(c *config.NTP) { + if c.Enable { + ntp.ReCreateNTPService(net.JoinHostPort(c.Server, strconv.Itoa(c.Port)), + time.Duration(c.Interval)) + } +} + func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, generalIPv6 bool) { if !c.Enable { resolver.DefaultResolver = nil diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 1fa9a3ba..13ddde0d 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -5,7 +5,6 @@ import ( "fmt" "net" "strings" - "time" "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/common/sockopt" @@ -14,6 +13,7 @@ import ( embedSS "github.com/Dreamacro/clash/listener/shadowsocks" "github.com/Dreamacro/clash/listener/sing" "github.com/Dreamacro/clash/log" + "github.com/Dreamacro/clash/ntp" shadowsocks "github.com/metacubex/sing-shadowsocks" "github.com/metacubex/sing-shadowsocks/shadowaead" @@ -64,7 +64,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C case common.Contains(shadowaead.List, config.Cipher): sl.service, err = shadowaead.NewService(config.Cipher, nil, config.Password, udpTimeout, h) case common.Contains(shadowaead_2022.List, config.Cipher): - sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h, time.Now) + sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h, ntp.Now) default: err = fmt.Errorf("shadowsocks: unsupported method: %s", config.Cipher) return embedSS.New(config, tcpIn, udpIn) diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index f6a279c1..374a378b 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -10,6 +10,7 @@ import ( C "github.com/Dreamacro/clash/constant" LC "github.com/Dreamacro/clash/listener/config" "github.com/Dreamacro/clash/listener/sing" + "github.com/Dreamacro/clash/ntp" vmess "github.com/metacubex/sing-vmess" "github.com/sagernet/sing/common" @@ -42,7 +43,7 @@ func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packe Additions: additions, } - service := vmess.NewService[string](h, vmess.ServiceWithDisableHeaderProtection()) + service := vmess.NewService[string](h, vmess.ServiceWithDisableHeaderProtection(), vmess.ServiceWithTimeFunc(ntp.Now)) err = service.UpdateUsers( common.Map(config.Users, func(it LC.VmessUser) string { return it.Username diff --git a/ntp/service.go b/ntp/service.go new file mode 100644 index 00000000..e8864eb6 --- /dev/null +++ b/ntp/service.go @@ -0,0 +1,84 @@ +package ntp + +import ( + "context" + "github.com/Dreamacro/clash/log" + "github.com/beevik/ntp" + "sync" + "time" +) + +var offset time.Duration +var service *Service + +type Service struct { + addr string + interval time.Duration + ticker *time.Ticker + ctx context.Context + cancel context.CancelFunc + mu *sync.Mutex + running bool +} + +func ReCreateNTPService(addr string, interval time.Duration) { + if service != nil { + service.Stop() + } + ctx, cancel := context.WithCancel(context.Background()) + service = &Service{addr: addr, interval: interval, ctx: ctx, cancel: cancel, mu: &sync.Mutex{}} + service.Start() +} + +func (srv *Service) Start() { + srv.mu.Lock() + defer srv.mu.Unlock() + log.Infoln("NTP service start") + srv.ticker = time.NewTicker(srv.interval * time.Minute) + service.running = true + go func() { + for { + err := srv.updateTime(srv.addr) + if err != nil { + log.Warnln("updateTime failed:", err) + } + select { + case <-srv.ticker.C: + case <-srv.ctx.Done(): + return + } + } + }() +} + +func (srv *Service) Stop() { + srv.mu.Lock() + defer srv.mu.Unlock() + srv.ticker.Stop() + srv.cancel() + service.running = false +} + +func (srv *Service) updateTime(addr string) error { + response, err := ntp.Query(addr) + if err != nil { + return err + } + localTime := time.Now() + ntpTime := response.Time + offset = localTime.Sub(ntpTime) + if offset > time.Duration(0) { + log.Warnln("System clock is ahead of NTP time by", offset) + } else if offset < time.Duration(0) { + log.Warnln("System clock is behind NTP time by", -offset) + } + return nil +} + +func Now() time.Time { + now := time.Now() + if service.running && offset.Abs() > 0 { + now = now.Add(offset) + } + return now +} From a366e9a4b5397b7da7040b26dc15b3e0f4457600 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 2 Sep 2023 12:37:43 +0800 Subject: [PATCH 401/530] fix: ntp service panic --- common/cmd/cmd_test.go | 2 +- ntp/service.go | 29 ++++++++++++++++++++--------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/common/cmd/cmd_test.go b/common/cmd/cmd_test.go index 4bba6def..b124a22d 100644 --- a/common/cmd/cmd_test.go +++ b/common/cmd/cmd_test.go @@ -21,7 +21,7 @@ func TestSplitArgs(t *testing.T) { func TestExecCmd(t *testing.T) { if runtime.GOOS == "windows" { - _, err := ExecCmd("dir") + _, err := ExecCmd("cmd -c 'dir'") assert.Nil(t, err) return } diff --git a/ntp/service.go b/ntp/service.go index e8864eb6..af06a571 100644 --- a/ntp/service.go +++ b/ntp/service.go @@ -17,7 +17,7 @@ type Service struct { ticker *time.Ticker ctx context.Context cancel context.CancelFunc - mu *sync.Mutex + mu sync.Mutex running bool } @@ -26,7 +26,7 @@ func ReCreateNTPService(addr string, interval time.Duration) { service.Stop() } ctx, cancel := context.WithCancel(context.Background()) - service = &Service{addr: addr, interval: interval, ctx: ctx, cancel: cancel, mu: &sync.Mutex{}} + service = &Service{addr: addr, interval: interval, ctx: ctx, cancel: cancel} service.Start() } @@ -40,7 +40,7 @@ func (srv *Service) Start() { for { err := srv.updateTime(srv.addr) if err != nil { - log.Warnln("updateTime failed:", err) + log.Warnln("updateTime failed: %s", err) } select { case <-srv.ticker.C: @@ -54,9 +54,20 @@ func (srv *Service) Start() { func (srv *Service) Stop() { srv.mu.Lock() defer srv.mu.Unlock() - srv.ticker.Stop() - srv.cancel() - service.running = false + if service.running { + srv.ticker.Stop() + srv.cancel() + service.running = false + } +} + +func (srv *Service) Running() bool { + if srv == nil { + return false + } + srv.mu.Lock() + defer srv.mu.Unlock() + return srv.running } func (srv *Service) updateTime(addr string) error { @@ -68,16 +79,16 @@ func (srv *Service) updateTime(addr string) error { ntpTime := response.Time offset = localTime.Sub(ntpTime) if offset > time.Duration(0) { - log.Warnln("System clock is ahead of NTP time by", offset) + log.Warnln("System clock is ahead of NTP time by %s", offset) } else if offset < time.Duration(0) { - log.Warnln("System clock is behind NTP time by", -offset) + log.Warnln("System clock is behind NTP time by %s", -offset) } return nil } func Now() time.Time { now := time.Now() - if service.running && offset.Abs() > 0 { + if service.Running() && offset.Abs() > 0 { now = now.Add(offset) } return now From 9feb4d666809eb64dfdb17376bdd918146c373fc Mon Sep 17 00:00:00 2001 From: YanceyChiew <35898533+YanceyChiew@users.noreply.github.com> Date: Sat, 2 Sep 2023 01:14:26 +0800 Subject: [PATCH 402/530] fix: RESTful api missing TunConf.device In commit 54fee7b, due to failure to take into account that not all required parameters of `sing_tun.server.New` have default values provided by `LC.Tun`, the name of the tun device cannot be obtained when `TunConf.device` is not explicitly configured. This commit fixed the issue. --- hub/executor/executor.go | 2 +- listener/listener.go | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index d5ca4afb..8cb8358f 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -134,7 +134,7 @@ func GetGeneral() *config.General { RedirPort: ports.RedirPort, TProxyPort: ports.TProxyPort, MixedPort: ports.MixedPort, - Tun: listener.LastTunConf, + Tun: listener.GetTunConf(), TuicServer: listener.GetTuicConf(), ShadowSocksConfig: ports.ShadowSocksConfig, VmessConfig: ports.VmessConfig, diff --git a/listener/listener.go b/listener/listener.go index 7b513fa7..a340d3a2 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -84,9 +84,7 @@ type Ports struct { func GetTunConf() LC.Tun { if tunLister == nil { - return LC.Tun{ - Enable: false, - } + return LastTunConf } return tunLister.Config() } From 427a377c2a19aca095f1b39da332d5dc882f5033 Mon Sep 17 00:00:00 2001 From: YanceyChiew <35898533+YanceyChiew@users.noreply.github.com> Date: Sat, 2 Sep 2023 03:27:48 +0800 Subject: [PATCH 403/530] refactor: Decouple .Cleanup from ReCreateTun The listener.Cleanup method will be called during executor.Shutdown and route.restart, so it should serve all kinds of listeners rather than a single tun device. Currently listener.ReCreateTun will call it to handle some internal affairs, This should be decoupled. In this way, the cleanup tasks for data outside the process life cycle that other listeners will add here in the future will not be accidentally triggered by configuring tun. --- listener/listener.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/listener/listener.go b/listener/listener.go index a340d3a2..9b4840e1 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -515,7 +515,6 @@ func ReCreateTun(tunConf LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.Pack if err != nil { log.Errorln("Start TUN listening error: %s", err.Error()) tunConf.Enable = false - Cleanup(false) } }() @@ -526,7 +525,7 @@ func ReCreateTun(tunConf LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.Pack return } - Cleanup(true) + closeTunListener() if !tunConf.Enable { return @@ -896,10 +895,13 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { return false } -func Cleanup(wait bool) { +func closeTunListener() { if tunLister != nil { tunLister.Close() tunLister = nil } - LastTunConf = LC.Tun{} +} + +func Cleanup(wait bool) { + closeTunListener() } From d79c13064eb7bc464da31f72c5c9bcb88ba75c4b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 2 Sep 2023 14:10:26 +0800 Subject: [PATCH 404/530] chore: cleanup codes --- hub/executor/executor.go | 2 +- listener/listener.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 8cb8358f..b7111c14 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -491,7 +491,7 @@ func updateIPTables(cfg *config.Config) { } func Shutdown() { - listener.Cleanup(false) + listener.Cleanup() tproxy.CleanupTProxyIPTables() resolver.StoreFakePoolState() diff --git a/listener/listener.go b/listener/listener.go index 9b4840e1..b1d59d49 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -902,6 +902,6 @@ func closeTunListener() { } } -func Cleanup(wait bool) { +func Cleanup() { closeTunListener() } From 73fa79bf3f508159311839dc7e295070180c80da Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 2 Sep 2023 16:25:55 +0800 Subject: [PATCH 405/530] feat: configurable TCPKeepAlive interval --- adapter/outbound/direct.go | 4 +++- adapter/outbound/http.go | 4 +++- adapter/outbound/shadowsocks.go | 2 +- adapter/outbound/shadowsocksr.go | 2 +- adapter/outbound/snell.go | 7 ++++--- adapter/outbound/socks5.go | 5 +++-- adapter/outbound/trojan.go | 7 ++++--- adapter/outbound/util.go | 8 -------- adapter/outbound/vless.go | 6 +++--- adapter/outbound/vmess.go | 6 +++--- adapter/outboundgroup/util.go | 12 ------------ common/net/tcpip.go | 10 ++++++++++ config/config.go | 9 +++++++++ docs/config.yaml | 2 ++ listener/autoredir/tcp.go | 3 ++- listener/mixed/mixed.go | 4 ++-- listener/redir/tcp.go | 3 ++- listener/shadowsocks/tcp.go | 2 +- listener/sing_shadowsocks/server.go | 3 ++- listener/sing_vmess/server.go | 3 ++- listener/socks/tcp.go | 2 +- listener/tproxy/tproxy.go | 3 ++- listener/tunnel/tcp.go | 3 ++- 23 files changed, 62 insertions(+), 48 deletions(-) diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index af183b52..720f96f9 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -3,6 +3,8 @@ package outbound import ( "context" "errors" + + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" @@ -24,7 +26,7 @@ func (d *Direct) DialContext(ctx context.Context, metadata *C.Metadata, opts ... if err != nil { return nil, err } - tcpKeepAlive(c) + N.TCPKeepAlive(c) return NewConn(c, d), nil } diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 0b652ca9..acc75d37 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -7,11 +7,13 @@ import ( "encoding/base64" "errors" "fmt" + "io" "net" "net/http" "strconv" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" tlsC "github.com/Dreamacro/clash/component/tls" @@ -74,7 +76,7 @@ func (h *Http) DialContextWithDialer(ctx context.Context, dialer C.Dialer, metad if err != nil { return nil, fmt.Errorf("%s connect error: %w", h.addr, err) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 0f46cf79..f744ec53 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -146,7 +146,7 @@ func (ss *ShadowSocks) DialContextWithDialer(ctx context.Context, dialer C.Diale if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index cd6854af..0f03f86d 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -80,7 +80,7 @@ func (ssr *ShadowSocksR) DialContextWithDialer(ctx context.Context, dialer C.Dia if err != nil { return nil, fmt.Errorf("%s connect error: %w", ssr.addr, err) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index d0b9e748..16405fcf 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -6,6 +6,7 @@ import ( "net" "strconv" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/structure" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" @@ -93,7 +94,7 @@ func (s *Snell) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta if err != nil { return nil, fmt.Errorf("%s connect error: %w", s.addr, err) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) @@ -121,7 +122,7 @@ func (s *Snell) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met if err != nil { return nil, err } - tcpKeepAlive(c) + N.TCPKeepAlive(c) c = streamConn(c, streamOption{s.psk, s.version, s.addr, s.obfsOption}) err = snell.WriteUDPHeader(c, s.version) @@ -207,7 +208,7 @@ func NewSnell(option SnellOption) (*Snell, error) { return nil, err } - tcpKeepAlive(c) + N.TCPKeepAlive(c) return streamConn(c, streamOption{psk, option.Version, addr, obfsOption}), nil }) } diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index f451cd1a..2e9bccd6 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -9,6 +9,7 @@ import ( "net" "strconv" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" tlsC "github.com/Dreamacro/clash/component/tls" @@ -80,7 +81,7 @@ func (ss *Socks5) DialContextWithDialer(ctx context.Context, dialer C.Dialer, me if err != nil { return nil, fmt.Errorf("%s connect error: %w", ss.addr, err) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) @@ -126,7 +127,7 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, safeConnClose(c, err) }(c) - tcpKeepAlive(c) + N.TCPKeepAlive(c) var user *socks5.User if ss.user != "" { user = &socks5.User{ diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index ec420bf3..6339b476 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -8,6 +8,7 @@ import ( "net/http" "strconv" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" tlsC "github.com/Dreamacro/clash/component/tls" @@ -131,7 +132,7 @@ func (t *Trojan) DialContextWithDialer(ctx context.Context, dialer C.Dialer, met if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) @@ -184,7 +185,7 @@ func (t *Trojan) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, me defer func(c net.Conn) { safeConnClose(c, err) }(c) - tcpKeepAlive(c) + N.TCPKeepAlive(c) c, err = t.plainStream(ctx, c) if err != nil { return nil, fmt.Errorf("%s connect error: %w", t.addr, err) @@ -268,7 +269,7 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { if err != nil { return nil, fmt.Errorf("%s connect error: %s", t.addr, err.Error()) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) return c, nil } diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index 7f3ec4c3..36607e4f 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -7,7 +7,6 @@ import ( "net" "net/netip" "sync" - "time" "github.com/Dreamacro/clash/component/resolver" C "github.com/Dreamacro/clash/constant" @@ -19,13 +18,6 @@ var ( once sync.Once ) -func tcpKeepAlive(c net.Conn) { - if tcp, ok := c.(*net.TCPConn); ok { - _ = tcp.SetKeepAlive(true) - _ = tcp.SetKeepAlivePeriod(30 * time.Second) - } -} - func getClientSessionCache() tls.ClientSessionCache { once.Do(func() { globalClientSessionCache = tls.NewLRUClientSessionCache(128) diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 2456c2c3..81408e5f 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -263,7 +263,7 @@ func (v *Vless) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) }(c) @@ -328,7 +328,7 @@ func (v *Vless) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) }(c) @@ -578,7 +578,7 @@ func NewVless(option VlessOption) (*Vless, error) { if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) return c, nil } diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 0fa0b1d9..3e7694d1 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -308,7 +308,7 @@ func (v *Vmess) DialContextWithDialer(ctx context.Context, dialer C.Dialer, meta if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) }(c) @@ -369,7 +369,7 @@ func (v *Vmess) ListenPacketWithDialer(ctx context.Context, dialer C.Dialer, met if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) defer func(c net.Conn) { safeConnClose(c, err) }(c) @@ -469,7 +469,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { if err != nil { return nil, fmt.Errorf("%s connect error: %s", v.addr, err.Error()) } - tcpKeepAlive(c) + N.TCPKeepAlive(c) return c, nil } diff --git a/adapter/outboundgroup/util.go b/adapter/outboundgroup/util.go index 85373a1f..84216377 100644 --- a/adapter/outboundgroup/util.go +++ b/adapter/outboundgroup/util.go @@ -1,17 +1,5 @@ package outboundgroup -import ( - "net" - "time" -) - -func tcpKeepAlive(c net.Conn) { - if tcp, ok := c.(*net.TCPConn); ok { - _ = tcp.SetKeepAlive(true) - _ = tcp.SetKeepAlivePeriod(30 * time.Second) - } -} - type SelectAble interface { Set(string) error ForceSet(name string) diff --git a/common/net/tcpip.go b/common/net/tcpip.go index a84e7e4c..171191e2 100644 --- a/common/net/tcpip.go +++ b/common/net/tcpip.go @@ -4,8 +4,11 @@ import ( "fmt" "net" "strings" + "time" ) +var KeepAliveInterval time.Duration + func SplitNetworkType(s string) (string, string, error) { var ( shecme string @@ -44,3 +47,10 @@ func SplitHostPort(s string) (host, port string, hasPort bool, err error) { host, port, err = net.SplitHostPort(temp) return } + +func TCPKeepAlive(c net.Conn) { + if tcp, ok := c.(*net.TCPConn); ok { + _ = tcp.SetKeepAlive(true) + _ = tcp.SetKeepAlivePeriod(KeepAliveInterval * time.Second) + } +} diff --git a/config/config.go b/config/config.go index 3db51776..62fef1bd 100644 --- a/config/config.go +++ b/config/config.go @@ -16,6 +16,7 @@ import ( "github.com/Dreamacro/clash/adapter/outbound" "github.com/Dreamacro/clash/adapter/outboundgroup" "github.com/Dreamacro/clash/adapter/provider" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/auth" "github.com/Dreamacro/clash/component/dialer" @@ -59,6 +60,7 @@ type General struct { Sniffing bool `json:"sniffing"` EBpf EBpf `json:"-"` GlobalClientFingerprint string `json:"global-client-fingerprint"` + KeepAliveInterval int `json:"keep-alive-interval"` } // Inbound config @@ -280,6 +282,7 @@ type RawConfig struct { TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` GlobalClientFingerprint string `yaml:"global-client-fingerprint"` + KeepAliveInterval int `yaml:"keep-alive-interval"` Sniffer RawSniffer `yaml:"sniffer"` ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` @@ -559,6 +562,11 @@ func parseGeneral(cfg *RawConfig) (*General, error) { C.GeoSiteUrl = cfg.GeoXUrl.GeoSite C.MmdbUrl = cfg.GeoXUrl.Mmdb C.GeodataMode = cfg.GeodataMode + if cfg.KeepAliveInterval == 0 { + cfg.KeepAliveInterval = 30 + } + N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second + log.Infoln("Keep Alive Interval set %+v", N.KeepAliveInterval) // checkout externalUI exist if externalUI != "" { externalUI = C.Path.Resolve(externalUI) @@ -600,6 +608,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { FindProcessMode: cfg.FindProcessMode, EBpf: cfg.EBpf, GlobalClientFingerprint: cfg.GlobalClientFingerprint, + KeepAliveInterval: cfg.KeepAliveInterval, }, nil } diff --git a/docs/config.yaml b/docs/config.yaml index 62cd0c58..ca33911e 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -50,6 +50,8 @@ external-ui: /path/to/ui/folder # 配置 WEB UI 目录,使用 http://{{externa # Utls is currently support TLS transport in TCP/grpc/WS/HTTP for VLESS/Vmess and trojan. global-client-fingerprint: chrome +keep-alive-interval: 30 + # routing-mark:6666 # 配置 fwmark 仅用于 Linux experimental: diff --git a/listener/autoredir/tcp.go b/listener/autoredir/tcp.go index 854d31d6..c390d89a 100644 --- a/listener/autoredir/tcp.go +++ b/listener/autoredir/tcp.go @@ -5,6 +5,7 @@ import ( "net/netip" "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" "github.com/Dreamacro/clash/transport/socks5" @@ -55,7 +56,7 @@ func (l *Listener) handleRedir(conn net.Conn, in chan<- C.ConnContext) { return } - _ = conn.(*net.TCPConn).SetKeepAlive(true) + N.TCPKeepAlive(conn) in <- inbound.NewSocket(target, conn, C.REDIR, l.additions...) } diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index e8385873..7241927d 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -1,9 +1,9 @@ package mixed import ( - "github.com/Dreamacro/clash/adapter/inbound" "net" + "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/common/cache" N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" @@ -70,7 +70,7 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { - conn.(*net.TCPConn).SetKeepAlive(true) + N.TCPKeepAlive(conn) bufConn := N.NewBufferedConn(conn) head, err := bufConn.Peek(1) diff --git a/listener/redir/tcp.go b/listener/redir/tcp.go index ad4a91bc..9a843af8 100644 --- a/listener/redir/tcp.go +++ b/listener/redir/tcp.go @@ -4,6 +4,7 @@ import ( "net" "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" ) @@ -66,6 +67,6 @@ func handleRedir(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Ad conn.Close() return } - conn.(*net.TCPConn).SetKeepAlive(true) + N.TCPKeepAlive(conn) in <- inbound.NewSocket(target, conn, C.REDIR, additions...) } diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index febf87c3..2d0958a0 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -59,7 +59,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C } continue } - _ = c.(*net.TCPConn).SetKeepAlive(true) + N.TCPKeepAlive(c) go sl.HandleConn(c, tcpIn) } }() diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 13ddde0d..d0e137a7 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/sockopt" C "github.com/Dreamacro/clash/constant" LC "github.com/Dreamacro/clash/listener/config" @@ -145,7 +146,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C } continue } - _ = c.(*net.TCPConn).SetKeepAlive(true) + N.TCPKeepAlive(c) go sl.HandleConn(c, tcpIn) } diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index 374a378b..06f3e051 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -7,6 +7,7 @@ import ( "strings" "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" LC "github.com/Dreamacro/clash/listener/config" "github.com/Dreamacro/clash/listener/sing" @@ -84,7 +85,7 @@ func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packe } continue } - _ = c.(*net.TCPConn).SetKeepAlive(true) + N.TCPKeepAlive(c) go sl.HandleConn(c, tcpIn) } diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index cbaac987..2fd252a3 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -67,7 +67,7 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } func handleSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { - conn.(*net.TCPConn).SetKeepAlive(true) + N.TCPKeepAlive(conn) bufConn := N.NewBufferedConn(conn) head, err := bufConn.Peek(1) if err != nil { diff --git a/listener/tproxy/tproxy.go b/listener/tproxy/tproxy.go index 198481f7..8c868609 100644 --- a/listener/tproxy/tproxy.go +++ b/listener/tproxy/tproxy.go @@ -4,6 +4,7 @@ import ( "net" "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -32,7 +33,7 @@ func (l *Listener) Close() error { func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { target := socks5.ParseAddrToSocksAddr(conn.LocalAddr()) - conn.(*net.TCPConn).SetKeepAlive(true) + N.TCPKeepAlive(conn) in <- inbound.NewSocket(target, conn, C.TPROXY, additions...) } diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index c1d896ad..d660d2b8 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -5,6 +5,7 @@ import ( "net" "github.com/Dreamacro/clash/adapter/inbound" + N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" ) @@ -34,7 +35,7 @@ func (l *Listener) Close() error { } func (l *Listener) handleTCP(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { - conn.(*net.TCPConn).SetKeepAlive(true) + N.TCPKeepAlive(conn) ctx := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...) ctx.Metadata().SpecialProxy = l.proxy in <- ctx From 1cad615b25e277b0153192f0b6c8788597c57b8c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 2 Sep 2023 16:54:35 +0800 Subject: [PATCH 406/530] chore: using xsync.MapOf replace sync.Map --- adapter/adapter.go | 31 ++++++++++---------- component/auth/auth.go | 10 +++---- component/nat/table.go | 58 ++++++++++++++++++++++++------------- constant/adapters.go | 14 +++++---- go.mod | 1 + go.sum | 2 ++ listener/tproxy/packet.go | 11 ++++--- transport/tuic/v4/client.go | 13 +++++---- transport/tuic/v4/server.go | 10 +++---- transport/tuic/v5/client.go | 11 +++---- transport/tuic/v5/server.go | 10 +++---- tunnel/connection.go | 9 ++---- tunnel/statistic/manager.go | 11 +++---- tunnel/tunnel.go | 5 ++-- 14 files changed, 110 insertions(+), 86 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index c7351061..44f09ba1 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -10,7 +10,6 @@ import ( "net/netip" "net/url" "strconv" - "sync" "time" "github.com/Dreamacro/clash/common/atomic" @@ -19,6 +18,8 @@ import ( "github.com/Dreamacro/clash/component/dialer" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" + + "github.com/puzpuzpuz/xsync/v2" ) var UnifiedDelay = atomic.NewBool(false) @@ -37,7 +38,7 @@ type Proxy struct { history *queue.Queue[C.DelayHistory] alive *atomic.Bool url string - extra sync.Map + extra *xsync.MapOf[string, *extraProxyState] } // Alive implements C.Proxy @@ -48,7 +49,7 @@ func (p *Proxy) Alive() bool { // AliveForTestUrl implements C.Proxy func (p *Proxy) AliveForTestUrl(url string) bool { if state, ok := p.extra.Load(url); ok { - return state.(*extraProxyState).alive.Load() + return state.alive.Load() } return p.alive.Load() @@ -96,7 +97,7 @@ func (p *Proxy) DelayHistoryForTestUrl(url string) []C.DelayHistory { var queueM []C.DelayHistory if state, ok := p.extra.Load(url); ok { - queueM = state.(*extraProxyState).history.Copy() + queueM = state.history.Copy() } if queueM == nil { @@ -113,10 +114,10 @@ func (p *Proxy) DelayHistoryForTestUrl(url string) []C.DelayHistory { func (p *Proxy) ExtraDelayHistory() map[string][]C.DelayHistory { extraHistory := map[string][]C.DelayHistory{} - p.extra.Range(func(k, v interface{}) bool { + p.extra.Range(func(k string, v *extraProxyState) bool { - testUrl := k.(string) - state := v.(*extraProxyState) + testUrl := k + state := v histories := []C.DelayHistory{} queueM := state.history.Copy() @@ -155,8 +156,8 @@ func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { history := p.history.Last() if state, ok := p.extra.Load(url); ok { - alive = state.(*extraProxyState).alive.Load() - history = state.(*extraProxyState).history.Last() + alive = state.alive.Load() + history = state.history.Last() } if !alive { @@ -226,10 +227,10 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In p.extra.Store(url, state) } - state.(*extraProxyState).alive.Store(alive) - state.(*extraProxyState).history.Put(record) - if state.(*extraProxyState).history.Len() > defaultHistoriesNum { - state.(*extraProxyState).history.Pop() + 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) @@ -311,7 +312,7 @@ func NewProxy(adapter C.ProxyAdapter) *Proxy { history: queue.New[C.DelayHistory](defaultHistoriesNum), alive: atomic.NewBool(true), url: "", - extra: sync.Map{}} + extra: xsync.NewMapOf[*extraProxyState]()} } func urlToMetadata(rawURL string) (addr C.Metadata, err error) { @@ -355,7 +356,7 @@ func (p *Proxy) determineFinalStoreType(store C.DelayHistoryStoreType, url strin } length := 0 - p.extra.Range(func(_, _ interface{}) bool { + p.extra.Range(func(_ string, _ *extraProxyState) bool { length++ return length < 2*C.DefaultMaxHealthCheckUrlNum }) diff --git a/component/auth/auth.go b/component/auth/auth.go index 9d30b927..9b351606 100644 --- a/component/auth/auth.go +++ b/component/auth/auth.go @@ -1,7 +1,7 @@ package auth import ( - "sync" + "github.com/puzpuzpuz/xsync/v2" ) type Authenticator interface { @@ -15,7 +15,7 @@ type AuthUser struct { } type inMemoryAuthenticator struct { - storage *sync.Map + storage *xsync.MapOf[string, string] usernames []string } @@ -31,13 +31,13 @@ func NewAuthenticator(users []AuthUser) Authenticator { return nil } - au := &inMemoryAuthenticator{storage: &sync.Map{}} + au := &inMemoryAuthenticator{storage: xsync.NewMapOf[string]()} for _, user := range users { au.storage.Store(user.User, user.Pass) } usernames := make([]string, 0, len(users)) - au.storage.Range(func(key, value any) bool { - usernames = append(usernames, key.(string)) + au.storage.Range(func(key string, value string) bool { + usernames = append(usernames, key) return true }) au.usernames = usernames diff --git a/component/nat/table.go b/component/nat/table.go index adc6eace..df258dc2 100644 --- a/component/nat/table.go +++ b/component/nat/table.go @@ -5,23 +5,28 @@ import ( "sync" C "github.com/Dreamacro/clash/constant" + + "github.com/puzpuzpuz/xsync/v2" ) type Table struct { - mapping sync.Map + mapping *xsync.MapOf[string, *Entry] + lockMap *xsync.MapOf[string, *sync.Cond] } type Entry struct { PacketConn C.PacketConn WriteBackProxy C.WriteBackProxy - LocalUDPConnMap sync.Map + LocalUDPConnMap *xsync.MapOf[string, *net.UDPConn] + LocalLockMap *xsync.MapOf[string, *sync.Cond] } func (t *Table) Set(key string, e C.PacketConn, w C.WriteBackProxy) { t.mapping.Store(key, &Entry{ PacketConn: e, WriteBackProxy: w, - LocalUDPConnMap: sync.Map{}, + LocalUDPConnMap: xsync.NewMapOf[*net.UDPConn](), + LocalLockMap: xsync.NewMapOf[*sync.Cond](), }) } @@ -34,15 +39,19 @@ func (t *Table) Get(key string) (C.PacketConn, C.WriteBackProxy) { } func (t *Table) GetOrCreateLock(key string) (*sync.Cond, bool) { - item, loaded := t.mapping.LoadOrStore(key, sync.NewCond(&sync.Mutex{})) - return item.(*sync.Cond), loaded + item, loaded := t.lockMap.LoadOrCompute(key, makeLock) + return item, loaded } func (t *Table) Delete(key string) { t.mapping.Delete(key) } -func (t *Table) GetLocalConn(lAddr, rAddr string) *net.UDPConn { +func (t *Table) DeleteLock(lockKey string) { + t.lockMap.Delete(lockKey) +} + +func (t *Table) GetForLocalConn(lAddr, rAddr string) *net.UDPConn { entry, exist := t.getEntry(lAddr) if !exist { return nil @@ -51,10 +60,10 @@ func (t *Table) GetLocalConn(lAddr, rAddr string) *net.UDPConn { if !exist { return nil } - return item.(*net.UDPConn) + return item } -func (t *Table) AddLocalConn(lAddr, rAddr string, conn *net.UDPConn) bool { +func (t *Table) AddForLocalConn(lAddr, rAddr string, conn *net.UDPConn) bool { entry, exist := t.getEntry(lAddr) if !exist { return false @@ -63,7 +72,7 @@ func (t *Table) AddLocalConn(lAddr, rAddr string, conn *net.UDPConn) bool { return true } -func (t *Table) RangeLocalConn(lAddr string, f func(key, value any) bool) { +func (t *Table) RangeForLocalConn(lAddr string, f func(key string, value *net.UDPConn) bool) { entry, exist := t.getEntry(lAddr) if !exist { return @@ -76,11 +85,11 @@ func (t *Table) GetOrCreateLockForLocalConn(lAddr, key string) (*sync.Cond, bool if !loaded { return nil, false } - item, loaded := entry.LocalUDPConnMap.LoadOrStore(key, sync.NewCond(&sync.Mutex{})) - return item.(*sync.Cond), loaded + item, loaded := entry.LocalLockMap.LoadOrCompute(key, makeLock) + return item, loaded } -func (t *Table) DeleteLocalConnMap(lAddr, key string) { +func (t *Table) DeleteForLocalConn(lAddr, key string) { entry, loaded := t.getEntry(lAddr) if !loaded { return @@ -88,17 +97,26 @@ func (t *Table) DeleteLocalConnMap(lAddr, key string) { entry.LocalUDPConnMap.Delete(key) } -func (t *Table) getEntry(key string) (*Entry, bool) { - item, ok := t.mapping.Load(key) - // This should not happen usually since this function called after PacketConn created - if !ok { - return nil, false +func (t *Table) DeleteLockForLocalConn(lAddr, key string) { + entry, loaded := t.getEntry(lAddr) + if !loaded { + return } - entry, ok := item.(*Entry) - return entry, ok + entry.LocalLockMap.Delete(key) +} + +func (t *Table) getEntry(key string) (*Entry, bool) { + return t.mapping.Load(key) +} + +func makeLock() *sync.Cond { + return sync.NewCond(&sync.Mutex{}) } // New return *Cache func New() *Table { - return &Table{} + return &Table{ + mapping: xsync.NewMapOf[*Entry](), + lockMap: xsync.NewMapOf[*sync.Cond](), + } } diff --git a/constant/adapters.go b/constant/adapters.go index a3796ef7..5639dd47 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -267,13 +267,17 @@ type NatTable interface { Delete(key string) - GetLocalConn(lAddr, rAddr string) *net.UDPConn + DeleteLock(key string) - AddLocalConn(lAddr, rAddr string, conn *net.UDPConn) bool + GetForLocalConn(lAddr, rAddr string) *net.UDPConn - RangeLocalConn(lAddr string, f func(key, value any) bool) + AddForLocalConn(lAddr, rAddr string, conn *net.UDPConn) bool - GetOrCreateLockForLocalConn(lAddr, key string) (*sync.Cond, bool) + RangeForLocalConn(lAddr string, f func(key string, value *net.UDPConn) bool) - DeleteLocalConnMap(lAddr, key string) + GetOrCreateLockForLocalConn(lAddr string, key string) (*sync.Cond, bool) + + DeleteForLocalConn(lAddr, key string) + + DeleteLockForLocalConn(lAddr, key string) } diff --git a/go.mod b/go.mod index 00fd802b..a57d9a2b 100644 --- a/go.mod +++ b/go.mod @@ -30,6 +30,7 @@ require ( github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 + github.com/puzpuzpuz/xsync/v2 v2.5.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c diff --git a/go.sum b/go.sum index 84b13831..e718b9e4 100644 --- a/go.sum +++ b/go.sum @@ -134,6 +134,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= +github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErpE8c= +github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= 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.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index 2966fd2e..b73339a1 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -55,16 +55,15 @@ func (c *packet) InAddr() net.Addr { func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natTable C.NatTable) (*net.UDPConn, error) { remote := rAddr.String() local := lAddr.String() - localConn := natTable.GetLocalConn(local, remote) + localConn := natTable.GetForLocalConn(local, remote) // localConn not exist if localConn == nil { - lockKey := remote + "-lock" - cond, loaded := natTable.GetOrCreateLockForLocalConn(local, lockKey) + cond, loaded := natTable.GetOrCreateLockForLocalConn(local, remote) if loaded { cond.L.Lock() cond.Wait() // we should get localConn here - localConn = natTable.GetLocalConn(local, remote) + localConn = natTable.GetForLocalConn(local, remote) if localConn == nil { return nil, fmt.Errorf("localConn is nil, nat entry not exist") } @@ -74,7 +73,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natT return nil, fmt.Errorf("cond is nil, nat entry not exist") } defer func() { - natTable.DeleteLocalConnMap(local, lockKey) + natTable.DeleteLockForLocalConn(local, remote) cond.Broadcast() }() conn, err := listenLocalConn(rAddr, lAddr, in, natTable) @@ -82,7 +81,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natT log.Errorln("listenLocalConn failed with error: %s, packet loss (rAddr[%T]=%s lAddr[%T]=%s)", err.Error(), rAddr, remote, lAddr, local) return nil, err } - natTable.AddLocalConn(local, remote, conn) + natTable.AddForLocalConn(local, remote, conn) localConn = conn } } diff --git a/transport/tuic/v4/client.go b/transport/tuic/v4/client.go index fd3bf54a..ce33b72b 100644 --- a/transport/tuic/v4/client.go +++ b/transport/tuic/v4/client.go @@ -22,6 +22,7 @@ import ( "github.com/Dreamacro/clash/transport/tuic/common" "github.com/metacubex/quic-go" + "github.com/puzpuzpuz/xsync/v2" "github.com/zhangyunhao116/fastrand" ) @@ -49,7 +50,7 @@ type clientImpl struct { openStreams atomic.Int64 closed atomic.Bool - udpInputMap sync.Map + udpInputMap *xsync.MapOf[uint32, net.Conn] // only ready for PoolClient dialerRef C.Dialer @@ -263,11 +264,10 @@ func (t *clientImpl) forceClose(quicConn quic.Connection, 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 := t.udpInputMap + udpInputMap.Range(func(key uint32, value net.Conn) bool { + conn := value + _ = conn.Close() udpInputMap.Delete(key) return true }) @@ -469,6 +469,7 @@ func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client ClientOption: clientOption, udp: udp, dialerRef: dialerRef, + udpInputMap: xsync.NewIntegerMapOf[uint32, net.Conn](), } c := &Client{ci} runtime.SetFinalizer(c, closeClient) diff --git a/transport/tuic/v4/server.go b/transport/tuic/v4/server.go index b0012d96..56133fea 100644 --- a/transport/tuic/v4/server.go +++ b/transport/tuic/v4/server.go @@ -17,6 +17,7 @@ import ( "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" + "github.com/puzpuzpuz/xsync/v2" ) type ServerOption struct { @@ -33,6 +34,7 @@ func NewServerHandler(option *ServerOption, quicConn quic.EarlyConnection, uuid quicConn: quicConn, uuid: uuid, authCh: make(chan struct{}), + udpInputMap: xsync.NewIntegerMapOf[uint32, *atomic.Bool](), } } @@ -45,7 +47,7 @@ type serverHandler struct { authOk atomic.Bool authOnce sync.Once - udpInputMap sync.Map + udpInputMap *xsync.MapOf[uint32, *atomic.Bool] } func (s *serverHandler) AuthOk() bool { @@ -78,8 +80,7 @@ func (s *serverHandler) parsePacket(packet *Packet, udpRelayMode common.UdpRelay assocId = packet.ASSOC_ID - v, _ := s.udpInputMap.LoadOrStore(assocId, &atomic.Bool{}) - writeClosed := v.(*atomic.Bool) + writeClosed, _ := s.udpInputMap.LoadOrCompute(assocId, func() *atomic.Bool { return &atomic.Bool{} }) if writeClosed.Load() { return nil } @@ -173,8 +174,7 @@ func (s *serverHandler) HandleUniStream(reader *bufio.Reader) (err error) { if err != nil { return } - if v, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded { - writeClosed := v.(*atomic.Bool) + if writeClosed, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded { writeClosed.Store(true) } case HeartbeatType: diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go index 74dfd581..c4ac25d4 100644 --- a/transport/tuic/v5/client.go +++ b/transport/tuic/v5/client.go @@ -20,6 +20,7 @@ import ( "github.com/Dreamacro/clash/transport/tuic/common" "github.com/metacubex/quic-go" + "github.com/puzpuzpuz/xsync/v2" "github.com/zhangyunhao116/fastrand" ) @@ -46,7 +47,7 @@ type clientImpl struct { openStreams atomic.Int64 closed atomic.Bool - udpInputMap sync.Map + udpInputMap xsync.MapOf[uint16, net.Conn] // only ready for PoolClient dialerRef C.Dialer @@ -270,10 +271,9 @@ func (t *clientImpl) forceClose(quicConn quic.Connection, err error) { _ = quicConn.CloseWithError(ProtocolError, errStr) } udpInputMap := &t.udpInputMap - udpInputMap.Range(func(key, value any) bool { - if conn, ok := value.(net.Conn); ok { - _ = conn.Close() - } + udpInputMap.Range(func(key uint16, value net.Conn) bool { + conn := value + _ = conn.Close() udpInputMap.Delete(key) return true }) @@ -406,6 +406,7 @@ func NewClient(clientOption *ClientOption, udp bool, dialerRef C.Dialer) *Client ClientOption: clientOption, udp: udp, dialerRef: dialerRef, + udpInputMap: *xsync.NewIntegerMapOf[uint16, net.Conn](), } c := &Client{ci} runtime.SetFinalizer(c, closeClient) diff --git a/transport/tuic/v5/server.go b/transport/tuic/v5/server.go index 30259583..10003a9d 100644 --- a/transport/tuic/v5/server.go +++ b/transport/tuic/v5/server.go @@ -16,6 +16,7 @@ import ( "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" + "github.com/puzpuzpuz/xsync/v2" ) type ServerOption struct { @@ -32,6 +33,7 @@ func NewServerHandler(option *ServerOption, quicConn quic.EarlyConnection, uuid quicConn: quicConn, uuid: uuid, authCh: make(chan struct{}), + udpInputMap: xsync.NewIntegerMapOf[uint16, *serverUDPInput](), } } @@ -45,7 +47,7 @@ type serverHandler struct { authUUID atomic.TypedValue[string] authOnce sync.Once - udpInputMap sync.Map + udpInputMap *xsync.MapOf[uint16, *serverUDPInput] } func (s *serverHandler) AuthOk() bool { @@ -94,8 +96,7 @@ func (s *serverHandler) parsePacket(packet *Packet, udpRelayMode common.UdpRelay assocId = packet.ASSOC_ID - v, _ := s.udpInputMap.LoadOrStore(assocId, &serverUDPInput{}) - input := v.(*serverUDPInput) + input, _ := s.udpInputMap.LoadOrCompute(assocId, func() *serverUDPInput { return &serverUDPInput{} }) if input.writeClosed.Load() { return nil } @@ -186,8 +187,7 @@ func (s *serverHandler) HandleUniStream(reader *bufio.Reader) (err error) { if err != nil { return } - if v, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded { - input := v.(*serverUDPInput) + if input, loaded := s.udpInputMap.LoadAndDelete(disassociate.ASSOC_ID); loaded { input.writeClosed.Store(true) } } diff --git a/tunnel/connection.go b/tunnel/connection.go index 2e76b86b..9fc4f405 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -73,12 +73,9 @@ func handleUDPToLocal(writeBack C.WriteBack, pc N.EnhancePacketConn, key string, } func closeAllLocalCoon(lAddr string) { - natTable.RangeLocalConn(lAddr, func(key, value any) bool { - conn, ok := value.(*net.UDPConn) - if !ok || conn == nil { - log.Debugln("Value %#v unknown value when closing TProxy local conn...", conn) - return true - } + natTable.RangeForLocalConn(lAddr, func(key string, value *net.UDPConn) bool { + conn := value + conn.Close() log.Debugln("Closing TProxy local conn... lAddr=%s rAddr=%s", lAddr, key) return true diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 2358d0bd..19ce58d9 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -2,11 +2,11 @@ package statistic import ( "os" - "sync" "time" "github.com/Dreamacro/clash/common/atomic" + "github.com/puzpuzpuz/xsync/v2" "github.com/shirou/gopsutil/v3/process" ) @@ -14,6 +14,7 @@ var DefaultManager *Manager func init() { DefaultManager = &Manager{ + connections: xsync.NewMapOf[Tracker](), uploadTemp: atomic.NewInt64(0), downloadTemp: atomic.NewInt64(0), uploadBlip: atomic.NewInt64(0), @@ -27,7 +28,7 @@ func init() { } type Manager struct { - connections sync.Map + connections *xsync.MapOf[string, Tracker] uploadTemp *atomic.Int64 downloadTemp *atomic.Int64 uploadBlip *atomic.Int64 @@ -48,14 +49,14 @@ func (m *Manager) Leave(c Tracker) { func (m *Manager) Get(id string) (c Tracker) { if value, ok := m.connections.Load(id); ok { - c = value.(Tracker) + c = value } return } func (m *Manager) Range(f func(c Tracker) bool) { - m.connections.Range(func(key, value any) bool { - return f(value.(Tracker)) + m.connections.Range(func(key string, value Tracker) bool { + return f(value) }) } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index d4c15a87..b7557e10 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -318,8 +318,7 @@ func handleUDPConn(packet C.PacketAdapter) { return } - lockKey := key + "-lock" - cond, loaded := natTable.GetOrCreateLock(lockKey) + cond, loaded := natTable.GetOrCreateLock(key) go func() { defer packet.Drop() @@ -333,7 +332,7 @@ func handleUDPConn(packet C.PacketAdapter) { } defer func() { - natTable.Delete(lockKey) + natTable.DeleteLock(key) cond.Broadcast() }() From d6b80acfbc1570c07e99d91f035119d443cf9d84 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 2 Sep 2023 20:17:43 +0800 Subject: [PATCH 407/530] chore: Use xsync provided map size calculation --- adapter/adapter.go | 12 +------- test/go.mod | 23 ++++++++------- test/go.sum | 73 +++++++++++++++++++++++++++++++++------------- 3 files changed, 67 insertions(+), 41 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index 44f09ba1..13f7f06f 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -355,13 +355,7 @@ func (p *Proxy) determineFinalStoreType(store C.DelayHistoryStoreType, url strin return C.OriginalHistory } - length := 0 - p.extra.Range(func(_ string, _ *extraProxyState) bool { - length++ - return length < 2*C.DefaultMaxHealthCheckUrlNum - }) - - if length == 0 { + if p.extra.Size() < 2*C.DefaultMaxHealthCheckUrlNum { return C.ExtraHistory } @@ -370,9 +364,5 @@ func (p *Proxy) determineFinalStoreType(store C.DelayHistoryStoreType, url strin return C.ExtraHistory } - if length < 2*C.DefaultMaxHealthCheckUrlNum { - return C.ExtraHistory - } - return store } diff --git a/test/go.mod b/test/go.mod index 80f958a5..2d7ef893 100644 --- a/test/go.mod +++ b/test/go.mod @@ -14,12 +14,13 @@ require ( replace github.com/Dreamacro/clash => ../ require ( - github.com/3andne/restls-client-go v0.1.4 // indirect + github.com/3andne/restls-client-go v0.1.6 // indirect github.com/Microsoft/go-winio v0.6.0 // indirect github.com/RyuaNerin/go-krypto v1.0.2 // indirect 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/beevik/ntp v1.3.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 @@ -31,6 +32,7 @@ require ( github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect github.com/gofrs/uuid/v5 v5.0.0 // indirect @@ -44,7 +46,7 @@ require ( 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 + github.com/klauspost/compress v1.16.7 // 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 @@ -52,7 +54,7 @@ require ( 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-20230611153922-78842f086475 // indirect - github.com/metacubex/quic-go v0.37.4-0.20230806014204-ef9b221eec12 // indirect + github.com/metacubex/quic-go v0.38.1-0.20230821081539-517fdb17fb28 // 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 @@ -60,7 +62,7 @@ require ( 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.2 // indirect + github.com/mroth/weightedrand/v2 v2.1.0 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/openacid/low v0.1.21 // indirect @@ -71,17 +73,18 @@ require ( 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/puzpuzpuz/xsync/v2 v2.5.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.1 // indirect + github.com/quic-go/qtls-go1-20 v0.3.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.9 // indirect - github.com/sagernet/sing-mux v0.1.2 // indirect + github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a // indirect + github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c // 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/tfo-go v0.0.0-20230816093905-5a5c285d44a6 // indirect github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 // indirect - github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 // indirect + github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f // 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.7 // indirect @@ -99,7 +102,7 @@ require ( gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.etcd.io/bbolt v1.3.7 // indirect golang.org/x/crypto v0.12.0 // indirect - golang.org/x/exp v0.0.0-20230801115018-d63ba01acd4b // indirect + golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb // 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 diff --git a/test/go.sum b/test/go.sum index fbf635c6..03971c26 100644 --- a/test/go.sum +++ b/test/go.sum @@ -1,5 +1,5 @@ -github.com/3andne/restls-client-go v0.1.4 h1:kLNC2aSRHPlEVYmTj6EOqJoorCpobEe2toMRSfBF7FU= -github.com/3andne/restls-client-go v0.1.4/go.mod h1:04CGbRk1BwBiEDles8b5mlKgTqIwE5MqF7JDloJV47I= +github.com/3andne/restls-client-go v0.1.6 h1:tRx/YilqW7iHpgmEL4E1D8dAsuB0tFF3uvncS+B6I08= +github.com/3andne/restls-client-go v0.1.6/go.mod h1:iEdTZNt9kzPIxjIGSMScUFSBrUH6bFRNg0BWlP4orEY= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= @@ -11,6 +11,8 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/beevik/ntp v1.3.0 h1:/w5VhpW5BGKS37vFm1p9oVk/t4HnnkKZAZIubHM6F7Q= +github.com/beevik/ntp v1.3.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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= @@ -44,6 +46,8 @@ 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/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= +github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= 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= @@ -81,8 +85,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/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= 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/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I= +github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= 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= @@ -99,8 +103,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.38.1-0.20230821081539-517fdb17fb28 h1:ggSo4B1LDH9ZIROoUibxlrUpi7YCMri7HMXn4aNQkiM= +github.com/metacubex/quic-go v0.38.1-0.20230821081539-517fdb17fb28/go.mod h1:SthFvvoqgrEUgIxQXRnqdUAAYQECBavkhl7iA0geVd8= 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= @@ -117,8 +121,8 @@ 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.2 h1:A8wJRUBcfguGl6oOQHI8fy5P4ViGRT9hdQdlG/7RiXo= -github.com/mroth/weightedrand/v2 v2.0.2/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= +github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= +github.com/mroth/weightedrand/v2 v2.1.0/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= @@ -143,10 +147,12 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErpE8c= +github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= 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.1 h1:O4BLOM3hwfVF3AcktIylQXyl7Yi2iBNVy5QsV+ySxbg= -github.com/quic-go/qtls-go1-20 v0.3.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= +github.com/quic-go/qtls-go1-20 v0.3.2/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= @@ -154,20 +160,20 @@ 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.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 v0.2.10-0.20230807080248-4db0062caa0a h1:b89t6Mjgk4rJ5lrNMnCzy1/J116XkhgdB3YNd9FHyF4= +github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= +github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c h1:35/FowAvt3Z62mck0TXzVc4jS5R5CWq62qcV2P1cp0I= +github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY= 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= -github.com/sagernet/tfo-go v0.0.0-20230303015439-ffcfd8c41cf9/go.mod h1:FUyTEc5ye5NjKnDTDMuiLF2M6T4BE6y6KZuax//UCEg= +github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 h1:Px+hN4Vzgx+iCGVnWH5A8eR7JhNnIV3rGQmBxA7cw6Q= +github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6/go.mod h1:zovq6vTvEM6ECiqE3Eeb9rpIylPpamPcmrJ9tv0Bt0M= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 h1:kDUqhc9Vsk5HJuhfIATJ8oQwBmpOZJuozQG7Vk88lL4= github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2/go.mod h1:JKQMZq/O2qnZjdrt+B57olmfgEmLtY9iiSIEYtWvoSM= -github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77 h1:g6QtRWQ2dKX7EQP++1JLNtw4C2TNxd4/ov8YUpOPOSo= -github.com/sagernet/wireguard-go v0.0.0-20230420044414-a7bac1754e77/go.mod h1:pJDdXzZIwJ+2vmnT0TKzmf8meeum+e2mTDSehw79eE0= +github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f h1:Kvo8w8Y9lzFGB/7z09MJ3TR99TFtfI/IuY87Ygcycho= +github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f/go.mod h1:mySs0abhpc/gLlvhoq7HP1RzOaRmIXVeZGCh++zoApk= 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= @@ -210,6 +216,7 @@ github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1 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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 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= @@ -221,28 +228,39 @@ 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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= 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/exp v0.0.0-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= +golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= 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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.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= @@ -257,18 +275,31 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w 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= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.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/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.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= @@ -279,6 +310,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK 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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +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= From d6cf2a837ff101b0d3c634a8e76b022ff5505353 Mon Sep 17 00:00:00 2001 From: "riolu.rs" Date: Sun, 3 Sep 2023 17:48:52 +0800 Subject: [PATCH 408/530] chore: ntp service dep with sing, optional synchronize system time --- config/config.go | 46 +++++++++++----------- go.mod | 1 - go.sum | 29 -------------- hub/executor/executor.go | 2 +- ntp/service.go | 84 +++++++++++++++++++++++----------------- ntp/time_stub.go | 12 ++++++ ntp/time_unix.go | 14 +++++++ ntp/time_windows.go | 32 +++++++++++++++ 8 files changed, 130 insertions(+), 90 deletions(-) create mode 100644 ntp/time_stub.go create mode 100644 ntp/time_unix.go create mode 100644 ntp/time_windows.go diff --git a/config/config.go b/config/config.go index 62fef1bd..cb030530 100644 --- a/config/config.go +++ b/config/config.go @@ -91,10 +91,11 @@ type Controller struct { // NTP config type NTP struct { - Enable bool `yaml:"enable"` - Server string `yaml:"server"` - Port int `yaml:"port"` - Interval int `yaml:"interval"` + Enable bool `yaml:"enable"` + WriteToSystem bool `yaml:"write-to-system"` + Server string `yaml:"server"` + Port int `yaml:"port"` + Interval int `yaml:"interval"` } // DNS config @@ -179,10 +180,11 @@ type Config struct { } type RawNTP struct { - Enable bool `yaml:"enable"` - Server string `yaml:"server"` - ServerPort int `yaml:"server-port"` - Interval int `yaml:"interval"` + Enable bool `yaml:"enable"` + WriteToSystem bool `yaml:"write-to-system"` + Server string `yaml:"server"` + ServerPort int `yaml:"server-port"` + Interval int `yaml:"interval"` } type RawDNS struct { @@ -399,6 +401,13 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { InboundInterface: "lo", Bypass: []string{}, }, + NTP: RawNTP{ + Enable: false, + WriteToSystem: false, + Server: "time.apple.com", + ServerPort: 123, + Interval: 30, + }, DNS: RawDNS{ Enable: false, IPv6: false, @@ -1162,24 +1171,13 @@ func parseFallbackGeoSite(countries []string, rules []C.Rule) ([]*router.DomainM } func paresNTP(rawCfg *RawConfig) *NTP { - var server = "time.apple.com" - var port = 123 - var interval = 30 cfg := rawCfg.NTP - if len(cfg.Server) != 0 { - server = cfg.Server - } - if cfg.ServerPort != 0 { - port = cfg.ServerPort - } - if cfg.Interval != 0 { - interval = cfg.Interval - } ntpCfg := &NTP{ - Enable: cfg.Enable, - Server: server, - Port: port, - Interval: interval, + Enable: cfg.Enable, + Server: cfg.Server, + Port: cfg.ServerPort, + Interval: cfg.Interval, + WriteToSystem: cfg.WriteToSystem, } return ntpCfg } diff --git a/go.mod b/go.mod index a57d9a2b..aa37eff2 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,6 @@ go 1.20 require ( github.com/3andne/restls-client-go v0.1.6 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da - github.com/beevik/ntp v1.3.0 github.com/cilium/ebpf v0.11.0 github.com/coreos/go-iptables v0.7.0 github.com/dlclark/regexp2 v1.10.0 diff --git a/go.sum b/go.sum index e718b9e4..530b615d 100644 --- a/go.sum +++ b/go.sum @@ -10,8 +10,6 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/beevik/ntp v1.3.0 h1:/w5VhpW5BGKS37vFm1p9oVk/t4HnnkKZAZIubHM6F7Q= -github.com/beevik/ntp v1.3.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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= @@ -197,7 +195,6 @@ github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1 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/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 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= @@ -210,8 +207,6 @@ 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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= 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-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= @@ -219,24 +214,15 @@ golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N0 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= 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.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.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= @@ -250,30 +236,17 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w 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= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/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.8.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/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/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.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= @@ -282,8 +255,6 @@ 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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -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= diff --git a/hub/executor/executor.go b/hub/executor/executor.go index b7111c14..f4364b7b 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -186,7 +186,7 @@ func updateExperimental(c *config.Config) { func updateNTP(c *config.NTP) { if c.Enable { ntp.ReCreateNTPService(net.JoinHostPort(c.Server, strconv.Itoa(c.Port)), - time.Duration(c.Interval)) + time.Duration(c.Interval), c.WriteToSystem) } } diff --git a/ntp/service.go b/ntp/service.go index af06a571..726ac636 100644 --- a/ntp/service.go +++ b/ntp/service.go @@ -3,7 +3,9 @@ package ntp import ( "context" "github.com/Dreamacro/clash/log" - "github.com/beevik/ntp" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/ntp" "sync" "time" ) @@ -12,43 +14,37 @@ var offset time.Duration var service *Service type Service struct { - addr string - interval time.Duration - ticker *time.Ticker - ctx context.Context - cancel context.CancelFunc - mu sync.Mutex - running bool + server M.Socksaddr + ticker *time.Ticker + ctx context.Context + cancel context.CancelFunc + mu sync.Mutex + syncSystemTime bool + running bool } -func ReCreateNTPService(addr string, interval time.Duration) { +func ReCreateNTPService(server string, interval time.Duration, syncSystemTime bool) { if service != nil { service.Stop() } ctx, cancel := context.WithCancel(context.Background()) - service = &Service{addr: addr, interval: interval, ctx: ctx, cancel: cancel} + service = &Service{ + ctx: ctx, + cancel: cancel, + server: M.ParseSocksaddr(server), + ticker: time.NewTicker(interval * time.Minute), + syncSystemTime: syncSystemTime, + } service.Start() } func (srv *Service) Start() { srv.mu.Lock() defer srv.mu.Unlock() - log.Infoln("NTP service start") - srv.ticker = time.NewTicker(srv.interval * time.Minute) + log.Infoln("NTP service start, sync system time is %t", srv.syncSystemTime) service.running = true - go func() { - for { - err := srv.updateTime(srv.addr) - if err != nil { - log.Warnln("updateTime failed: %s", err) - } - select { - case <-srv.ticker.C: - case <-srv.ctx.Done(): - return - } - } - }() + srv.update() + go srv.loopUpdate() } func (srv *Service) Stop() { @@ -70,20 +66,38 @@ func (srv *Service) Running() bool { return srv.running } -func (srv *Service) updateTime(addr string) error { - response, err := ntp.Query(addr) - if err != nil { - return err +func (srv *Service) update() { + response, err := ntp.Exchange(context.Background(), N.SystemDialer, srv.server) + if err != nil || response == nil { + log.Errorln("initialize time: %s", err) } - localTime := time.Now() - ntpTime := response.Time - offset = localTime.Sub(ntpTime) + offset = response.ClockOffset if offset > time.Duration(0) { - log.Warnln("System clock is ahead of NTP time by %s", offset) + log.Infoln("System clock is ahead of NTP time by %s", offset) } else if offset < time.Duration(0) { - log.Warnln("System clock is behind NTP time by %s", -offset) + log.Infoln("System clock is behind NTP time by %s", -offset) + } + if srv.syncSystemTime { + timeNow := response.Time + err = setSystemTime(timeNow) + if err == nil { + log.Infoln("sync system time success: %s", timeNow.Local().Format(ntp.TimeLayout)) + } else { + log.Errorln("write time to system: %s", err) + srv.syncSystemTime = false + } + } +} + +func (srv *Service) loopUpdate() { + for { + select { + case <-srv.ctx.Done(): + return + case <-srv.ticker.C: + } + srv.update() } - return nil } func Now() time.Time { diff --git a/ntp/time_stub.go b/ntp/time_stub.go new file mode 100644 index 00000000..12050983 --- /dev/null +++ b/ntp/time_stub.go @@ -0,0 +1,12 @@ +//go:build !(windows || linux || darwin) + +package ntp + +import ( + "os" + "time" +) + +func setSystemTime(nowTime time.Time) error { + return os.ErrInvalid +} diff --git a/ntp/time_unix.go b/ntp/time_unix.go new file mode 100644 index 00000000..9e819473 --- /dev/null +++ b/ntp/time_unix.go @@ -0,0 +1,14 @@ +//go:build linux || darwin + +package ntp + +import ( + "time" + + "golang.org/x/sys/unix" +) + +func setSystemTime(nowTime time.Time) error { + timeVal := unix.NsecToTimeval(nowTime.UnixNano()) + return unix.Settimeofday(&timeVal) +} diff --git a/ntp/time_windows.go b/ntp/time_windows.go new file mode 100644 index 00000000..8ef29b1b --- /dev/null +++ b/ntp/time_windows.go @@ -0,0 +1,32 @@ +package ntp + +import ( + "time" + "unsafe" + + "golang.org/x/sys/windows" +) + +func setSystemTime(nowTime time.Time) error { + var systemTime windows.Systemtime + systemTime.Year = uint16(nowTime.Year()) + systemTime.Month = uint16(nowTime.Month()) + systemTime.Day = uint16(nowTime.Day()) + systemTime.Hour = uint16(nowTime.Hour()) + systemTime.Minute = uint16(nowTime.Minute()) + systemTime.Second = uint16(nowTime.Second()) + systemTime.Milliseconds = uint16(nowTime.UnixMilli() - nowTime.Unix()*1000) + + dllKernel32 := windows.NewLazySystemDLL("kernel32.dll") + proc := dllKernel32.NewProc("SetSystemTime") + + _, _, err := proc.Call( + uintptr(unsafe.Pointer(&systemTime)), + ) + + if err != nil && err.Error() != "The operation completed successfully." { + return err + } + + return nil +} From 1d4af2d92bcae7ec394830e58435ded6454882ef Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 3 Sep 2023 20:42:54 +0800 Subject: [PATCH 409/530] chore: TCPKeepAlive interval set to 15s by default --- common/net/tcpip.go | 2 +- config/config.go | 8 ++++---- docs/config.yaml | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/common/net/tcpip.go b/common/net/tcpip.go index 171191e2..7bc31edd 100644 --- a/common/net/tcpip.go +++ b/common/net/tcpip.go @@ -7,7 +7,7 @@ import ( "time" ) -var KeepAliveInterval time.Duration +var KeepAliveInterval = 15 * time.Second func SplitNetworkType(s string) (string, string, error) { var ( diff --git a/config/config.go b/config/config.go index cb030530..4421adc2 100644 --- a/config/config.go +++ b/config/config.go @@ -571,11 +571,11 @@ func parseGeneral(cfg *RawConfig) (*General, error) { C.GeoSiteUrl = cfg.GeoXUrl.GeoSite C.MmdbUrl = cfg.GeoXUrl.Mmdb C.GeodataMode = cfg.GeodataMode - if cfg.KeepAliveInterval == 0 { - cfg.KeepAliveInterval = 30 + if cfg.KeepAliveInterval != 0 { + N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second } - N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second - log.Infoln("Keep Alive Interval set %+v", N.KeepAliveInterval) + + log.Debugln("TCP Keep Alive Interval set %+v", N.KeepAliveInterval) // checkout externalUI exist if externalUI != "" { externalUI = C.Path.Resolve(externalUI) diff --git a/docs/config.yaml b/docs/config.yaml index ca33911e..cd540311 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -50,7 +50,8 @@ external-ui: /path/to/ui/folder # 配置 WEB UI 目录,使用 http://{{externa # Utls is currently support TLS transport in TCP/grpc/WS/HTTP for VLESS/Vmess and trojan. global-client-fingerprint: chrome -keep-alive-interval: 30 +# TCP keep alive interval +keep-alive-interval: 15 # routing-mark:6666 # 配置 fwmark 仅用于 Linux experimental: From a1eab125ee29cc4d858f454af9200a2f2455240e Mon Sep 17 00:00:00 2001 From: "riolu.rs" Date: Mon, 4 Sep 2023 18:19:22 +0800 Subject: [PATCH 410/530] fix: ntp service panic --- ntp/service.go | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/ntp/service.go b/ntp/service.go index 726ac636..3234180d 100644 --- a/ntp/service.go +++ b/ntp/service.go @@ -67,9 +67,19 @@ func (srv *Service) Running() bool { } func (srv *Service) update() { - response, err := ntp.Exchange(context.Background(), N.SystemDialer, srv.server) - if err != nil || response == nil { - log.Errorln("initialize time: %s", err) + var response *ntp.Response + var err error + for i := 0; i < 3; i++ { + response, err = ntp.Exchange(context.Background(), N.SystemDialer, srv.server) + if err != nil { + if i == 2 { + log.Errorln("Initialize NTP time failed: %s", err) + return + } + time.Sleep(time.Second * 2) // wait for 2 seconds before the next try + continue + } + break } offset = response.ClockOffset if offset > time.Duration(0) { @@ -81,9 +91,9 @@ func (srv *Service) update() { timeNow := response.Time err = setSystemTime(timeNow) if err == nil { - log.Infoln("sync system time success: %s", timeNow.Local().Format(ntp.TimeLayout)) + log.Infoln("Sync system time success: %s", timeNow.Local().Format(ntp.TimeLayout)) } else { - log.Errorln("write time to system: %s", err) + log.Errorln("Write time to system: %s", err) srv.syncSystemTime = false } } From 7286391883eedab755dca5e4e6cc6bda476c2793 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Thu, 7 Sep 2023 18:44:58 +0800 Subject: [PATCH 411/530] feat: support users to customize download ua --- component/http/http.go | 6 ++---- config/config.go | 5 +++++ constant/http.go | 5 +++++ 3 files changed, 12 insertions(+), 4 deletions(-) create mode 100644 constant/http.go diff --git a/component/http/http.go b/component/http/http.go index bcede09f..c5172fcb 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -10,14 +10,12 @@ import ( "time" "github.com/Dreamacro/clash/component/tls" + C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/listener/inner" ) -const ( - UA = "clash.meta" -) - func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) { + UA := C.UA method = strings.ToUpper(method) urlRes, err := URL.Parse(url) if err != nil { diff --git a/config/config.go b/config/config.go index 4421adc2..56c616d0 100644 --- a/config/config.go +++ b/config/config.go @@ -60,6 +60,7 @@ type General struct { Sniffing bool `json:"sniffing"` EBpf EBpf `json:"-"` GlobalClientFingerprint string `json:"global-client-fingerprint"` + GlobalUA string `json:"global-ua"` KeepAliveInterval int `json:"keep-alive-interval"` } @@ -284,6 +285,7 @@ type RawConfig struct { TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` GlobalClientFingerprint string `yaml:"global-client-fingerprint"` + GlobalUA string `yaml:"global-ua"` KeepAliveInterval int `yaml:"keep-alive-interval"` Sniffer RawSniffer `yaml:"sniffer"` @@ -370,6 +372,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { ProxyGroup: []map[string]any{}, TCPConcurrent: false, FindProcessMode: P.FindProcessStrict, + GlobalUA: "clash.meta", Tun: RawTun{ Enable: false, Device: "", @@ -571,6 +574,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { C.GeoSiteUrl = cfg.GeoXUrl.GeoSite C.MmdbUrl = cfg.GeoXUrl.Mmdb C.GeodataMode = cfg.GeodataMode + C.UA = cfg.GlobalUA if cfg.KeepAliveInterval != 0 { N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second } @@ -617,6 +621,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { FindProcessMode: cfg.FindProcessMode, EBpf: cfg.EBpf, GlobalClientFingerprint: cfg.GlobalClientFingerprint, + GlobalUA: cfg.GlobalUA, KeepAliveInterval: cfg.KeepAliveInterval, }, nil } diff --git a/constant/http.go b/constant/http.go new file mode 100644 index 00000000..8e321f6b --- /dev/null +++ b/constant/http.go @@ -0,0 +1,5 @@ +package constant + +var ( + UA string +) From 90acce7fa15884eabd8ee8f0783cdc26b9d1c6ab Mon Sep 17 00:00:00 2001 From: H1JK Date: Fri, 8 Sep 2023 22:58:59 +0800 Subject: [PATCH 412/530] feat: Add disable quic-go GSO to experimental --- config/config.go | 3 ++- docs/config.yaml | 7 +++++++ hub/executor/executor.go | 3 +++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index 56c616d0..db021618 100644 --- a/config/config.go +++ b/config/config.go @@ -156,7 +156,8 @@ type Sniffer struct { // Experimental config type Experimental struct { - Fingerprints []string `yaml:"fingerprints"` + Fingerprints []string `yaml:"fingerprints"` + QUICGoDisableGSO bool `yaml:"quic-go-disable-gso"` } // Config is clash config manager diff --git a/docs/config.yaml b/docs/config.yaml index cd540311..ada57905 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -55,6 +55,13 @@ keep-alive-interval: 15 # routing-mark:6666 # 配置 fwmark 仅用于 Linux experimental: + # Disable quic-go GSO support. This may result in reduced performance on Linux. + # This is not recommended for most users. + # Only users encountering issues with quic-go's internal implementation should enable this, + # and they should disable it as soon as the issue is resolved. + # This field will be removed when quic-go fixes all their issues in GSO. + # This equivalent to the environment variable QUIC_GO_DISABLE_GSO=1. + #quic-go-disable-gso: true # 类似于 /etc/hosts, 仅支持配置单个 IP hosts: diff --git a/hub/executor/executor.go b/hub/executor/executor.go index f4364b7b..b840ba48 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -181,6 +181,9 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList } func updateExperimental(c *config.Config) { + if c.Experimental.QUICGoDisableGSO { + _ = os.Setenv("QUIC_GO_DISABLE_GSO", "1") + } } func updateNTP(c *config.NTP) { From f241e1f81a53ffed8283c2fd1ab360ca40083318 Mon Sep 17 00:00:00 2001 From: H1JK Date: Sat, 9 Sep 2023 09:53:14 +0800 Subject: [PATCH 413/530] chore: Update dependencies --- go.mod | 26 ++++++++--------- go.sum | 53 ++++++++++++++++++----------------- test/go.mod | 27 +++++++++--------- test/go.sum | 81 +++++++++++++++++------------------------------------ 4 files changed, 79 insertions(+), 108 deletions(-) diff --git a/go.mod b/go.mod index aa37eff2..f75f58fd 100644 --- a/go.mod +++ b/go.mod @@ -13,13 +13,13 @@ require ( 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/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c + github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a 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.38.1-0.20230821081539-517fdb17fb28 + github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf github.com/metacubex/sing-shadowsocks v0.2.4 github.com/metacubex/sing-shadowsocks2 v0.1.3 github.com/metacubex/sing-tun v0.1.11 @@ -38,17 +38,17 @@ require ( github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f github.com/samber/lo v1.38.1 - github.com/shirou/gopsutil/v3 v3.23.7 + github.com/shirou/gopsutil/v3 v3.23.8 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.3 - golang.org/x/crypto v0.12.0 - golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb - golang.org/x/net v0.14.0 + golang.org/x/crypto v0.13.0 + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 + golang.org/x/net v0.15.0 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.11.0 + golang.org/x/sys v0.12.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 @@ -84,7 +84,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.2 // indirect + github.com/quic-go/qtls-go1-20 v0.3.3 // 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 @@ -92,16 +92,16 @@ require ( 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/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // 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.11.0 // indirect - golang.org/x/text v0.12.0 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.9.1 // indirect + golang.org/x/tools v0.13.0 // indirect ) replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579 diff --git a/go.sum b/go.sum index 530b615d..59d83450 100644 --- a/go.sum +++ b/go.sum @@ -69,8 +69,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-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs= -github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= +github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a h1:S33o3djA1nPRd+d/bf7jbbXytXuK/EoXow7+aa76grQ= +github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a/go.mod h1:zmdm3sTSDP3vOOX3CEWRkkRHtKr1DxBx+J1OQFoDQQs= 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= @@ -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.38.1-0.20230821081539-517fdb17fb28 h1:ggSo4B1LDH9ZIROoUibxlrUpi7YCMri7HMXn4aNQkiM= -github.com/metacubex/quic-go v0.38.1-0.20230821081539-517fdb17fb28/go.mod h1:SthFvvoqgrEUgIxQXRnqdUAAYQECBavkhl7iA0geVd8= +github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= +github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579 h1:dE1dBB6CTzNdSMFTE5OCHvzHLewiqiA1nhD+7egtvAc= github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= github.com/metacubex/sing-shadowsocks v0.2.4 h1:Gc99Z17JVif1PKKq1pjqhSmc2kvHUgk+AqxOstCzhQ0= @@ -136,8 +136,8 @@ github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErp github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= 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.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= -github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= +github.com/quic-go/qtls-go1-20 v0.3.3/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= @@ -159,8 +159,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.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= -github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4= +github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= +github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= 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= @@ -183,10 +183,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.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= -github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= 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= @@ -207,20 +207,20 @@ 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.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-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= -golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 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.11.0 h1:bUO06HqtnRcc/7l71XBe4WcqTZ+3AH1J59zWDDwLKgU= -golang.org/x/mod v0.11.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.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.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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= @@ -239,24 +239,25 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-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/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/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.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.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc= -golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.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.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.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 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= diff --git a/test/go.mod b/test/go.mod index 2d7ef893..5582dd04 100644 --- a/test/go.mod +++ b/test/go.mod @@ -8,7 +8,7 @@ require ( github.com/docker/go-connections v0.4.0 github.com/miekg/dns v1.1.55 github.com/stretchr/testify v1.8.4 - golang.org/x/net v0.14.0 + golang.org/x/net v0.15.0 ) replace github.com/Dreamacro/clash => ../ @@ -20,7 +20,6 @@ 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/beevik/ntp v1.3.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 @@ -43,7 +42,7 @@ require ( 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-20230731140434-0f9eb93a696c // indirect + github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a // indirect github.com/josharian/native v1.1.0 // indirect github.com/jpillora/backoff v1.0.0 // indirect github.com/klauspost/compress v1.16.7 // indirect @@ -54,7 +53,7 @@ require ( 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-20230611153922-78842f086475 // indirect - github.com/metacubex/quic-go v0.38.1-0.20230821081539-517fdb17fb28 // indirect + github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf // 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 @@ -75,7 +74,7 @@ require ( github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect github.com/puzpuzpuz/xsync/v2 v2.5.0 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.2 // indirect + github.com/quic-go/qtls-go1-20 v0.3.3 // 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.10-0.20230807080248-4db0062caa0a // indirect @@ -87,28 +86,28 @@ require ( github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f // 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.7 // indirect + github.com/shirou/gopsutil/v3 v3.23.8 // 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.3 // indirect - github.com/tklauser/go-sysconf v0.3.11 // indirect - github.com/tklauser/numcpus v0.6.0 // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // 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.12.0 // indirect - golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb // indirect - golang.org/x/mod v0.11.0 // indirect + golang.org/x/crypto v0.13.0 // indirect + golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect + golang.org/x/mod v0.12.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/sys v0.12.0 // indirect + golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.9.1 // indirect + golang.org/x/tools v0.13.0 // 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 03971c26..609d2fcb 100644 --- a/test/go.sum +++ b/test/go.sum @@ -11,8 +11,6 @@ github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmH github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= -github.com/beevik/ntp v1.3.0 h1:/w5VhpW5BGKS37vFm1p9oVk/t4HnnkKZAZIubHM6F7Q= -github.com/beevik/ntp v1.3.0/go.mod h1:vD6h1um4kzXpqmLTuu0cCLcC+NfvC0IC+ltmEDA8E78= github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= 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= @@ -76,8 +74,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-20230731140434-0f9eb93a696c h1:P/3mFnHCv1A/ej4m8pF5EB6FUt9qEL2Q9lfrcUNwCYs= -github.com/insomniacslk/dhcp v0.0.0-20230731140434-0f9eb93a696c/go.mod h1:7474bZ1YNCvarT6WFKie4kEET6J0KYRDC4XJqqXzQW4= +github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a h1:S33o3djA1nPRd+d/bf7jbbXytXuK/EoXow7+aa76grQ= +github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a/go.mod h1:zmdm3sTSDP3vOOX3CEWRkkRHtKr1DxBx+J1OQFoDQQs= 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= @@ -103,8 +101,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.38.1-0.20230821081539-517fdb17fb28 h1:ggSo4B1LDH9ZIROoUibxlrUpi7YCMri7HMXn4aNQkiM= -github.com/metacubex/quic-go v0.38.1-0.20230821081539-517fdb17fb28/go.mod h1:SthFvvoqgrEUgIxQXRnqdUAAYQECBavkhl7iA0geVd8= +github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= +github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= 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= @@ -151,8 +149,8 @@ github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErp github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= 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.2 h1:rRgN3WfnKbyik4dBV8A6girlJVxGand/d+jVKbQq5GI= -github.com/quic-go/qtls-go1-20 v0.3.2/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= +github.com/quic-go/qtls-go1-20 v0.3.3/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= @@ -178,8 +176,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.7 h1:C+fHO8hfIppoJ1WdsVm1RoI0RwXoNdfTK7yWXV0wVj4= -github.com/shirou/gopsutil/v3 v3.23.7/go.mod h1:c4gnmoRC0hQuaLqvxnx1//VXQ0Ms/X9UnJF8pddY5z4= +github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= +github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= 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= @@ -202,10 +200,10 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.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= -github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= 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= @@ -216,7 +214,6 @@ github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1 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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 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= @@ -228,39 +225,28 @@ 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.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= -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-20230811145659-89c5cff77bcb h1:mIKbk8weKhSeLH2GmUTrvx8CjkyJmnU1wFmg59CUjFA= -golang.org/x/exp v0.0.0-20230811145659-89c5cff77bcb/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= +golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= +golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 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.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -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/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.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-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= -golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= -golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14= -golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI= +golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= +golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.1.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= @@ -275,33 +261,20 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w 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= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.9.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/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= -golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.10.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/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= +golang.org/x/text v0.13.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= @@ -310,10 +283,8 @@ golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapK 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.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -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/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= +golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= 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= From af99b52527535aa578434c61b25d945020a7e467 Mon Sep 17 00:00:00 2001 From: kunish Date: Sat, 9 Sep 2023 13:06:49 +0800 Subject: [PATCH 414/530] docs(README): update dashboard section --- README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 9339a935..51cecc2d 100644 --- a/README.md +++ b/README.md @@ -24,13 +24,22 @@ - VMess, Shadowsocks, Trojan, Snell protocol support for remote connections - Built-in DNS server that aims to minimize DNS pollution attack impact, supports DoH/DoT upstream and fake IP. - Rules based off domains, GEOIP, IPCIDR or Process to forward packets to different nodes -- Remote groups allow users to implement powerful rules. Supports automatic fallback, load balancing or auto select node based off latency -- Remote providers, allowing users to get node lists remotely instead of hardcoding in config +- Remote groups allow users to implement powerful rules. Supports automatic fallback, load balancing or auto select node + based off latency +- Remote providers, allowing users to get node lists remotely instead of hard-coding in config - Netfilter TCP redirecting. Deploy Clash on your Internet gateway with `iptables`. - Comprehensive HTTP RESTful API controller +## Dashboard + +We made an official web dashboard providing first class support for this project, check it out +at [metacubexd](https://github.com/MetaCubeX/metacubexd) + ## Wiki -Configuration examples can be found at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml), while documentation can be found [Clash.Meta Wiki](https://clash-meta.wiki). + +Configuration examples can be found +at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml), while documentation can be +found [Clash.Meta Wiki](https://clash-meta.wiki). ## Build @@ -43,7 +52,7 @@ git clone https://github.com/MetaCubeX/Clash.Meta.git cd Clash.Meta && go mod download ``` -If you can't visit github,you should set proxy first: +If you can't visit GitHub, you should set proxy first: ```shell go env -w GOPROXY=https://goproxy.io,direct @@ -324,36 +333,27 @@ ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta WantedBy=multi-user.target ``` -Launch clashd on system startup with: +Launch clash-meta daemon on system startup with: ```shell $ systemctl enable Clash-Meta ``` -Launch clashd immediately with: +Launch clash-meta daemon immediately with: ```shell $ systemctl start Clash-Meta ``` -### Display Process name - -Clash add field `Process` to `Metadata` and prepare to get process name for Restful API `GET /connections`. - -To display process name in GUI please use [Razord-meta](https://github.com/MetaCubeX/Razord-meta). - -### Dashboard - -We also made a custom fork of yacd provide better support for this project, check it out at [Yacd-meta](https://github.com/MetaCubeX/Yacd-meta) - ## Development -If you want to build an application that uses clash as a library, check out the +If you want to build an application that uses clash as a library, check out the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library) ## Debugging -Check [wiki](https://github.com/MetaCubeX/Clash.Meta/wiki/How-to-use-debug-api) to get an instruction on using debug API. +Check [wiki](https://github.com/MetaCubeX/Clash.Meta/wiki/How-to-use-debug-api) to get an instruction on using debug +API. ## Credits From c3d72f6883d991a9dbcbdb9e54dcd838864a07f1 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+larvan2@users.noreply.github.com> Date: Fri, 15 Sep 2023 23:25:56 +0800 Subject: [PATCH 415/530] feat: download/upgrade XD to external-ui --- config/{updateGeo.go => update_geo.go} | 22 ----- config/update_xd.go | 123 +++++++++++++++++++++++++ config/utils.go | 22 +++++ constant/path.go | 1 + hub/route/server.go | 1 + hub/route/upgrade.go | 17 ++++ hub/updater/updater.go | 2 +- 7 files changed, 165 insertions(+), 23 deletions(-) rename config/{updateGeo.go => update_geo.go} (75%) create mode 100644 config/update_xd.go diff --git a/config/updateGeo.go b/config/update_geo.go similarity index 75% rename from config/updateGeo.go rename to config/update_geo.go index b75d3184..07f211e4 100644 --- a/config/updateGeo.go +++ b/config/update_geo.go @@ -1,17 +1,11 @@ package config import ( - "context" "fmt" - "io" - "net/http" - "os" "runtime" - "time" "github.com/Dreamacro/clash/component/geodata" _ "github.com/Dreamacro/clash/component/geodata/standard" - clashHttp "github.com/Dreamacro/clash/component/http" C "github.com/Dreamacro/clash/constant" "github.com/oschwald/maxminddb-golang" @@ -72,19 +66,3 @@ func UpdateGeoDatabases() error { return nil } - -func downloadForBytes(url string) ([]byte, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) - defer cancel() - resp, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) - if err != nil { - return nil, err - } - defer resp.Body.Close() - - return io.ReadAll(resp.Body) -} - -func saveFile(bytes []byte, path string) error { - return os.WriteFile(path, bytes, 0o644) -} diff --git a/config/update_xd.go b/config/update_xd.go new file mode 100644 index 00000000..696768b4 --- /dev/null +++ b/config/update_xd.go @@ -0,0 +1,123 @@ +package config + +import ( + "archive/zip" + "fmt" + "io" + "os" + "path" + "path/filepath" + "strings" + "sync" + + C "github.com/Dreamacro/clash/constant" +) + +const xdURL = "https://codeload.github.com/MetaCubeX/metacubexd/zip/refs/heads/gh-pages" + +var xdMutex sync.Mutex + +func UpdateXD() error { + xdMutex.Lock() + defer xdMutex.Unlock() + + err := cleanup(C.UIPath) + if err != nil { + return fmt.Errorf("cleanup exist file error: %w", err) + } + + data, err := downloadForBytes(xdURL) + if err != nil { + return fmt.Errorf("can't download XD file: %w", err) + } + + saved := path.Join(C.UIPath, "xd.zip") + if saveFile(data, saved) != nil { + return fmt.Errorf("can't save XD zip file: %w", err) + } + defer os.Remove(saved) + + err = unzip(saved, C.UIPath) + if err != nil { + return fmt.Errorf("can't extract XD zip file: %w", err) + } + + err = os.Rename(path.Join(C.UIPath, "metacubexd-gh-pages"), path.Join(C.UIPath, "xd")) + if err != nil { + return fmt.Errorf("can't rename folder: %w", err) + } + return nil +} + +func unzip(src, dest string) error { + r, err := zip.OpenReader(src) + if err != nil { + return err + } + defer r.Close() + + for _, f := range r.File { + fpath := filepath.Join(dest, f.Name) + + if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { + return fmt.Errorf("invalid file path: %s", fpath) + } + + if f.FileInfo().IsDir() { + os.MkdirAll(fpath, os.ModePerm) + continue + } + + if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { + return err + } + + outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) + if err != nil { + return err + } + + rc, err := f.Open() + if err != nil { + return err + } + + _, err = io.Copy(outFile, rc) + + outFile.Close() + rc.Close() + + if err != nil { + return err + } + } + return nil +} + +func cleanup(root string) error { + return filepath.Walk(root, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if path == root { + // skip root itself + return nil + } + if info.IsDir() { + if err := os.RemoveAll(path); err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + } else { + if err := os.Remove(path); err != nil { + if os.IsNotExist(err) { + return nil + } + return err + } + } + return nil + }) +} diff --git a/config/utils.go b/config/utils.go index 799082c4..1fa54634 100644 --- a/config/utils.go +++ b/config/utils.go @@ -1,15 +1,37 @@ package config import ( + "context" "fmt" + "io" "net" + "net/http" "net/netip" + "os" "strings" + "time" "github.com/Dreamacro/clash/adapter/outboundgroup" "github.com/Dreamacro/clash/common/structure" + clashHttp "github.com/Dreamacro/clash/component/http" ) +func downloadForBytes(url string) ([]byte, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) + defer cancel() + resp, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + return io.ReadAll(resp.Body) +} + +func saveFile(bytes []byte, path string) error { + return os.WriteFile(path, bytes, 0o644) +} + func trimArr(arr []string) (r []string) { for _, e := range arr { r = append(r, strings.Trim(e, " ")) diff --git a/constant/path.go b/constant/path.go index d7477e0e..e595d920 100644 --- a/constant/path.go +++ b/constant/path.go @@ -15,6 +15,7 @@ const Name = "clash" var ( GeositeName = "GeoSite.dat" GeoipName = "GeoIP.dat" + UIPath = "" ) // Path is used to get the configuration path diff --git a/hub/route/server.go b/hub/route/server.go index d2fecd05..3df6196a 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -49,6 +49,7 @@ type Memory struct { func SetUIPath(path string) { uiPath = C.Path.Resolve(path) + C.UIPath = uiPath } func Start(addr string, tlsAddr string, secret string, diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index 5e75bc8b..ef5dffaf 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -5,6 +5,7 @@ import ( "net/http" "os" + "github.com/Dreamacro/clash/config" "github.com/Dreamacro/clash/hub/updater" "github.com/Dreamacro/clash/log" @@ -15,6 +16,7 @@ import ( func upgradeRouter() http.Handler { r := chi.NewRouter() r.Post("/", upgrade) + r.Post("/xd", updateXD) return r } @@ -43,3 +45,18 @@ func upgrade(w http.ResponseWriter, r *http.Request) { go restartExecutable(execPath) } + +func updateXD(w http.ResponseWriter, r *http.Request) { + err := config.UpdateXD() + if err != nil { + log.Warnln("%s", err) + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, newError(fmt.Sprintf("%s", err))) + return + } + + render.JSON(w, r, render.M{"status": "ok"}) + if f, ok := w.(http.Flusher); ok { + f.Flush() + } +} diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 90b14c27..1a930c03 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -32,7 +32,7 @@ var ( workDir string // mu protects all fields below. - mu sync.RWMutex + mu sync.Mutex currentExeName string // 当前可执行文件 updateDir string // 更新目录 From fa49fd7ba2efbae8cb9b00bf5cf786ea940037d2 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+larvan2@users.noreply.github.com> Date: Fri, 15 Sep 2023 23:15:05 +0800 Subject: [PATCH 416/530] chore: use cmp in go 1.21 Co-authored-by: H1JK --- transport/hysteria/pmtud_fix/avail.go | 3 +-- transport/hysteria/pmtud_fix/unavail.go | 3 +-- transport/tuic/congestion/minmax.go | 16 ---------------- transport/tuic/congestion/minmax_go120.go | 19 +++++++++++++++++++ transport/tuic/congestion/minmax_go121.go | 13 +++++++++++++ 5 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 transport/tuic/congestion/minmax_go120.go create mode 100644 transport/tuic/congestion/minmax_go121.go diff --git a/transport/hysteria/pmtud_fix/avail.go b/transport/hysteria/pmtud_fix/avail.go index 2f2bce83..af248f5c 100644 --- a/transport/hysteria/pmtud_fix/avail.go +++ b/transport/hysteria/pmtud_fix/avail.go @@ -1,5 +1,4 @@ -//go:build linux || windows -// +build linux windows +//go:build linux || windows || darwin package pmtud_fix diff --git a/transport/hysteria/pmtud_fix/unavail.go b/transport/hysteria/pmtud_fix/unavail.go index 0eeb83df..35b849d2 100644 --- a/transport/hysteria/pmtud_fix/unavail.go +++ b/transport/hysteria/pmtud_fix/unavail.go @@ -1,5 +1,4 @@ -//go:build !linux && !windows -// +build !linux,!windows +//go:build !linux && !windows && !darwin package pmtud_fix diff --git a/transport/tuic/congestion/minmax.go b/transport/tuic/congestion/minmax.go index ed75072e..0a8f4ad4 100644 --- a/transport/tuic/congestion/minmax.go +++ b/transport/tuic/congestion/minmax.go @@ -3,27 +3,11 @@ package congestion import ( "math" "time" - - "golang.org/x/exp/constraints" ) // InfDuration is a duration of infinite length const InfDuration = time.Duration(math.MaxInt64) -func Max[T constraints.Ordered](a, b T) T { - if a < b { - return b - } - return a -} - -func Min[T constraints.Ordered](a, b T) T { - if a < b { - return a - } - return b -} - // MinNonZeroDuration return the minimum duration that's not zero. func MinNonZeroDuration(a, b time.Duration) time.Duration { if a == 0 { diff --git a/transport/tuic/congestion/minmax_go120.go b/transport/tuic/congestion/minmax_go120.go new file mode 100644 index 00000000..1266edbc --- /dev/null +++ b/transport/tuic/congestion/minmax_go120.go @@ -0,0 +1,19 @@ +//go:build !go1.21 + +package congestion + +import "golang.org/x/exp/constraints" + +func Max[T constraints.Ordered](a, b T) T { + if a < b { + return b + } + return a +} + +func Min[T constraints.Ordered](a, b T) T { + if a < b { + return a + } + return b +} diff --git a/transport/tuic/congestion/minmax_go121.go b/transport/tuic/congestion/minmax_go121.go new file mode 100644 index 00000000..65b06726 --- /dev/null +++ b/transport/tuic/congestion/minmax_go121.go @@ -0,0 +1,13 @@ +//go:build go1.21 + +package congestion + +import "cmp" + +func Max[T cmp.Ordered](a, b T) T { + return max(a, b) +} + +func Min[T cmp.Ordered](a, b T) T { + return min(a, b) +} From 2d3b9364bf0e6867c34d99d98b464cd9c733e340 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Sat, 16 Sep 2023 12:29:49 +0800 Subject: [PATCH 417/530] fix: caceh dns result --- dns/resolver.go | 1 + 1 file changed, 1 insertion(+) diff --git a/dns/resolver.go b/dns/resolver.go index 8f41a44e..89e36214 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -200,6 +200,7 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M isIPReq := isIPRequest(q) if isIPReq { + cache=true return r.ipExchange(ctx, m) } From 33d41338ef00ff20e444e03f3d9ee7b60fc787a4 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 17 Sep 2023 17:05:13 +0800 Subject: [PATCH 418/530] migration: go 1.21 --- adapter/adapter.go | 12 ++++++------ common/observable/observable_test.go | 6 +++--- go.mod | 2 +- hub/updater/limitedreader.go | 13 +------------ transport/tuic/congestion/cubic.go | 2 +- transport/tuic/congestion/cubic_sender.go | 4 ++-- .../tuic/congestion/hybrid_slow_start.go | 4 ++-- transport/tuic/congestion/minmax.go | 2 +- transport/tuic/congestion/minmax_go120.go | 19 ------------------- transport/tuic/congestion/minmax_go121.go | 13 ------------- transport/tuic/congestion/pacer.go | 6 +++--- 11 files changed, 20 insertions(+), 63 deletions(-) delete mode 100644 transport/tuic/congestion/minmax_go120.go delete mode 100644 transport/tuic/congestion/minmax_go121.go diff --git a/adapter/adapter.go b/adapter/adapter.go index 13f7f06f..abef3d89 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -136,21 +136,21 @@ func (p *Proxy) ExtraDelayHistory() map[string][]C.DelayHistory { // 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) { - var max uint16 = 0xffff + var maxDelay uint16 = 0xffff if !p.alive.Load() { - return max + return maxDelay } history := p.history.Last() if history.Delay == 0 { - return max + return maxDelay } return history.Delay } // LastDelayForTestUrl implements C.Proxy func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { - var max uint16 = 0xffff + var maxDelay uint16 = 0xffff alive := p.alive.Load() history := p.history.Last() @@ -161,11 +161,11 @@ func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { } if !alive { - return max + return maxDelay } if history.Delay == 0 { - return max + return maxDelay } return history.Delay } diff --git a/common/observable/observable_test.go b/common/observable/observable_test.go index 5a02273d..3f0b0e7f 100644 --- a/common/observable/observable_test.go +++ b/common/observable/observable_test.go @@ -85,16 +85,16 @@ func TestObservable_UnSubscribeWithNotExistSubscription(t *testing.T) { func TestObservable_SubscribeGoroutineLeak(t *testing.T) { iter := iterator[int]([]int{1, 2, 3, 4, 5}) src := NewObservable[int](iter) - max := 100 + total := 100 var list []Subscription[int] - for i := 0; i < max; i++ { + for i := 0; i < total; i++ { ch, _ := src.Subscribe() list = append(list, ch) } var wg sync.WaitGroup - wg.Add(max) + wg.Add(total) waitCh := func(ch <-chan int) { for range ch { } diff --git a/go.mod b/go.mod index f75f58fd..ca98937b 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Dreamacro/clash -go 1.20 +go 1.21 require ( github.com/3andne/restls-client-go v0.1.6 diff --git a/hub/updater/limitedreader.go b/hub/updater/limitedreader.go index c31db601..52d7e969 100644 --- a/hub/updater/limitedreader.go +++ b/hub/updater/limitedreader.go @@ -3,8 +3,6 @@ package updater import ( "fmt" "io" - - "golang.org/x/exp/constraints" ) // LimitReachedError records the limit and the operation that caused it. @@ -35,7 +33,7 @@ func (lr *limitedReader) Read(p []byte) (n int, err error) { } } - p = p[:Min(lr.n, int64(len(p)))] + p = p[:min(lr.n, int64(len(p)))] n, err = lr.r.Read(p) lr.n -= int64(n) @@ -56,12 +54,3 @@ func LimitReader(r io.Reader, n int64) (limited io.Reader, err error) { n: n, }, nil } - -// Min returns the smaller of x or y. -func Min[T constraints.Integer | ~string](x, y T) (res T) { - if x < y { - return x - } - - return y -} diff --git a/transport/tuic/congestion/cubic.go b/transport/tuic/congestion/cubic.go index dd491a32..7dbe2b06 100644 --- a/transport/tuic/congestion/cubic.go +++ b/transport/tuic/congestion/cubic.go @@ -186,7 +186,7 @@ func (c *Cubic) CongestionWindowAfterAck( targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow } // Limit the CWND increase to half the acked bytes. - targetCongestionWindow = Min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) + targetCongestionWindow = min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) // Increase the window by approximately Alpha * 1 MSS of bytes every // time we ack an estimated tcp window of bytes. For small diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go index ca20b420..a467b8c9 100644 --- a/transport/tuic/congestion/cubic_sender.go +++ b/transport/tuic/congestion/cubic_sender.go @@ -177,7 +177,7 @@ func (c *cubicSender) OnPacketAcked( priorInFlight congestion.ByteCount, eventTime time.Time, ) { - c.largestAckedPacketNumber = Max(ackedPacketNumber, c.largestAckedPacketNumber) + c.largestAckedPacketNumber = max(ackedPacketNumber, c.largestAckedPacketNumber) if c.InRecovery() { return } @@ -245,7 +245,7 @@ func (c *cubicSender) maybeIncreaseCwnd( c.numAckedPackets = 0 } } else { - c.congestionWindow = Min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) + c.congestionWindow = min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) } } diff --git a/transport/tuic/congestion/hybrid_slow_start.go b/transport/tuic/congestion/hybrid_slow_start.go index 7586774e..e0b42e53 100644 --- a/transport/tuic/congestion/hybrid_slow_start.go +++ b/transport/tuic/congestion/hybrid_slow_start.go @@ -74,8 +74,8 @@ func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT ti // Divide minRTT by 8 to get a rtt increase threshold for exiting. minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp) // Ensure the rtt threshold is never less than 2ms or more than 16ms. - minRTTincreaseThresholdUs = Min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) - minRTTincreaseThreshold := time.Duration(Max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond + minRTTincreaseThresholdUs = min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) + minRTTincreaseThreshold := time.Duration(max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) { s.hystartFound = true diff --git a/transport/tuic/congestion/minmax.go b/transport/tuic/congestion/minmax.go index 0a8f4ad4..50667766 100644 --- a/transport/tuic/congestion/minmax.go +++ b/transport/tuic/congestion/minmax.go @@ -16,7 +16,7 @@ func MinNonZeroDuration(a, b time.Duration) time.Duration { if b == 0 { return a } - return Min(a, b) + return min(a, b) } // AbsDuration returns the absolute value of a time duration diff --git a/transport/tuic/congestion/minmax_go120.go b/transport/tuic/congestion/minmax_go120.go deleted file mode 100644 index 1266edbc..00000000 --- a/transport/tuic/congestion/minmax_go120.go +++ /dev/null @@ -1,19 +0,0 @@ -//go:build !go1.21 - -package congestion - -import "golang.org/x/exp/constraints" - -func Max[T constraints.Ordered](a, b T) T { - if a < b { - return b - } - return a -} - -func Min[T constraints.Ordered](a, b T) T { - if a < b { - return a - } - return b -} diff --git a/transport/tuic/congestion/minmax_go121.go b/transport/tuic/congestion/minmax_go121.go deleted file mode 100644 index 65b06726..00000000 --- a/transport/tuic/congestion/minmax_go121.go +++ /dev/null @@ -1,13 +0,0 @@ -//go:build go1.21 - -package congestion - -import "cmp" - -func Max[T cmp.Ordered](a, b T) T { - return max(a, b) -} - -func Min[T cmp.Ordered](a, b T) T { - return min(a, b) -} diff --git a/transport/tuic/congestion/pacer.go b/transport/tuic/congestion/pacer.go index f60ef5fe..9e85107d 100644 --- a/transport/tuic/congestion/pacer.go +++ b/transport/tuic/congestion/pacer.go @@ -52,11 +52,11 @@ func (p *pacer) Budget(now time.Time) congestion.ByteCount { return p.maxBurstSize() } budget := p.budgetAtLastSent + (congestion.ByteCount(p.getAdjustedBandwidth())*congestion.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9 - return Min(p.maxBurstSize(), budget) + return min(p.maxBurstSize(), budget) } func (p *pacer) maxBurstSize() congestion.ByteCount { - return Max( + return max( congestion.ByteCount(uint64((MinPacingDelay+TimerGranularity).Nanoseconds())*p.getAdjustedBandwidth())/1e9, maxBurstSizePackets*p.maxDatagramSize, ) @@ -68,7 +68,7 @@ func (p *pacer) TimeUntilSend() time.Time { if p.budgetAtLastSent >= p.maxDatagramSize { return time.Time{} } - return p.lastSentTime.Add(Max( + return p.lastSentTime.Add(max( MinPacingDelay, time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.getAdjustedBandwidth())))*time.Nanosecond, )) From 6a5a94f48f87bf30d2a31877596566b8b21c2001 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 17 Sep 2023 17:18:35 +0800 Subject: [PATCH 419/530] chore: DNS cache policy follow upstream --- dns/util.go | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/dns/util.go b/dns/util.go index 77f677cb..c9d48a49 100644 --- a/dns/util.go +++ b/dns/util.go @@ -30,9 +30,13 @@ const ( ) func minimalTTL(records []D.RR) uint32 { - return lo.MinBy(records, func(r1 D.RR, r2 D.RR) bool { + minObj := lo.MinBy(records, func(r1 D.RR, r2 D.RR) bool { return r1.Header().Ttl < r2.Header().Ttl - }).Header().Ttl + }) + if minObj != nil { + return minObj.Header().Ttl + } + return 0 } func updateTTL(records []D.RR, ttl uint32) { @@ -46,27 +50,25 @@ func updateTTL(records []D.RR, ttl uint32) { } func putMsgToCache(c *cache.LruCache[string, *D.Msg], key string, msg *D.Msg) { - // skip dns cache for acme challenge - if len(msg.Question) != 0 { - if q := msg.Question[0]; q.Qtype == D.TypeTXT && strings.HasPrefix(q.Name, "_acme-challenge") { - log.Debugln("[DNS] dns cache ignored because of acme challenge for: %s", q.Name) + putMsgToCacheWithExpire(c, key, msg, 0) +} + +func putMsgToCacheWithExpire(c *cache.LruCache[string, *D.Msg], key string, msg *D.Msg, sec uint32) { + if sec == 0 { + if sec = minimalTTL(msg.Answer); sec == 0 { + if sec = minimalTTL(msg.Ns); sec == 0 { + sec = minimalTTL(msg.Extra) + } + } + if sec == 0 { return } - } - var ttl uint32 - switch { - case len(msg.Answer) != 0: - ttl = minimalTTL(msg.Answer) - case len(msg.Ns) != 0: - ttl = minimalTTL(msg.Ns) - case len(msg.Extra) != 0: - ttl = minimalTTL(msg.Extra) - default: - log.Debugln("[DNS] response msg empty: %#v", msg) - return + + sec = max(sec, 120) // at least 2 minutes to cache + } - c.SetWithExpire(key, msg.Copy(), time.Now().Add(time.Second*time.Duration(ttl))) + c.SetWithExpire(key, msg.Copy(), time.Now().Add(time.Duration(sec)*time.Second)) } func setMsgTTL(msg *D.Msg, ttl uint32) { From 7c21768e9956745523b10265f250c54512c5c065 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 18 Sep 2023 19:21:30 +0800 Subject: [PATCH 420/530] feat: update external-ui --- config/config.go | 35 ++++++++++-- config/{update_xd.go => update_ui.go} | 79 +++++++++++++-------------- constant/path.go | 1 - docs/config.yaml | 6 +- hub/route/server.go | 1 - hub/route/upgrade.go | 6 +- 6 files changed, 75 insertions(+), 53 deletions(-) rename config/{update_xd.go => update_ui.go} (54%) diff --git a/config/config.go b/config/config.go index db021618..a2e64026 100644 --- a/config/config.go +++ b/config/config.go @@ -8,6 +8,8 @@ import ( "net/netip" "net/url" "os" + "path" + "path/filepath" "regexp" "strings" "time" @@ -277,6 +279,8 @@ type RawConfig struct { ExternalController string `yaml:"external-controller"` ExternalControllerTLS string `yaml:"external-controller-tls"` ExternalUI string `yaml:"external-ui"` + ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"` + ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"` Secret string `yaml:"secret"` Interface string `yaml:"interface-name"` RoutingMark int `yaml:"routing-mark"` @@ -569,7 +573,6 @@ 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 @@ -580,14 +583,34 @@ func parseGeneral(cfg *RawConfig) (*General, error) { N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second } - log.Debugln("TCP Keep Alive Interval set %+v", N.KeepAliveInterval) + if cfg.ExternalUIURL != "" { + ExternalUIURL = cfg.ExternalUIURL + } + ExternalUIPath = cfg.ExternalUI // checkout externalUI exist - if externalUI != "" { - externalUI = C.Path.Resolve(externalUI) - if _, err := os.Stat(externalUI); os.IsNotExist(err) { - return nil, fmt.Errorf("external-ui: %s not exist", externalUI) + if ExternalUIPath != "" { + ExternalUIPath = C.Path.Resolve(ExternalUIPath) + if _, err := os.Stat(ExternalUIPath); os.IsNotExist(err) { + defaultUIpath := path.Join(C.Path.HomeDir(), "ui") + log.Warnln("external-ui: %s does not exist, creating folder in %s", ExternalUIPath, defaultUIpath) + if err := os.MkdirAll(defaultUIpath, os.ModePerm); err != nil { + return nil, err + } + ExternalUIPath = defaultUIpath + cfg.ExternalUI = defaultUIpath } } + // checkout UIpath/name exist + if cfg.ExternalUIName != "" { + ExternalUIName = cfg.ExternalUIName + ExternalUIFolder = filepath.Clean(path.Join(ExternalUIPath, cfg.ExternalUIName)) + if _, err := os.Stat(ExternalUIPath); os.IsNotExist(err) { + if err := os.MkdirAll(ExternalUIPath, os.ModePerm); err != nil { + return nil, err + } + } + } + cfg.Tun.RedirectToTun = cfg.EBpf.RedirectToTun return &General{ Inbound: Inbound{ diff --git a/config/update_xd.go b/config/update_ui.go similarity index 54% rename from config/update_xd.go rename to config/update_ui.go index 696768b4..81b5bb03 100644 --- a/config/update_xd.go +++ b/config/update_ui.go @@ -9,112 +9,109 @@ import ( "path/filepath" "strings" "sync" - - C "github.com/Dreamacro/clash/constant" ) -const xdURL = "https://codeload.github.com/MetaCubeX/metacubexd/zip/refs/heads/gh-pages" +var ( + ExternalUIURL string + ExternalUIPath string + ExternalUIFolder string + ExternalUIName string +) var xdMutex sync.Mutex -func UpdateXD() error { +func UpdateUI() error { xdMutex.Lock() defer xdMutex.Unlock() - err := cleanup(C.UIPath) - if err != nil { - return fmt.Errorf("cleanup exist file error: %w", err) + if ExternalUIPath == "" || ExternalUIFolder == "" || ExternalUIName == "" { + return fmt.Errorf("ExternalUI configure incomplete") } - data, err := downloadForBytes(xdURL) + err := cleanup(ExternalUIFolder) if err != nil { - return fmt.Errorf("can't download XD file: %w", err) + if !os.IsNotExist(err) { + return fmt.Errorf("cleanup exist file error: %w", err) + } } - saved := path.Join(C.UIPath, "xd.zip") + data, err := downloadForBytes(ExternalUIURL) + if err != nil { + return fmt.Errorf("can't download file: %w", err) + } + + saved := path.Join(ExternalUIPath, "download.zip") if saveFile(data, saved) != nil { - return fmt.Errorf("can't save XD zip file: %w", err) + return fmt.Errorf("can't save zip file: %w", err) } defer os.Remove(saved) - err = unzip(saved, C.UIPath) + unzipFolder, err := unzip(saved, ExternalUIPath) if err != nil { - return fmt.Errorf("can't extract XD zip file: %w", err) + return fmt.Errorf("can't extract zip file: %w", err) } - err = os.Rename(path.Join(C.UIPath, "metacubexd-gh-pages"), path.Join(C.UIPath, "xd")) + err = os.Rename(unzipFolder, ExternalUIFolder) if err != nil { return fmt.Errorf("can't rename folder: %w", err) } return nil } -func unzip(src, dest string) error { +func unzip(src, dest string) (string, error) { r, err := zip.OpenReader(src) if err != nil { - return err + return "", err } defer r.Close() - + var extractedFolder string for _, f := range r.File { fpath := filepath.Join(dest, f.Name) - if !strings.HasPrefix(fpath, filepath.Clean(dest)+string(os.PathSeparator)) { - return fmt.Errorf("invalid file path: %s", fpath) + return "", fmt.Errorf("invalid file path: %s", fpath) } - if f.FileInfo().IsDir() { os.MkdirAll(fpath, os.ModePerm) continue } - if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil { - return err + return "", err } - outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode()) if err != nil { - return err + return "", err } - rc, err := f.Open() if err != nil { - return err + return "", err } - _, err = io.Copy(outFile, rc) - outFile.Close() rc.Close() - if err != nil { - return err + return "", err + } + if extractedFolder == "" { + extractedFolder = filepath.Dir(fpath) } } - return nil + return extractedFolder, nil } func cleanup(root string) error { + if _, err := os.Stat(root); os.IsNotExist(err) { + return nil + } return filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err } - if path == root { - // skip root itself - return nil - } if info.IsDir() { if err := os.RemoveAll(path); err != nil { - if os.IsNotExist(err) { - return nil - } return err } } else { if err := os.Remove(path); err != nil { - if os.IsNotExist(err) { - return nil - } return err } } diff --git a/constant/path.go b/constant/path.go index e595d920..d7477e0e 100644 --- a/constant/path.go +++ b/constant/path.go @@ -15,7 +15,6 @@ const Name = "clash" var ( GeositeName = "GeoSite.dat" GeoipName = "GeoIP.dat" - UIPath = "" ) // Path is used to get the configuration path diff --git a/docs/config.yaml b/docs/config.yaml index ada57905..274eaedd 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -41,7 +41,11 @@ external-controller-tls: 0.0.0.0:9443 # RESTful API HTTPS 监听地址,需要 # secret: "123456" # `Authorization:Bearer ${secret}` # tcp-concurrent: true # TCP 并发连接所有 IP, 将使用最快握手的 TCP -external-ui: /path/to/ui/folder # 配置 WEB UI 目录,使用 http://{{external-controller}}/ui 访问 + +# 配置 WEB UI 目录,使用 http://{{external-controller}}/ui 访问 +external-ui: /path/to/ui/folder/ +external-ui-name: xd +external-ui-url: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip" # interface-name: en0 # 设置出口网卡 diff --git a/hub/route/server.go b/hub/route/server.go index 3df6196a..d2fecd05 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -49,7 +49,6 @@ type Memory struct { func SetUIPath(path string) { uiPath = C.Path.Resolve(path) - C.UIPath = uiPath } func Start(addr string, tlsAddr string, secret string, diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index ef5dffaf..be226616 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -16,7 +16,7 @@ import ( func upgradeRouter() http.Handler { r := chi.NewRouter() r.Post("/", upgrade) - r.Post("/xd", updateXD) + r.Post("/ui", updateUI) return r } @@ -46,8 +46,8 @@ func upgrade(w http.ResponseWriter, r *http.Request) { go restartExecutable(execPath) } -func updateXD(w http.ResponseWriter, r *http.Request) { - err := config.UpdateXD() +func updateUI(w http.ResponseWriter, r *http.Request) { + err := config.UpdateUI() if err != nil { log.Warnln("%s", err) render.Status(r, http.StatusInternalServerError) From fd96efd45697a5278870b0ea4f9893e0ea7b5f7b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 18 Sep 2023 19:36:11 +0800 Subject: [PATCH 421/530] chore: ignore PR when Pre-releasing --- .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 d7cdd6c9..4a65a829 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -209,7 +209,7 @@ jobs: Upload-Prerelease: permissions: write-all - if: ${{ github.ref_type=='branch' }} + if: ${{ github.ref_type=='branch' && github.event_name != 'pull_request' }} needs: [Build] runs-on: ubuntu-latest steps: From 20fafdca65642273eccbfe5df257e780c308812c Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 18 Sep 2023 19:42:08 +0800 Subject: [PATCH 422/530] chore: cleanup code --- config/config.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/config.go b/config/config.go index a2e64026..66815274 100644 --- a/config/config.go +++ b/config/config.go @@ -63,7 +63,6 @@ type General struct { EBpf EBpf `json:"-"` GlobalClientFingerprint string `json:"global-client-fingerprint"` GlobalUA string `json:"global-ua"` - KeepAliveInterval int `json:"keep-alive-interval"` } // Inbound config @@ -646,7 +645,6 @@ func parseGeneral(cfg *RawConfig) (*General, error) { EBpf: cfg.EBpf, GlobalClientFingerprint: cfg.GlobalClientFingerprint, GlobalUA: cfg.GlobalUA, - KeepAliveInterval: cfg.KeepAliveInterval, }, nil } From 8b518161a308c1295aa9a83b185e782b6b7e9211 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Wed, 20 Sep 2023 14:23:58 +0800 Subject: [PATCH 423/530] chore: update external-ui --- config/config.go | 2 ++ config/update_ui.go | 22 ++++++++++++---------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/config/config.go b/config/config.go index 66815274..d0e69e49 100644 --- a/config/config.go +++ b/config/config.go @@ -608,6 +608,8 @@ func parseGeneral(cfg *RawConfig) (*General, error) { return nil, err } } + } else { + ExternalUIFolder = ExternalUIPath } cfg.Tun.RedirectToTun = cfg.EBpf.RedirectToTun diff --git a/config/update_ui.go b/config/update_ui.go index 81b5bb03..5bc2596e 100644 --- a/config/update_ui.go +++ b/config/update_ui.go @@ -9,6 +9,8 @@ import ( "path/filepath" "strings" "sync" + + C "github.com/Dreamacro/clash/constant" ) var ( @@ -24,29 +26,29 @@ func UpdateUI() error { xdMutex.Lock() defer xdMutex.Unlock() - if ExternalUIPath == "" || ExternalUIFolder == "" || ExternalUIName == "" { + if ExternalUIPath == "" || ExternalUIFolder == "" { return fmt.Errorf("ExternalUI configure incomplete") } - err := cleanup(ExternalUIFolder) - if err != nil { - if !os.IsNotExist(err) { - return fmt.Errorf("cleanup exist file error: %w", err) - } - } - data, err := downloadForBytes(ExternalUIURL) if err != nil { return fmt.Errorf("can't download file: %w", err) } - saved := path.Join(ExternalUIPath, "download.zip") + saved := path.Join(C.Path.HomeDir(), "download.zip") if saveFile(data, saved) != nil { return fmt.Errorf("can't save zip file: %w", err) } defer os.Remove(saved) - unzipFolder, err := unzip(saved, ExternalUIPath) + err = cleanup(ExternalUIFolder) + if err != nil { + if !os.IsNotExist(err) { + return fmt.Errorf("cleanup exist file error: %w", err) + } + } + + unzipFolder, err := unzip(saved, C.Path.HomeDir()) if err != nil { return fmt.Errorf("can't extract zip file: %w", err) } From f909b3c0dcde070aaece47d4b83a1178535412f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B1=90=E6=AE=87?= <95160953+xishang0128@users.noreply.github.com> Date: Wed, 20 Sep 2023 15:26:36 +0800 Subject: [PATCH 424/530] chore: Update android-ndk --- .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 4a65a829..defd294b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -147,7 +147,7 @@ jobs: if: ${{ matrix.job.type=='WithCGO' && matrix.job.target=='android' }} id: setup-ndk with: - ndk-version: r25b + ndk-version: r26 add-to-path: false local-cache: true From 0d7a57fa9d3dd098a5d865e3674fd3d38171b1b3 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Thu, 21 Sep 2023 03:40:46 +0800 Subject: [PATCH 425/530] Chore: update github issue template --- .github/ISSUE_TEMPLATE/bug_report.yml | 82 ++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.yml | 36 ++++++++++ 2 files changed, 118 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml create mode 100644 .github/ISSUE_TEMPLATE/feature_request.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 00000000..f8a0f4ae --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,82 @@ +name: Bug report +description: Create a report to help us improve +title: "[Bug] " +body: + - type: checkboxes + id: ensure + attributes: + label: Verify steps + description: " +在提交之前,请确认 +Please verify that you've followed these steps +" + options: + - label: " +确保你使用的是**本仓库**最新的的 clash 或 clash Alpha 版本 +Ensure you are using the latest version of Clash or Clash Premium from **this repository**. +" + required: true + - label: " +如果你可以自己 debug 并解决的话,提交 PR 吧 +Is this something you can **debug and fix**? Send a pull request! Bug fixes and documentation fixes are welcome. +" + required: false + - label: " +我已经在 [Issue Tracker](……/) 中找过我要提出的问题 +I have searched on the [issue tracker](……/) for a related issue. +" + required: true + - label: " +我已经使用 Alpha 分支版本测试过,问题依旧存在 +I have tested using the dev branch, and the issue still exists. +" + required: true + - label: " +我已经仔细看过 [Documentation](https://wiki.metacubex.one/) 并无法自行解决问题 +I have read the [documentation](https://wiki.metacubex.one/) and was unable to solve the issue. +" + required: true + - label: " +这是 Clash 核心的问题,并非我所使用的 Clash 衍生版本(如 OpenClash、KoolClash 等)的特定问题 +This is an issue of the Clash core *per se*, not to the derivatives of Clash, like OpenClash or KoolClash. +" + required: true + - type: input + attributes: + label: Clash version + description: "use `clash -v`" + validations: + required: true + - type: dropdown + id: os + attributes: + label: What OS are you seeing the problem on? + multiple: true + options: + - macOS + - Windows + - Linux + - OpenBSD/FreeBSD + - type: textarea + attributes: + render: yaml + label: "Clash config" + description: " +在下方附上 Clash core 配置文件,请确保配置文件中没有敏感信息(比如:服务器地址,密码,端口等) +Paste the Clash core configuration file below, please make sure that there is no sensitive information in the configuration file (e.g., server address/url, password, port) +" + validations: + required: true + - type: textarea + attributes: + render: shell + label: Clash log + description: " +在下方附上 Clash Core 的日志,log level 使用 DEBUG +Paste the Clash core log below with the log level set to `DEBUG`. +" + - type: textarea + attributes: + label: Description + validations: + required: true \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 00000000..c8f70b19 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,36 @@ +name: Feature request +description: Suggest an idea for this project +title: "[Feature] " +body: + - type: checkboxes + id: ensure + attributes: + label: Verify steps + description: " +在提交之前,请确认 +Please verify that you've followed these steps +" + options: + - label: " +我已经在 [Issue Tracker](……/) 中找过我要提出的请求 +I have searched on the [issue tracker](……/) for a related feature request. +" + required: true + - label: " +我已经仔细看过 [Documentation](https://wiki.metacubex.one/) 并无法找到这个功能 +I have read the [documentation](https://wiki.metacubex.one/) and was unable to solve the issue. +" + required: true + - type: textarea + attributes: + label: Description + description: 请详细、清晰地表达你要提出的论述,例如这个问题如何影响到你?你想实现什么功能?目前 Clash Core 的行为是什麽? + validations: + required: true + - type: textarea + attributes: + label: Possible Solution + description: " +此项非必须,但是如果你有想法的话欢迎提出。 +Not obligatory, but suggest a fix/reason for the bug, or ideas how to implement the addition or change +" \ No newline at end of file From 62266010aca1510d7e10a5cbbbfbbb682b7605fb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 08:25:26 +0800 Subject: [PATCH 426/530] Revert "migration: go 1.21" This reverts commit 33d41338ef00ff20e444e03f3d9ee7b60fc787a4. --- adapter/adapter.go | 12 ++++++------ common/observable/observable_test.go | 6 +++--- go.mod | 2 +- hub/updater/limitedreader.go | 13 ++++++++++++- transport/tuic/congestion/cubic.go | 2 +- transport/tuic/congestion/cubic_sender.go | 4 ++-- .../tuic/congestion/hybrid_slow_start.go | 4 ++-- transport/tuic/congestion/minmax.go | 2 +- transport/tuic/congestion/minmax_go120.go | 19 +++++++++++++++++++ transport/tuic/congestion/minmax_go121.go | 13 +++++++++++++ transport/tuic/congestion/pacer.go | 6 +++--- 11 files changed, 63 insertions(+), 20 deletions(-) create mode 100644 transport/tuic/congestion/minmax_go120.go create mode 100644 transport/tuic/congestion/minmax_go121.go diff --git a/adapter/adapter.go b/adapter/adapter.go index abef3d89..13f7f06f 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -136,21 +136,21 @@ func (p *Proxy) ExtraDelayHistory() map[string][]C.DelayHistory { // 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) { - var maxDelay uint16 = 0xffff + var max uint16 = 0xffff if !p.alive.Load() { - return maxDelay + return max } history := p.history.Last() if history.Delay == 0 { - return maxDelay + return max } return history.Delay } // LastDelayForTestUrl implements C.Proxy func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { - var maxDelay uint16 = 0xffff + var max uint16 = 0xffff alive := p.alive.Load() history := p.history.Last() @@ -161,11 +161,11 @@ func (p *Proxy) LastDelayForTestUrl(url string) (delay uint16) { } if !alive { - return maxDelay + return max } if history.Delay == 0 { - return maxDelay + return max } return history.Delay } diff --git a/common/observable/observable_test.go b/common/observable/observable_test.go index 3f0b0e7f..5a02273d 100644 --- a/common/observable/observable_test.go +++ b/common/observable/observable_test.go @@ -85,16 +85,16 @@ func TestObservable_UnSubscribeWithNotExistSubscription(t *testing.T) { func TestObservable_SubscribeGoroutineLeak(t *testing.T) { iter := iterator[int]([]int{1, 2, 3, 4, 5}) src := NewObservable[int](iter) - total := 100 + max := 100 var list []Subscription[int] - for i := 0; i < total; i++ { + for i := 0; i < max; i++ { ch, _ := src.Subscribe() list = append(list, ch) } var wg sync.WaitGroup - wg.Add(total) + wg.Add(max) waitCh := func(ch <-chan int) { for range ch { } diff --git a/go.mod b/go.mod index ca98937b..f75f58fd 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/Dreamacro/clash -go 1.21 +go 1.20 require ( github.com/3andne/restls-client-go v0.1.6 diff --git a/hub/updater/limitedreader.go b/hub/updater/limitedreader.go index 52d7e969..c31db601 100644 --- a/hub/updater/limitedreader.go +++ b/hub/updater/limitedreader.go @@ -3,6 +3,8 @@ package updater import ( "fmt" "io" + + "golang.org/x/exp/constraints" ) // LimitReachedError records the limit and the operation that caused it. @@ -33,7 +35,7 @@ func (lr *limitedReader) Read(p []byte) (n int, err error) { } } - p = p[:min(lr.n, int64(len(p)))] + p = p[:Min(lr.n, int64(len(p)))] n, err = lr.r.Read(p) lr.n -= int64(n) @@ -54,3 +56,12 @@ func LimitReader(r io.Reader, n int64) (limited io.Reader, err error) { n: n, }, nil } + +// Min returns the smaller of x or y. +func Min[T constraints.Integer | ~string](x, y T) (res T) { + if x < y { + return x + } + + return y +} diff --git a/transport/tuic/congestion/cubic.go b/transport/tuic/congestion/cubic.go index 7dbe2b06..dd491a32 100644 --- a/transport/tuic/congestion/cubic.go +++ b/transport/tuic/congestion/cubic.go @@ -186,7 +186,7 @@ func (c *Cubic) CongestionWindowAfterAck( targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow } // Limit the CWND increase to half the acked bytes. - targetCongestionWindow = min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) + targetCongestionWindow = Min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) // Increase the window by approximately Alpha * 1 MSS of bytes every // time we ack an estimated tcp window of bytes. For small diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go index a467b8c9..ca20b420 100644 --- a/transport/tuic/congestion/cubic_sender.go +++ b/transport/tuic/congestion/cubic_sender.go @@ -177,7 +177,7 @@ func (c *cubicSender) OnPacketAcked( priorInFlight congestion.ByteCount, eventTime time.Time, ) { - c.largestAckedPacketNumber = max(ackedPacketNumber, c.largestAckedPacketNumber) + c.largestAckedPacketNumber = Max(ackedPacketNumber, c.largestAckedPacketNumber) if c.InRecovery() { return } @@ -245,7 +245,7 @@ func (c *cubicSender) maybeIncreaseCwnd( c.numAckedPackets = 0 } } else { - c.congestionWindow = min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) + c.congestionWindow = Min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) } } diff --git a/transport/tuic/congestion/hybrid_slow_start.go b/transport/tuic/congestion/hybrid_slow_start.go index e0b42e53..7586774e 100644 --- a/transport/tuic/congestion/hybrid_slow_start.go +++ b/transport/tuic/congestion/hybrid_slow_start.go @@ -74,8 +74,8 @@ func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT ti // Divide minRTT by 8 to get a rtt increase threshold for exiting. minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp) // Ensure the rtt threshold is never less than 2ms or more than 16ms. - minRTTincreaseThresholdUs = min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) - minRTTincreaseThreshold := time.Duration(max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond + minRTTincreaseThresholdUs = Min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) + minRTTincreaseThreshold := time.Duration(Max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) { s.hystartFound = true diff --git a/transport/tuic/congestion/minmax.go b/transport/tuic/congestion/minmax.go index 50667766..0a8f4ad4 100644 --- a/transport/tuic/congestion/minmax.go +++ b/transport/tuic/congestion/minmax.go @@ -16,7 +16,7 @@ func MinNonZeroDuration(a, b time.Duration) time.Duration { if b == 0 { return a } - return min(a, b) + return Min(a, b) } // AbsDuration returns the absolute value of a time duration diff --git a/transport/tuic/congestion/minmax_go120.go b/transport/tuic/congestion/minmax_go120.go new file mode 100644 index 00000000..1266edbc --- /dev/null +++ b/transport/tuic/congestion/minmax_go120.go @@ -0,0 +1,19 @@ +//go:build !go1.21 + +package congestion + +import "golang.org/x/exp/constraints" + +func Max[T constraints.Ordered](a, b T) T { + if a < b { + return b + } + return a +} + +func Min[T constraints.Ordered](a, b T) T { + if a < b { + return a + } + return b +} diff --git a/transport/tuic/congestion/minmax_go121.go b/transport/tuic/congestion/minmax_go121.go new file mode 100644 index 00000000..65b06726 --- /dev/null +++ b/transport/tuic/congestion/minmax_go121.go @@ -0,0 +1,13 @@ +//go:build go1.21 + +package congestion + +import "cmp" + +func Max[T cmp.Ordered](a, b T) T { + return max(a, b) +} + +func Min[T cmp.Ordered](a, b T) T { + return min(a, b) +} diff --git a/transport/tuic/congestion/pacer.go b/transport/tuic/congestion/pacer.go index 9e85107d..f60ef5fe 100644 --- a/transport/tuic/congestion/pacer.go +++ b/transport/tuic/congestion/pacer.go @@ -52,11 +52,11 @@ func (p *pacer) Budget(now time.Time) congestion.ByteCount { return p.maxBurstSize() } budget := p.budgetAtLastSent + (congestion.ByteCount(p.getAdjustedBandwidth())*congestion.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9 - return min(p.maxBurstSize(), budget) + return Min(p.maxBurstSize(), budget) } func (p *pacer) maxBurstSize() congestion.ByteCount { - return max( + return Max( congestion.ByteCount(uint64((MinPacingDelay+TimerGranularity).Nanoseconds())*p.getAdjustedBandwidth())/1e9, maxBurstSizePackets*p.maxDatagramSize, ) @@ -68,7 +68,7 @@ func (p *pacer) TimeUntilSend() time.Time { if p.budgetAtLastSent >= p.maxDatagramSize { return time.Time{} } - return p.lastSentTime.Add(max( + return p.lastSentTime.Add(Max( MinPacingDelay, time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/float64(p.getAdjustedBandwidth())))*time.Nanosecond, )) From 42b85de83eb6b681c456d6c6b07eb1267ae4c695 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 08:28:05 +0800 Subject: [PATCH 427/530] chore: Restore go1.20 support --- dns/util.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/dns/util.go b/dns/util.go index c9d48a49..08daadbd 100644 --- a/dns/util.go +++ b/dns/util.go @@ -64,7 +64,9 @@ func putMsgToCacheWithExpire(c *cache.LruCache[string, *D.Msg], key string, msg return } - sec = max(sec, 120) // at least 2 minutes to cache + if sec > 120 { + sec = 120 // at least 2 minutes to cache + } } From 24fd5777676fc76e0965db5bbdfee3bf1b825d96 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 08:57:38 +0800 Subject: [PATCH 428/530] chore: Update dependencies --- go.mod | 18 +++++++++--------- go.sum | 33 +++++++++++++++++---------------- listener/sing_tun/server.go | 7 +++---- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/go.mod b/go.mod index f75f58fd..698fcc8a 100644 --- a/go.mod +++ b/go.mod @@ -20,19 +20,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.38.1-0.20230909013832-033f6a2115cf - 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-shadowsocks v0.2.5 + github.com/metacubex/sing-shadowsocks2 v0.1.4 + github.com/metacubex/sing-tun v0.1.12 + github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 - github.com/miekg/dns v1.1.55 + github.com/miekg/dns v1.1.56 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 github.com/puzpuzpuz/xsync/v2 v2.5.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a - github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c + github.com/sagernet/sing v0.2.11 + github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 @@ -66,7 +66,7 @@ require ( github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-ole/go-ole v1.3.0 // 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 @@ -104,4 +104,4 @@ require ( golang.org/x/tools v0.13.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24 diff --git a/go.sum b/go.sum index 59d83450..74cff3cf 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,9 @@ github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vz 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= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 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= @@ -96,20 +97,20 @@ 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.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= -github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579 h1:dE1dBB6CTzNdSMFTE5OCHvzHLewiqiA1nhD+7egtvAc= -github.com/metacubex/sing v0.0.0-20230817143035-28d23f152579/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= -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 v0.0.0-20230921005553-6eacdd2c7a24 h1:652uMd78eKMU7/sVkW8qqAdZkJaiDoUflfCs5LHvb0Q= +github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= +github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= +github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= +github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= +github.com/metacubex/sing-tun v0.1.12 h1:Jgmz0k3ddRiJ8zfS4X7j6B/iSy6GnOdDEU0nhqiZcK4= +github.com/metacubex/sing-tun v0.1.12/go.mod h1:X2P/H1HqXwqGcguGXWDVDhSS1GmDxVi13OmbtDedZ2M= +github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= +github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= 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/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= github.com/mroth/weightedrand/v2 v2.1.0/go.mod h1:f2faGsfOGOwc1p94wzHKKZyTpcJUW7OJ/9U4yfiNAOU= github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 h1:1102pQc2SEPp5+xrS26wEaeb26sZy6k9/ZXlZN+eXE4= @@ -143,8 +144,8 @@ 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.3-0.20230811111955-dc1639b5204c h1:35/FowAvt3Z62mck0TXzVc4jS5R5CWq62qcV2P1cp0I= -github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY= +github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= +github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= 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= @@ -239,9 +240,9 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.10.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 084c701b..66fe8cd5 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -172,7 +172,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte } }() - networkUpdateMonitor, err := tun.NewNetworkUpdateMonitor(handler) + networkUpdateMonitor, err := tun.NewNetworkUpdateMonitor(log.SingLogger) if err != nil { err = E.Cause(err, "create NetworkUpdateMonitor") return @@ -184,15 +184,14 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte return } - defaultInterfaceMonitor, err := tun.NewDefaultInterfaceMonitor(networkUpdateMonitor, tun.DefaultInterfaceMonitorOptions{OverrideAndroidVPN: true}) + defaultInterfaceMonitor, err := tun.NewDefaultInterfaceMonitor(networkUpdateMonitor, log.SingLogger, tun.DefaultInterfaceMonitorOptions{OverrideAndroidVPN: true}) if err != nil { err = E.Cause(err, "create DefaultInterfaceMonitor") return } l.defaultInterfaceMonitor = defaultInterfaceMonitor - defaultInterfaceMonitor.RegisterCallback(func(event int) error { + defaultInterfaceMonitor.RegisterCallback(func(event int) { l.FlushDefaultInterface() - return nil }) err = defaultInterfaceMonitor.Start() if err != nil { From 9b8e2d93435dcd13b9266c6213557c6230fc1c61 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 10:28:28 +0800 Subject: [PATCH 429/530] feat: support Hysteria2 --- adapter/outbound/hysteria.go | 36 ------ adapter/outbound/hysteria2.go | 218 ++++++++++++++++++++++++++++++++++ adapter/outbound/util.go | 38 ++++++ adapter/parser.go | 7 ++ constant/adapters.go | 3 + go.mod | 1 + go.sum | 2 + 7 files changed, 269 insertions(+), 36 deletions(-) create mode 100644 adapter/outbound/hysteria2.go diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 7da4975d..ff6e5deb 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -268,42 +268,6 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) { }, nil } -func stringToBps(s string) uint64 { - if s == "" { - return 0 - } - - // when have not unit, use Mbps - if v, err := strconv.Atoi(s); err == nil { - return stringToBps(fmt.Sprintf("%d Mbps", v)) - } - - m := rateStringRegexp.FindStringSubmatch(s) - if m == nil { - return 0 - } - var n uint64 - switch m[2] { - case "K": - n = 1 << 10 - case "M": - n = 1 << 20 - case "G": - n = 1 << 30 - case "T": - n = 1 << 40 - default: - n = 1 - } - v, _ := strconv.ParseUint(m[1], 10, 64) - n = v * n - if m[3] == "b" { - // Bits, need to convert to bytes - n = n >> 3 - } - return n -} - type hyPacketConn struct { core.UDPConn } diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go new file mode 100644 index 00000000..61c8b7c7 --- /dev/null +++ b/adapter/outbound/hysteria2.go @@ -0,0 +1,218 @@ +package outbound + +import ( + "context" + "crypto/sha256" + "crypto/tls" + "encoding/hex" + "encoding/pem" + "errors" + "fmt" + "net" + "os" + "runtime" + "strconv" + + CN "github.com/Dreamacro/clash/common/net" + "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" + tuicCommon "github.com/Dreamacro/clash/transport/tuic/common" + + "github.com/metacubex/sing-quic/hysteria2" + + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +func init() { + hysteria2.SetCongestionController = tuicCommon.SetCongestionController +} + +type Hysteria2 struct { + *Base + + option *Hysteria2Option + client *hysteria2.Client + dialer *hy2SingDialer +} + +type Hysteria2Option struct { + BasicOption + Name string `proxy:"name"` + Server string `proxy:"server"` + Port int `proxy:"port"` + Up string `proxy:"up,omitempty"` + Down string `proxy:"down,omitempty"` + Password string `proxy:"password,omitempty"` + Obfs string `proxy:"obfs,omitempty"` + ObfsPassword string `proxy:"obfs-password,omitempty"` + SNI string `proxy:"sni,omitempty"` + SkipCertVerify bool `proxy:"skip-cert-verify,omitempty"` + Fingerprint string `proxy:"fingerprint,omitempty"` + ALPN []string `proxy:"alpn,omitempty"` + CustomCA string `proxy:"ca,omitempty"` + CustomCAString string `proxy:"ca-str,omitempty"` +} + +type hy2SingDialer struct { + dialer dialer.Dialer + proxyName string +} + +var _ N.Dialer = (*hy2SingDialer)(nil) + +func (d *hy2SingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + var cDialer C.Dialer = d.dialer + if len(d.proxyName) > 0 { + pd, err := proxydialer.NewByName(d.proxyName, d.dialer) + if err != nil { + return nil, err + } + cDialer = pd + } + return cDialer.DialContext(ctx, network, destination.String()) +} + +func (d *hy2SingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + var cDialer C.Dialer = d.dialer + if len(d.proxyName) > 0 { + pd, err := proxydialer.NewByName(d.proxyName, d.dialer) + if err != nil { + return nil, err + } + cDialer = pd + } + return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) +} + +func (h *Hysteria2) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { + options := h.Base.DialOptions(opts...) + h.dialer.dialer = dialer.NewDialer(options...) + c, err := h.client.DialConn(ctx, M.ParseSocksaddr(metadata.RemoteAddress())) + if err != nil { + return nil, err + } + return NewConn(CN.NewRefConn(c, h), h), nil +} + +func (h *Hysteria2) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { + options := h.Base.DialOptions(opts...) + h.dialer.dialer = dialer.NewDialer(options...) + pc, err := h.client.ListenPacket(ctx) + if err != nil { + return nil, err + } + if pc == nil { + return nil, errors.New("packetConn is nil") + } + return newPacketConn(CN.NewRefPacketConn(CN.NewThreadSafePacketConn(pc), h), h), nil +} + +func closeHysteria2(h *Hysteria2) { + if h.client != nil { + _ = h.client.CloseWithError(errors.New("proxy removed")) + } +} + +func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { + addr := net.JoinHostPort(option.Server, strconv.Itoa(option.Port)) + var salamanderPassword string + if len(option.Obfs) > 0 { + if option.ObfsPassword == "" { + return nil, errors.New("missing obfs password") + } + switch option.Obfs { + case hysteria2.ObfsTypeSalamander: + salamanderPassword = option.ObfsPassword + default: + return nil, fmt.Errorf("unknown obfs type: %s", option.Obfs) + } + } + + serverName := option.Server + if option.SNI != "" { + serverName = option.SNI + } + + tlsConfig := &tls.Config{ + ServerName: serverName, + InsecureSkipVerify: option.SkipCertVerify, + MinVersion: tls.VersionTLS13, + } + + var bs []byte + var err error + if len(option.CustomCA) > 0 { + bs, err = os.ReadFile(option.CustomCA) + if err != nil { + return nil, fmt.Errorf("hysteria %s load ca error: %w", option.Name, err) + } + } else if option.CustomCAString != "" { + bs = []byte(option.CustomCAString) + } + + if len(bs) > 0 { + block, _ := pem.Decode(bs) + if block == nil { + return nil, fmt.Errorf("CA cert is not PEM") + } + + fpBytes := sha256.Sum256(block.Bytes) + if len(option.Fingerprint) == 0 { + option.Fingerprint = hex.EncodeToString(fpBytes[:]) + } + } + + if len(option.Fingerprint) != 0 { + var err error + tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) + if err != nil { + return nil, err + } + } else { + tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) + } + + if len(option.ALPN) > 0 { + tlsConfig.NextProtos = option.ALPN + } + + singDialer := &hy2SingDialer{dialer: dialer.NewDialer(), proxyName: option.DialerProxy} + + clientOptions := hysteria2.ClientOptions{ + Context: context.TODO(), + Dialer: singDialer, + ServerAddress: M.ParseSocksaddrHostPort(option.Server, uint16(option.Port)), + SendBPS: stringToBps(option.Up), + ReceiveBPS: stringToBps(option.Down), + SalamanderPassword: salamanderPassword, + Password: option.Password, + TLSConfig: tlsConfig, + UDPDisabled: false, + } + + client, err := hysteria2.NewClient(clientOptions) + if err != nil { + return nil, err + } + + outbound := &Hysteria2{ + Base: &Base{ + name: option.Name, + addr: addr, + tp: C.Hysteria2, + udp: true, + iface: option.Interface, + rmark: option.RoutingMark, + prefer: C.NewDNSPrefer(option.IPVersion), + }, + option: &option, + client: client, + dialer: singDialer, + } + runtime.SetFinalizer(outbound, closeHysteria2) + + return outbound, nil +} diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index 36607e4f..3faa3c43 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -4,8 +4,10 @@ import ( "bytes" "context" "crypto/tls" + "fmt" "net" "net/netip" + "strconv" "sync" "github.com/Dreamacro/clash/component/resolver" @@ -120,3 +122,39 @@ func safeConnClose(c net.Conn, err error) { _ = c.Close() } } + +func stringToBps(s string) uint64 { + if s == "" { + return 0 + } + + // when have not unit, use Mbps + if v, err := strconv.Atoi(s); err == nil { + return stringToBps(fmt.Sprintf("%d Mbps", v)) + } + + m := rateStringRegexp.FindStringSubmatch(s) + if m == nil { + return 0 + } + var n uint64 + switch m[2] { + case "K": + n = 1 << 10 + case "M": + n = 1 << 20 + case "G": + n = 1 << 30 + case "T": + n = 1 << 40 + default: + n = 1 + } + v, _ := strconv.ParseUint(m[1], 10, 64) + n = v * n + if m[3] == "b" { + // Bits, need to convert to bytes + n = n >> 3 + } + return n +} diff --git a/adapter/parser.go b/adapter/parser.go index 78e287f9..eeb0fd59 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -92,6 +92,13 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { break } proxy, err = outbound.NewHysteria(*hyOption) + case "hysteria2": + hyOption := &outbound.Hysteria2Option{} + err = decoder.Decode(mapping, hyOption) + if err != nil { + break + } + proxy, err = outbound.NewHysteria2(*hyOption) case "wireguard": wgOption := &outbound.WireGuardOption{} err = decoder.Decode(mapping, wgOption) diff --git a/constant/adapters.go b/constant/adapters.go index 5639dd47..33b9a44f 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -36,6 +36,7 @@ const ( Vless Trojan Hysteria + Hysteria2 WireGuard Tuic ) @@ -200,6 +201,8 @@ func (at AdapterType) String() string { return "Trojan" case Hysteria: return "Hysteria" + case Hysteria2: + return "Hysteria2" case WireGuard: return "WireGuard" case Tuic: diff --git a/go.mod b/go.mod index 698fcc8a..d16ccb01 100644 --- a/go.mod +++ b/go.mod @@ -20,6 +20,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf + github.com/metacubex/sing-quic v0.0.0-20230921015854-1ed89eed54d5 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.12 diff --git a/go.sum b/go.sum index 74cff3cf..45cb3cbb 100644 --- a/go.sum +++ b/go.sum @@ -99,6 +99,8 @@ github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+ github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24 h1:652uMd78eKMU7/sVkW8qqAdZkJaiDoUflfCs5LHvb0Q= github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/metacubex/sing-quic v0.0.0-20230921015854-1ed89eed54d5 h1:XhWilr6vJoXy4n/sP2datek28FTF3s3rWHhezdFFD8s= +github.com/metacubex/sing-quic v0.0.0-20230921015854-1ed89eed54d5/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= From 6c3b973748a844eb0de0c300b320bc7874840104 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 10:43:45 +0800 Subject: [PATCH 430/530] doc: add Hysteria2 doc --- adapter/outbound/hysteria.go | 3 --- adapter/outbound/util.go | 3 +++ docs/config.yaml | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index ff6e5deb..e30565fb 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -11,7 +11,6 @@ import ( "net" "net/netip" "os" - "regexp" "strconv" "time" @@ -43,8 +42,6 @@ const ( DefaultHopInterval = 10 ) -var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`) - type Hysteria struct { *Base diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index 3faa3c43..4b59183e 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -7,6 +7,7 @@ import ( "fmt" "net" "net/netip" + "regexp" "strconv" "sync" @@ -123,6 +124,8 @@ func safeConnClose(c net.Conn, err error) { } } +var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`) + func stringToBps(s string) uint64 { if s == "" { return 0 diff --git a/docs/config.yaml b/docs/config.yaml index 274eaedd..c2bdc263 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -642,6 +642,25 @@ proxies: # socks5 # fingerprint: xxxx # fast-open: true # 支持 TCP 快速打开,默认为 false + #hysteria2 + - name: "hysteria2" + type: hysteria2 + server: server.com + port: 443 + # up和down均不写或为0则使用BBR流控 + # up: "30 Mbps" # 若不写单位,默认为 Mbps + # down: "200 Mbps" # 若不写单位,默认为 Mbps + password: yourpassword + # obfs: salamander # 默认为空,如果填写则开启obfs,目前仅支持salamander + # obfs-password: yourpassword + # sni: server.com + # skip-cert-verify: false + # fingerprint: xxxx + # alpn: + # - h3 + # ca: "./my.ca" + # ca-str: "xyz" + # wireguard - name: "wg" type: wireguard From 233eeb0b38e1e549c5b1ef466b689cd25e5fe925 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 14:52:26 +0800 Subject: [PATCH 431/530] feat: inbound support Hysteria2 --- adapter/outbound/hysteria.go | 4 +- adapter/outbound/hysteria2.go | 4 +- adapter/outbound/util.go | 4 +- constant/metadata.go | 5 + listener/config/hysteria2.go | 24 ++++ listener/inbound/hysteria2.go | 93 +++++++++++++++ listener/parse.go | 7 ++ listener/sing_hysteria2/server.go | 180 ++++++++++++++++++++++++++++++ 8 files changed, 315 insertions(+), 6 deletions(-) create mode 100644 listener/config/hysteria2.go create mode 100644 listener/inbound/hysteria2.go create mode 100644 listener/sing_hysteria2/server.go diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index e30565fb..7cd4ea76 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -117,12 +117,12 @@ type HysteriaOption struct { func (c *HysteriaOption) Speed() (uint64, uint64, error) { var up, down uint64 - up = stringToBps(c.Up) + up = StringToBps(c.Up) if up == 0 { return 0, 0, fmt.Errorf("invaild upload speed: %s", c.Up) } - down = stringToBps(c.Down) + down = StringToBps(c.Down) if down == 0 { return 0, 0, fmt.Errorf("invaild download speed: %s", c.Down) } diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index 61c8b7c7..8963da66 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -185,8 +185,8 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { Context: context.TODO(), Dialer: singDialer, ServerAddress: M.ParseSocksaddrHostPort(option.Server, uint16(option.Port)), - SendBPS: stringToBps(option.Up), - ReceiveBPS: stringToBps(option.Down), + SendBPS: StringToBps(option.Up), + ReceiveBPS: StringToBps(option.Down), SalamanderPassword: salamanderPassword, Password: option.Password, TLSConfig: tlsConfig, diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index 4b59183e..b048cd8b 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -126,14 +126,14 @@ func safeConnClose(c net.Conn, err error) { var rateStringRegexp = regexp.MustCompile(`^(\d+)\s*([KMGT]?)([Bb])ps$`) -func stringToBps(s string) uint64 { +func StringToBps(s string) uint64 { if s == "" { return 0 } // when have not unit, use Mbps if v, err := strconv.Atoi(s); err == nil { - return stringToBps(fmt.Sprintf("%d Mbps", v)) + return StringToBps(fmt.Sprintf("%d Mbps", v)) } m := rateStringRegexp.FindStringSubmatch(s) diff --git a/constant/metadata.go b/constant/metadata.go index dbd31fd8..70478911 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -30,6 +30,7 @@ const ( TUNNEL TUN TUIC + HYSTERIA2 INNER ) @@ -78,6 +79,8 @@ func (t Type) String() string { return "Tun" case TUIC: return "Tuic" + case HYSTERIA2: + return "Hysteria2" case INNER: return "Inner" default: @@ -110,6 +113,8 @@ func ParseType(t string) (*Type, error) { res = TUN case "TUIC": res = TUIC + case "HYSTERIA2": + res = HYSTERIA2 case "INNER": res = INNER default: diff --git a/listener/config/hysteria2.go b/listener/config/hysteria2.go new file mode 100644 index 00000000..e8e9c09c --- /dev/null +++ b/listener/config/hysteria2.go @@ -0,0 +1,24 @@ +package config + +import "encoding/json" + +type Hysteria2Server struct { + Enable bool `yaml:"enable" json:"enable"` + Listen string `yaml:"listen" json:"listen"` + Users map[string]string `yaml:"users" json:"users,omitempty"` + Obfs string `yaml:"obfs" json:"obfs,omitempty"` + ObfsPassword string `yaml:"obfs-password" json:"obfs-password,omitempty"` + Certificate string `yaml:"certificate" json:"certificate"` + PrivateKey string `yaml:"private-key" json:"private-key"` + MaxIdleTime int `yaml:"max-idle-time" json:"max-idle-time,omitempty"` + ALPN []string `yaml:"alpn" json:"alpn,omitempty"` + Up string `yaml:"up" json:"up,omitempty"` + Down string `yaml:"down" json:"down,omitempty"` + IgnoreClientBandwidth bool `yaml:"ignore-client-bandwidth" json:"ignore-client-bandwidth,omitempty"` + Masquerade string `yaml:"masquerade" json:"masquerade,omitempty"` +} + +func (h Hysteria2Server) String() string { + b, _ := json.Marshal(h) + return string(b) +} diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go new file mode 100644 index 00000000..00feadb1 --- /dev/null +++ b/listener/inbound/hysteria2.go @@ -0,0 +1,93 @@ +package inbound + +import ( + C "github.com/Dreamacro/clash/constant" + LC "github.com/Dreamacro/clash/listener/config" + "github.com/Dreamacro/clash/listener/sing_hysteria2" + "github.com/Dreamacro/clash/log" +) + +type Hysteria2Option struct { + BaseOption + Users map[string]string `inbound:"users,omitempty"` + Obfs string `inbound:"obfs,omitempty"` + ObfsPassword string `inbound:"obfs-password,omitempty"` + Certificate string `inbound:"certificate"` + PrivateKey string `inbound:"private-key"` + MaxIdleTime int `inbound:"max-idle-time,omitempty"` + ALPN []string `inbound:"alpn,omitempty"` + Up string `inbound:"up,omitempty"` + Down string `inbound:"down,omitempty"` + IgnoreClientBandwidth bool `inbound:"ignore-client-bandwidth,omitempty"` + Masquerade string `inbound:"masquerade,omitempty"` +} + +func (o Hysteria2Option) Equal(config C.InboundConfig) bool { + return optionToString(o) == optionToString(config) +} + +type Hysteria2 struct { + *Base + config *Hysteria2Option + l *sing_hysteria2.Listener + ts LC.Hysteria2Server +} + +func NewHysteria2(options *Hysteria2Option) (*Hysteria2, error) { + base, err := NewBase(&options.BaseOption) + if err != nil { + return nil, err + } + return &Hysteria2{ + Base: base, + config: options, + ts: LC.Hysteria2Server{ + Enable: true, + Listen: base.RawAddress(), + Users: options.Users, + Obfs: options.Obfs, + ObfsPassword: options.ObfsPassword, + Certificate: options.Certificate, + PrivateKey: options.PrivateKey, + MaxIdleTime: options.MaxIdleTime, + ALPN: options.ALPN, + Up: options.Up, + Down: options.Down, + IgnoreClientBandwidth: options.IgnoreClientBandwidth, + Masquerade: options.Masquerade, + }, + }, nil +} + +// Config implements constant.InboundListener +func (t *Hysteria2) Config() C.InboundConfig { + return t.config +} + +// Address implements constant.InboundListener +func (t *Hysteria2) Address() string { + if t.l != nil { + for _, addr := range t.l.AddrList() { + return addr.String() + } + } + return "" +} + +// Listen implements constant.InboundListener +func (t *Hysteria2) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { + var err error + t.l, err = sing_hysteria2.New(t.ts, tcpIn, udpIn, t.Additions()...) + if err != nil { + return err + } + log.Infoln("Hysteria2[%s] proxy listening at: %s", t.Name(), t.Address()) + return nil +} + +// Close implements constant.InboundListener +func (t *Hysteria2) Close() error { + return t.l.Close() +} + +var _ C.InboundListener = (*Hysteria2)(nil) diff --git a/listener/parse.go b/listener/parse.go index c8e1ddf7..b0fac86a 100644 --- a/listener/parse.go +++ b/listener/parse.go @@ -86,6 +86,13 @@ func ParseListener(mapping map[string]any) (C.InboundListener, error) { return nil, err } listener, err = IN.NewVmess(vmessOption) + case "hysteria2": + hysteria2Option := &IN.Hysteria2Option{} + err = decoder.Decode(mapping, hysteria2Option) + if err != nil { + return nil, err + } + listener, err = IN.NewHysteria2(hysteria2Option) case "tuic": tuicOption := &IN.TuicOption{ MaxIdleTime: 15000, diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go new file mode 100644 index 00000000..1d6ab29a --- /dev/null +++ b/listener/sing_hysteria2/server.go @@ -0,0 +1,180 @@ +package sing_hysteria2 + +import ( + "context" + "crypto/tls" + "errors" + "fmt" + "net" + "net/http" + "net/http/httputil" + "net/url" + "strings" + + "github.com/Dreamacro/clash/adapter/inbound" + "github.com/Dreamacro/clash/adapter/outbound" + CN "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/common/sockopt" + C "github.com/Dreamacro/clash/constant" + LC "github.com/Dreamacro/clash/listener/config" + "github.com/Dreamacro/clash/listener/sing" + "github.com/Dreamacro/clash/log" + + "github.com/metacubex/sing-quic/hysteria2" + + E "github.com/sagernet/sing/common/exceptions" +) + +type Listener struct { + closed bool + config LC.Hysteria2Server + udpListeners []net.PacketConn + services []*hysteria2.Service[string] +} + +func New(config LC.Hysteria2Server, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (*Listener, error) { + var sl *Listener + var err error + if len(additions) == 0 { + additions = []inbound.Addition{ + inbound.WithInName("DEFAULT-HYSTERIA2"), + inbound.WithSpecialRules(""), + } + } + + h := &sing.ListenerHandler{ + TcpIn: tcpIn, + UdpIn: udpIn, + Type: C.HYSTERIA2, + Additions: additions, + } + + sl = &Listener{false, config, nil, nil} + + cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) + if err != nil { + return nil, err + } + tlsConfig := &tls.Config{ + MinVersion: tls.VersionTLS13, + Certificates: []tls.Certificate{cert}, + } + if len(config.ALPN) > 0 { + tlsConfig.NextProtos = config.ALPN + } else { + tlsConfig.NextProtos = []string{"h3"} + } + + var salamanderPassword string + if len(config.Obfs) > 0 { + if config.ObfsPassword == "" { + return nil, errors.New("missing obfs password") + } + switch config.Obfs { + case hysteria2.ObfsTypeSalamander: + salamanderPassword = config.ObfsPassword + default: + return nil, fmt.Errorf("unknown obfs type: %s", config.Obfs) + } + } + var masqueradeHandler http.Handler + if config.Masquerade != "" { + masqueradeURL, err := url.Parse(config.Masquerade) + if err != nil { + return nil, E.Cause(err, "parse masquerade URL") + } + switch masqueradeURL.Scheme { + case "file": + masqueradeHandler = http.FileServer(http.Dir(masqueradeURL.Path)) + case "http", "https": + masqueradeHandler = &httputil.ReverseProxy{ + Rewrite: func(r *httputil.ProxyRequest) { + r.SetURL(masqueradeURL) + r.Out.Host = r.In.Host + }, + ErrorHandler: func(w http.ResponseWriter, r *http.Request, err error) { + w.WriteHeader(http.StatusBadGateway) + }, + } + default: + return nil, E.New("unknown masquerade URL scheme: ", masqueradeURL.Scheme) + } + } + + service, err := hysteria2.NewService[string](hysteria2.ServiceOptions{ + Context: context.Background(), + Logger: log.SingLogger, + SendBPS: outbound.StringToBps(config.Up), + ReceiveBPS: outbound.StringToBps(config.Down), + SalamanderPassword: salamanderPassword, + TLSConfig: tlsConfig, + IgnoreClientBandwidth: config.IgnoreClientBandwidth, + Handler: h, + MasqueradeHandler: masqueradeHandler, + }) + if err != nil { + return nil, err + } + + userNameList := make([]string, 0, len(config.Users)) + userPasswordList := make([]string, 0, len(config.Users)) + for name, password := range config.Users { + userNameList = append(userNameList, name) + userPasswordList = append(userPasswordList, password) + } + service.UpdateUsers(userNameList, userPasswordList) + + for _, addr := range strings.Split(config.Listen, ",") { + addr := addr + _service := *service + service := &_service // make a copy + + ul, err := net.ListenPacket("udp", addr) + if err != nil { + return nil, err + } + + err = sockopt.UDPReuseaddr(ul.(*net.UDPConn)) + if err != nil { + log.Warnln("Failed to Reuse UDP Address: %s", err) + } + + sl.udpListeners = append(sl.udpListeners, ul) + sl.services = append(sl.services, service) + + go func() { + _ = service.Start(ul) + }() + } + + return sl, nil +} + +func (l *Listener) Close() error { + l.closed = true + var retErr error + for _, service := range l.services { + err := service.Close() + if err != nil { + retErr = err + } + } + for _, lis := range l.udpListeners { + err := lis.Close() + if err != nil { + retErr = err + } + } + return retErr +} + +func (l *Listener) Config() string { + return l.config.String() +} + +func (l *Listener) AddrList() (addrList []net.Addr) { + for _, lis := range l.udpListeners { + addrList = append(addrList, lis.LocalAddr()) + } + return +} From ee3213c28f69678e6eec5ba5cc739ce42241713d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 15:02:12 +0800 Subject: [PATCH 432/530] fix: tuicv5 panic in ReadFrom --- transport/tuic/v5/packet.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go index cd3ed12b..efbe0bb9 100644 --- a/transport/tuic/v5/packet.go +++ b/transport/tuic/v5/packet.go @@ -96,10 +96,10 @@ func (q *quicStreamPacketConn) SetWriteDeadline(t time.Time) error { } func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) { - if q.inputConn != nil { + if inputConn := q.inputConn; inputConn != nil { // copy inputConn avoid be nil in for loop for { var packet Packet - packet, err = ReadPacket(q.inputConn) + packet, err = ReadPacket(inputConn) if err != nil { return } @@ -116,10 +116,10 @@ func (q *quicStreamPacketConn) ReadFrom(p []byte) (n int, addr net.Addr, err err } func (q *quicStreamPacketConn) WaitReadFrom() (data []byte, put func(), addr net.Addr, err error) { - if q.inputConn != nil { + if inputConn := q.inputConn; inputConn != nil { // copy inputConn avoid be nil in for loop for { var packet Packet - packet, err = ReadPacket(q.inputConn) + packet, err = ReadPacket(inputConn) if err != nil { return } From da24810da2d810ad65492b2f4dd890062e92dee4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 16:41:31 +0800 Subject: [PATCH 433/530] chore: support set cwnd for hy2 too --- adapter/outbound/hysteria2.go | 2 ++ go.mod | 2 +- go.sum | 4 ++-- listener/config/hysteria2.go | 1 + listener/inbound/hysteria2.go | 2 ++ listener/sing_hysteria2/server.go | 1 + transport/tuic/common/congestion.go | 6 ++++-- 7 files changed, 13 insertions(+), 5 deletions(-) diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index 8963da66..46e052e6 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -54,6 +54,7 @@ type Hysteria2Option struct { ALPN []string `proxy:"alpn,omitempty"` CustomCA string `proxy:"ca,omitempty"` CustomCAString string `proxy:"ca-str,omitempty"` + CWND int `proxy:"cwnd,omitempty"` } type hy2SingDialer struct { @@ -191,6 +192,7 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { Password: option.Password, TLSConfig: tlsConfig, UDPDisabled: false, + CWND: option.CWND, } client, err := hysteria2.NewClient(clientOptions) diff --git a/go.mod b/go.mod index d16ccb01..487fe4c5 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf - github.com/metacubex/sing-quic v0.0.0-20230921015854-1ed89eed54d5 + github.com/metacubex/sing-quic v0.0.0-20230921083613-f4d3299bca83 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.12 diff --git a/go.sum b/go.sum index 45cb3cbb..5386ec0d 100644 --- a/go.sum +++ b/go.sum @@ -99,8 +99,8 @@ github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+ github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24 h1:652uMd78eKMU7/sVkW8qqAdZkJaiDoUflfCs5LHvb0Q= github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230921015854-1ed89eed54d5 h1:XhWilr6vJoXy4n/sP2datek28FTF3s3rWHhezdFFD8s= -github.com/metacubex/sing-quic v0.0.0-20230921015854-1ed89eed54d5/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4= +github.com/metacubex/sing-quic v0.0.0-20230921083613-f4d3299bca83 h1:xk2Uob4xSGCYRuo+UsDParhi1cam6G+11wrwGd6EvhM= +github.com/metacubex/sing-quic v0.0.0-20230921083613-f4d3299bca83/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= diff --git a/listener/config/hysteria2.go b/listener/config/hysteria2.go index e8e9c09c..5520babc 100644 --- a/listener/config/hysteria2.go +++ b/listener/config/hysteria2.go @@ -16,6 +16,7 @@ type Hysteria2Server struct { Down string `yaml:"down" json:"down,omitempty"` IgnoreClientBandwidth bool `yaml:"ignore-client-bandwidth" json:"ignore-client-bandwidth,omitempty"` Masquerade string `yaml:"masquerade" json:"masquerade,omitempty"` + CWND int `yaml:"cwnd" json:"cwnd,omitempty"` } func (h Hysteria2Server) String() string { diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go index 00feadb1..430d0e68 100644 --- a/listener/inbound/hysteria2.go +++ b/listener/inbound/hysteria2.go @@ -20,6 +20,7 @@ type Hysteria2Option struct { Down string `inbound:"down,omitempty"` IgnoreClientBandwidth bool `inbound:"ignore-client-bandwidth,omitempty"` Masquerade string `inbound:"masquerade,omitempty"` + CWND int `inbound:"cwnd,omitempty"` } func (o Hysteria2Option) Equal(config C.InboundConfig) bool { @@ -55,6 +56,7 @@ func NewHysteria2(options *Hysteria2Option) (*Hysteria2, error) { Down: options.Down, IgnoreClientBandwidth: options.IgnoreClientBandwidth, Masquerade: options.Masquerade, + CWND: options.CWND, }, }, nil } diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index 1d6ab29a..4e0a7c07 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -111,6 +111,7 @@ func New(config LC.Hysteria2Server, tcpIn chan<- C.ConnContext, udpIn chan<- C.P IgnoreClientBandwidth: config.IgnoreClientBandwidth, Handler: h, MasqueradeHandler: masqueradeHandler, + CWND: config.CWND, }) if err != nil { return nil, err diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index 8b8018b5..36ee01a1 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -13,7 +13,9 @@ const ( ) func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { - CWND := c.ByteCount(cwnd) + if cwnd == 0 { + cwnd = 32 + } switch cc { case "cubic": quicConn.SetCongestionControl( @@ -38,7 +40,7 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { congestion.NewBBRSender( congestion.DefaultClock{}, congestion.GetInitialPacketSize(quicConn.RemoteAddr()), - CWND*congestion.InitialMaxDatagramSize, + c.ByteCount(cwnd)*congestion.InitialMaxDatagramSize, congestion.DefaultBBRMaxCongestionWindow*congestion.InitialMaxDatagramSize, ), ) From f6bf9c08577060bb199c2f746c7d91dd3c0ca7b9 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 21 Sep 2023 17:25:01 +0800 Subject: [PATCH 434/530] feat: converter support hysteria2 --- common/convert/converter.go | 32 +++++++++++++++++++++++++++++ common/convert/converter_test.go | 35 ++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 common/convert/converter_test.go diff --git a/common/convert/converter.go b/common/convert/converter.go index ddc5c944..5a618f42 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -68,7 +68,39 @@ func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { hysteria["skip-cert-verify"], _ = strconv.ParseBool(query.Get("insecure")) proxies = append(proxies, hysteria) + case "hysteria2": + urlHysteria2, err := url.Parse(line) + if err != nil { + continue + } + query := urlHysteria2.Query() + name := uniqueName(names, urlHysteria2.Fragment) + hysteria2 := make(map[string]any, 20) + + hysteria2["name"] = name + hysteria2["type"] = scheme + hysteria2["server"] = urlHysteria2.Hostname() + if port := urlHysteria2.Port(); port != "" { + hysteria2["port"] = port + } else { + hysteria2["port"] = "443" + } + hysteria2["obfs"] = query.Get("obfs") + hysteria2["obfs-password"] = query.Get("obfs-password") + hysteria2["sni"] = query.Get("sni") + hysteria2["skip-cert-verify"], _ = strconv.ParseBool(query.Get("insecure")) + if alpn := query.Get("alpn"); alpn != "" { + hysteria2["alpn"] = strings.Split(alpn, ",") + } + if auth := urlHysteria2.User.String(); auth != "" { + hysteria2["password"] = auth + } + hysteria2["fingerprint"] = query.Get("pinSHA256") + hysteria2["down"] = query.Get("down") + hysteria2["up"] = query.Get("up") + + proxies = append(proxies, hysteria2) case "tuic": // A temporary unofficial TUIC share link standard // Modified from https://github.com/daeuniverse/dae/discussions/182 diff --git a/common/convert/converter_test.go b/common/convert/converter_test.go new file mode 100644 index 00000000..83b41c4c --- /dev/null +++ b/common/convert/converter_test.go @@ -0,0 +1,35 @@ +package convert + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// https://v2.hysteria.network/zh/docs/developers/URI-Scheme/ +func TestConvertsV2Ray_normal(t *testing.T) { + hy2test := "hysteria2://letmein@example.com:8443/?insecure=1&obfs=salamander&obfs-password=gawrgura&pinSHA256=deadbeef&sni=real.example.com&up=114&down=514&alpn=h3,h4#hy2test" + + expected := []map[string]interface{}{ + { + "name": "hy2test", + "type": "hysteria2", + "server": "example.com", + "port": "8443", + "sni": "real.example.com", + "obfs": "salamander", + "obfs-password": "gawrgura", + "alpn": []string{"h3", "h4"}, + "password": "letmein", + "up": "114", + "down": "514", + "skip-cert-verify": true, + "fingerprint": "deadbeef", + }, + } + + proxies, err := ConvertsV2Ray([]byte(hy2test)) + + assert.Nil(t, err) + assert.Equal(t, expected, proxies) +} From 7f49c91267bb08a78296780cd810ad3091f5eaf1 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 23:36:25 +0800 Subject: [PATCH 435/530] fix: hy2 udp not working --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 487fe4c5..0c7b2e31 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf - github.com/metacubex/sing-quic v0.0.0-20230921083613-f4d3299bca83 + github.com/metacubex/sing-quic v0.0.0-20230921153541-9d96dbf04c89 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.12 diff --git a/go.sum b/go.sum index 5386ec0d..d3b3b626 100644 --- a/go.sum +++ b/go.sum @@ -99,8 +99,8 @@ github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+ github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24 h1:652uMd78eKMU7/sVkW8qqAdZkJaiDoUflfCs5LHvb0Q= github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230921083613-f4d3299bca83 h1:xk2Uob4xSGCYRuo+UsDParhi1cam6G+11wrwGd6EvhM= -github.com/metacubex/sing-quic v0.0.0-20230921083613-f4d3299bca83/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4= +github.com/metacubex/sing-quic v0.0.0-20230921153541-9d96dbf04c89 h1:8tgapDMa9MNr4FNXBFgkC9Te0SjRVgByJ727GiQpiHE= +github.com/metacubex/sing-quic v0.0.0-20230921153541-9d96dbf04c89/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= From 4fe7a463c51626d195b9a7408a5e7bb8522e24ba Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 21 Sep 2023 23:49:45 +0800 Subject: [PATCH 436/530] chore: limit tuicv5's maxUdpRelayPacketSize up to 1200-PacketOverHead --- adapter/outbound/tuic.go | 6 +++++- transport/tuic/server.go | 4 ++++ transport/tuic/tuic.go | 1 + transport/tuic/v5/frag.go | 5 +++++ 4 files changed, 15 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 4d826912..b1032e8c 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -323,6 +323,10 @@ func NewTuic(option TuicOption) (*Tuic, error) { t.client = tuic.NewPoolClientV4(clientOption) } else { + maxUdpRelayPacketSize := option.MaxUdpRelayPacketSize + if maxUdpRelayPacketSize > tuic.MaxFragSizeV5 { + maxUdpRelayPacketSize = tuic.MaxFragSizeV5 + } clientOption := &tuic.ClientOptionV5{ TlsConfig: tlsConfig, QuicConfig: quicConfig, @@ -331,7 +335,7 @@ func NewTuic(option TuicOption) (*Tuic, error) { UdpRelayMode: udpRelayMode, CongestionController: option.CongestionController, ReduceRtt: option.ReduceRtt, - MaxUdpRelayPacketSize: option.MaxUdpRelayPacketSize, + MaxUdpRelayPacketSize: maxUdpRelayPacketSize, MaxOpenStreams: clientMaxOpenStreams, CWND: option.CWND, } diff --git a/transport/tuic/server.go b/transport/tuic/server.go index a6f91b88..cabc04e0 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -223,6 +223,10 @@ func NewServer(option *ServerOption, pc net.PacketConn) (*Server, error) { } } if len(option.Users) > 0 { + maxUdpRelayPacketSize := option.MaxUdpRelayPacketSize + if maxUdpRelayPacketSize > MaxFragSizeV5 { + maxUdpRelayPacketSize = MaxFragSizeV5 + } server.optionV5 = &v5.ServerOption{ HandleTcpFn: option.HandleTcpFn, HandleUdpFn: option.HandleUdpFn, diff --git a/transport/tuic/tuic.go b/transport/tuic/tuic.go index 8832ef91..387a152c 100644 --- a/transport/tuic/tuic.go +++ b/transport/tuic/tuic.go @@ -30,6 +30,7 @@ const DefaultConnectionReceiveWindow = common.DefaultConnectionReceiveWindow var GenTKN = v4.GenTKN var PacketOverHeadV4 = v4.PacketOverHead var PacketOverHeadV5 = v5.PacketOverHead +var MaxFragSizeV5 = v5.MaxFragSize type UdpRelayMode = common.UdpRelayMode diff --git a/transport/tuic/v5/frag.go b/transport/tuic/v5/frag.go index ae9dbf10..8df9f785 100644 --- a/transport/tuic/v5/frag.go +++ b/transport/tuic/v5/frag.go @@ -9,6 +9,11 @@ import ( "github.com/metacubex/quic-go" ) +// MaxFragSize is a safe udp relay packet size +// because tuicv5 support udp fragment so we unneeded to do a magic modify for quic-go to increase MaxDatagramFrameSize +// it may not work fine in some platform +var MaxFragSize = 1200 - PacketOverHead + func fragWriteNative(quicConn quic.Connection, packet Packet, buf *bytes.Buffer, fragSize int) (err error) { fullPayload := packet.DATA off := 0 From 90a5aa609a34e22a97e123842cee7a61670d187b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 22 Sep 2023 00:11:57 +0800 Subject: [PATCH 437/530] fix: uot read failed --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 0c7b2e31..6c67a38a 100644 --- a/go.mod +++ b/go.mod @@ -20,7 +20,7 @@ require ( github.com/mdlayher/netlink v1.7.2 github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf - github.com/metacubex/sing-quic v0.0.0-20230921153541-9d96dbf04c89 + github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.12 @@ -105,4 +105,4 @@ require ( golang.org/x/tools v0.13.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140 diff --git a/go.sum b/go.sum index d3b3b626..0105d57d 100644 --- a/go.sum +++ b/go.sum @@ -97,10 +97,10 @@ 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.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= -github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24 h1:652uMd78eKMU7/sVkW8qqAdZkJaiDoUflfCs5LHvb0Q= -github.com/metacubex/sing v0.0.0-20230921005553-6eacdd2c7a24/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230921153541-9d96dbf04c89 h1:8tgapDMa9MNr4FNXBFgkC9Te0SjRVgByJ727GiQpiHE= -github.com/metacubex/sing-quic v0.0.0-20230921153541-9d96dbf04c89/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4= +github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140 h1:qiTekhMDwY2vXARJx1D9EIEdtllbL7+ZBzHX9DQpWs4= +github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81 h1:6g+ohVa8FQLXz/ATmped/4kWuK0HKvhy1hwzQXyF0EI= +github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= From d48f9c2a6cc96a27df45ce74754604c5ac71320c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 22 Sep 2023 14:45:34 +0800 Subject: [PATCH 438/530] chore: rebuild ca parsing --- adapter/outbound/http.go | 22 +++----- adapter/outbound/hysteria.go | 39 ++------------ adapter/outbound/hysteria2.go | 39 ++------------ adapter/outbound/socks5.go | 13 ++--- adapter/outbound/trojan.go | 12 ++--- adapter/outbound/tuic.go | 39 ++------------ adapter/outbound/vless.go | 13 ++--- adapter/outbound/vmess.go | 12 ++--- component/{tls => ca}/config.go | 73 +++++++++++++++++---------- component/http/http.go | 5 +- dns/client.go | 4 +- dns/doh.go | 4 +- dns/doq.go | 4 +- hub/executor/executor.go | 6 +-- transport/sing-shadowtls/shadowtls.go | 10 ++-- transport/trojan/trojan.go | 14 +++-- transport/v2ray-plugin/websocket.go | 13 ++--- transport/vmess/tls.go | 14 +++-- 18 files changed, 120 insertions(+), 216 deletions(-) rename component/{tls => ca}/config.go (63%) diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index acc75d37..19074bb3 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -14,9 +14,9 @@ import ( "strconv" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/component/ca" "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" ) @@ -157,19 +157,13 @@ func NewHttp(option HttpOption) (*Http, error) { if option.SNI != "" { sni = option.SNI } - if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{ - InsecureSkipVerify: option.SkipCertVerify, - ServerName: sni, - }) - } else { - var err error - if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(&tls.Config{ - InsecureSkipVerify: option.SkipCertVerify, - ServerName: sni, - }, option.Fingerprint); err != nil { - return nil, err - } + var err error + tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(&tls.Config{ + InsecureSkipVerify: option.SkipCertVerify, + ServerName: sni, + }, option.Fingerprint) + if err != nil { + return nil, err } } diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 7cd4ea76..8a9d6258 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -2,15 +2,11 @@ package outbound import ( "context" - "crypto/sha256" "crypto/tls" "encoding/base64" - "encoding/hex" - "encoding/pem" "fmt" "net" "net/netip" - "os" "strconv" "time" @@ -18,9 +14,9 @@ import ( "github.com/metacubex/quic-go/congestion" M "github.com/sagernet/sing/common/metadata" + "github.com/Dreamacro/clash/component/ca" "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/log" hyCongestion "github.com/Dreamacro/clash/transport/hysteria/congestion" @@ -150,37 +146,10 @@ func NewHysteria(option HysteriaOption) (*Hysteria, error) { MinVersion: tls.VersionTLS13, } - var bs []byte var err error - if len(option.CustomCA) > 0 { - bs, err = os.ReadFile(option.CustomCA) - if err != nil { - return nil, fmt.Errorf("hysteria %s load ca error: %w", addr, err) - } - } else if option.CustomCAString != "" { - bs = []byte(option.CustomCAString) - } - - if len(bs) > 0 { - block, _ := pem.Decode(bs) - if block == nil { - return nil, fmt.Errorf("CA cert is not PEM") - } - - fpBytes := sha256.Sum256(block.Bytes) - if len(option.Fingerprint) == 0 { - option.Fingerprint = hex.EncodeToString(fpBytes[:]) - } - } - - if len(option.Fingerprint) != 0 { - var err error - tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) - if err != nil { - return nil, err - } - } else { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) + tlsConfig, err = ca.GetTLSConfig(tlsConfig, option.Fingerprint, option.CustomCA, option.CustomCAString) + if err != nil { + return nil, err } if len(option.ALPN) > 0 { diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index 46e052e6..e7ad91df 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -2,21 +2,17 @@ package outbound import ( "context" - "crypto/sha256" "crypto/tls" - "encoding/hex" - "encoding/pem" "errors" "fmt" "net" - "os" "runtime" "strconv" CN "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/component/ca" "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" tuicCommon "github.com/Dreamacro/clash/transport/tuic/common" @@ -143,37 +139,10 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { MinVersion: tls.VersionTLS13, } - var bs []byte var err error - if len(option.CustomCA) > 0 { - bs, err = os.ReadFile(option.CustomCA) - if err != nil { - return nil, fmt.Errorf("hysteria %s load ca error: %w", option.Name, err) - } - } else if option.CustomCAString != "" { - bs = []byte(option.CustomCAString) - } - - if len(bs) > 0 { - block, _ := pem.Decode(bs) - if block == nil { - return nil, fmt.Errorf("CA cert is not PEM") - } - - fpBytes := sha256.Sum256(block.Bytes) - if len(option.Fingerprint) == 0 { - option.Fingerprint = hex.EncodeToString(fpBytes[:]) - } - } - - if len(option.Fingerprint) != 0 { - var err error - tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) - if err != nil { - return nil, err - } - } else { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) + tlsConfig, err = ca.GetTLSConfig(tlsConfig, option.Fingerprint, option.CustomCA, option.CustomCAString) + if err != nil { + return nil, err } if len(option.ALPN) > 0 { diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 2e9bccd6..d857172e 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -10,9 +10,9 @@ import ( "strconv" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/component/ca" "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/socks5" ) @@ -180,13 +180,10 @@ func NewSocks5(option Socks5Option) (*Socks5, error) { ServerName: option.Server, } - if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - var err error - if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { - return nil, err - } + var err error + tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) + if err != nil { + return nil, err } } diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 6339b476..337f2a38 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -9,6 +9,7 @@ import ( "strconv" N "github.com/Dreamacro/clash/common/net" + "github.com/Dreamacro/clash/component/ca" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" tlsC "github.com/Dreamacro/clash/component/tls" @@ -280,13 +281,10 @@ func NewTrojan(option TrojanOption) (*Trojan, error) { ServerName: tOption.ServerName, } - if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - var err error - if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { - return nil, err - } + var err error + tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) + if err != nil { + return nil, err } t.transport = gun.NewHTTP2Client(dialFn, tlsConfig, tOption.ClientFingerprint, t.realityConfig) diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index b1032e8c..93e49dc7 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -2,22 +2,18 @@ package outbound import ( "context" - "crypto/sha256" "crypto/tls" - "encoding/hex" - "encoding/pem" "errors" "fmt" "math" "net" - "os" "strconv" "time" + "github.com/Dreamacro/clash/component/ca" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" - tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/tuic" @@ -162,37 +158,10 @@ func NewTuic(option TuicOption) (*Tuic, error) { tlsConfig.ServerName = option.SNI } - var bs []byte var err error - if len(option.CustomCA) > 0 { - bs, err = os.ReadFile(option.CustomCA) - if err != nil { - return nil, fmt.Errorf("tuic %s load ca error: %w", addr, err) - } - } else if option.CustomCAString != "" { - bs = []byte(option.CustomCAString) - } - - if len(bs) > 0 { - block, _ := pem.Decode(bs) - if block == nil { - return nil, fmt.Errorf("CA cert is not PEM") - } - - fpBytes := sha256.Sum256(block.Bytes) - if len(option.Fingerprint) == 0 { - option.Fingerprint = hex.EncodeToString(fpBytes[:]) - } - } - - if len(option.Fingerprint) != 0 { - var err error - tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) - if err != nil { - return nil, err - } - } else { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) + tlsConfig, err = ca.GetTLSConfig(tlsConfig, option.Fingerprint, option.CustomCA, option.CustomCAString) + if err != nil { + return nil, err } if option.ALPN != nil { // structure's Decode will ensure value not nil when input has value even it was set an empty array diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 81408e5f..037f3367 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -15,6 +15,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/ca" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" @@ -110,13 +111,9 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M NextProtos: []string{"http/1.1"}, } - if len(v.option.Fingerprint) == 0 { - wsOpts.TLSConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - wsOpts.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) - if err != nil { - return nil, err - } + wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) + if err != nil { + return nil, err } if v.option.ServerName != "" { @@ -592,7 +589,7 @@ func NewVless(option VlessOption) (*Vless, error) { } var tlsConfig *tls.Config if option.TLS { - tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{ + tlsConfig = ca.GetGlobalTLSConfig(&tls.Config{ InsecureSkipVerify: v.option.SkipCertVerify, ServerName: v.option.ServerName, }) diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 3e7694d1..db654580 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -13,6 +13,7 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/utils" + "github.com/Dreamacro/clash/component/ca" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/proxydialer" "github.com/Dreamacro/clash/component/resolver" @@ -127,12 +128,9 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M NextProtos: []string{"http/1.1"}, } - if len(v.option.Fingerprint) == 0 { - wsOpts.TLSConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - if wsOpts.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint); err != nil { - return nil, err - } + wsOpts.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, v.option.Fingerprint) + if err != nil { + return nil, err } if v.option.ServerName != "" { @@ -483,7 +481,7 @@ func NewVmess(option VmessOption) (*Vmess, error) { } var tlsConfig *tls.Config if option.TLS { - tlsConfig = tlsC.GetGlobalTLSConfig(&tls.Config{ + tlsConfig = ca.GetGlobalTLSConfig(&tls.Config{ InsecureSkipVerify: v.option.SkipCertVerify, ServerName: v.option.ServerName, }) diff --git a/component/tls/config.go b/component/ca/config.go similarity index 63% rename from component/tls/config.go rename to component/ca/config.go index d7382f7c..03fb007c 100644 --- a/component/tls/config.go +++ b/component/ca/config.go @@ -1,4 +1,4 @@ -package tls +package ca import ( "bytes" @@ -8,12 +8,13 @@ import ( "encoding/hex" "errors" "fmt" + "os" "strings" "sync" ) var trustCerts []*x509.Certificate -var certPool *x509.CertPool +var globalCertPool *x509.CertPool var mutex sync.RWMutex var errNotMatch = errors.New("certificate fingerprints do not match") @@ -33,12 +34,12 @@ func AddCertificate(certificate string) error { func initializeCertPool() { var err error - certPool, err = x509.SystemCertPool() + globalCertPool, err = x509.SystemCertPool() if err != nil { - certPool = x509.NewCertPool() + globalCertPool = x509.NewCertPool() } for _, cert := range trustCerts { - certPool.AddCert(cert) + globalCertPool.AddCert(cert) } } @@ -53,15 +54,15 @@ func getCertPool() *x509.CertPool { if len(trustCerts) == 0 { return nil } - if certPool == nil { + if globalCertPool == nil { mutex.Lock() defer mutex.Unlock() - if certPool != nil { - return certPool + if globalCertPool != nil { + return globalCertPool } initializeCertPool() } - return certPool + return globalCertPool } func verifyFingerprint(fingerprint *[32]byte) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error { @@ -94,29 +95,49 @@ func convertFingerprint(fingerprint string) (*[32]byte, error) { return (*[32]byte)(fpByte), nil } -func GetDefaultTLSConfig() *tls.Config { - return GetGlobalTLSConfig(nil) +// GetTLSConfig specified fingerprint, customCA and customCAString +func GetTLSConfig(tlsConfig *tls.Config, fingerprint string, customCA string, customCAString string) (*tls.Config, error) { + if tlsConfig == nil { + tlsConfig = &tls.Config{} + } + var certificate []byte + var err error + if len(customCA) > 0 { + certificate, err = os.ReadFile(customCA) + if err != nil { + return nil, fmt.Errorf("load ca error: %w", err) + } + } else if customCAString != "" { + certificate = []byte(customCAString) + } + if len(certificate) > 0 { + certPool := x509.NewCertPool() + if !certPool.AppendCertsFromPEM(certificate) { + return nil, fmt.Errorf("failed to parse certificate:\n\n %s", certificate) + } + tlsConfig.RootCAs = certPool + } else { + tlsConfig.RootCAs = getCertPool() + } + if len(fingerprint) > 0 { + var fingerprintBytes *[32]byte + fingerprintBytes, err = convertFingerprint(fingerprint) + if err != nil { + return nil, err + } + tlsConfig = GetGlobalTLSConfig(tlsConfig) + tlsConfig.VerifyPeerCertificate = verifyFingerprint(fingerprintBytes) + tlsConfig.InsecureSkipVerify = true + } + return tlsConfig, nil } // GetSpecifiedFingerprintTLSConfig specified fingerprint func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) (*tls.Config, error) { - if fingerprintBytes, err := convertFingerprint(fingerprint); err != nil { - return nil, err - } else { - tlsConfig = GetGlobalTLSConfig(tlsConfig) - tlsConfig.VerifyPeerCertificate = verifyFingerprint(fingerprintBytes) - tlsConfig.InsecureSkipVerify = true - return tlsConfig, nil - } + return GetTLSConfig(tlsConfig, fingerprint, "", "") } func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config { - certPool := getCertPool() - if tlsConfig == nil { - return &tls.Config{ - RootCAs: certPool, - } - } - tlsConfig.RootCAs = certPool + tlsConfig, _ = GetTLSConfig(tlsConfig, "", "", "") return tlsConfig } diff --git a/component/http/http.go b/component/http/http.go index c5172fcb..8e682e94 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -2,6 +2,7 @@ package http import ( "context" + "crypto/tls" "io" "net" "net/http" @@ -9,7 +10,7 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/component/ca" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/listener/inner" ) @@ -58,7 +59,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st return d.DialContext(ctx, network, address) } }, - TLSClientConfig: tls.GetDefaultTLSConfig(), + TLSClientConfig: ca.GetGlobalTLSConfig(&tls.Config{}), } client := http.Client{Transport: transport} diff --git a/dns/client.go b/dns/client.go index ba83412b..56f55668 100644 --- a/dns/client.go +++ b/dns/client.go @@ -9,9 +9,9 @@ import ( "strings" "github.com/Dreamacro/clash/common/atomic" + "github.com/Dreamacro/clash/component/ca" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" - tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" D "github.com/miekg/dns" @@ -99,7 +99,7 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) ch := make(chan result, 1) go func() { if strings.HasSuffix(c.Client.Net, "tls") { - conn = tls.Client(conn, tlsC.GetGlobalTLSConfig(c.Client.TLSConfig)) + conn = tls.Client(conn, ca.GetGlobalTLSConfig(c.Client.TLSConfig)) } msg, _, err := c.Client.ExchangeWithConn(m, &D.Conn{ diff --git a/dns/doh.go b/dns/doh.go index 49e502fd..0d84fc4f 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -15,7 +15,7 @@ import ( "sync" "time" - tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/component/ca" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" "github.com/metacubex/quic-go" @@ -382,7 +382,7 @@ func (doh *dnsOverHTTPS) createClient(ctx context.Context) (*http.Client, error) // HTTP3 is enabled in the upstream options). If this attempt is successful, // it returns an HTTP3 transport, otherwise it returns the H1/H2 transport. func (doh *dnsOverHTTPS) createTransport(ctx context.Context) (t http.RoundTripper, err error) { - tlsConfig := tlsC.GetGlobalTLSConfig( + tlsConfig := ca.GetGlobalTLSConfig( &tls.Config{ InsecureSkipVerify: false, MinVersion: tls.VersionTLS12, diff --git a/dns/doq.go b/dns/doq.go index f0016d79..afa8259a 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -12,7 +12,7 @@ import ( "sync" "time" - tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/component/ca" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" "github.com/metacubex/quic-go" @@ -330,7 +330,7 @@ func (doq *dnsOverQUIC) openConnection(ctx context.Context) (conn quic.Connectio return nil, err } - tlsConfig := tlsC.GetGlobalTLSConfig( + tlsConfig := ca.GetGlobalTLSConfig( &tls.Config{ ServerName: host, InsecureSkipVerify: false, diff --git a/hub/executor/executor.go b/hub/executor/executor.go index b840ba48..88cdfd6c 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -16,6 +16,7 @@ import ( "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/outboundgroup" "github.com/Dreamacro/clash/component/auth" + "github.com/Dreamacro/clash/component/ca" "github.com/Dreamacro/clash/component/dialer" G "github.com/Dreamacro/clash/component/geodata" "github.com/Dreamacro/clash/component/iface" @@ -23,7 +24,6 @@ import ( "github.com/Dreamacro/clash/component/profile/cachefile" "github.com/Dreamacro/clash/component/resolver" SNI "github.com/Dreamacro/clash/component/sniffer" - CTLS "github.com/Dreamacro/clash/component/tls" "github.com/Dreamacro/clash/component/trie" "github.com/Dreamacro/clash/config" C "github.com/Dreamacro/clash/constant" @@ -83,9 +83,9 @@ func ApplyConfig(cfg *config.Config, force bool) { tunnel.OnSuspend() - CTLS.ResetCertificate() + ca.ResetCertificate() for _, c := range cfg.TLS.CustomTrustCert { - if err := CTLS.AddCertificate(c); err != nil { + if err := ca.AddCertificate(c); err != nil { log.Warnln("%s\nadd error: %s", c, err.Error()) } } diff --git a/transport/sing-shadowtls/shadowtls.go b/transport/sing-shadowtls/shadowtls.go index 0e1e95c0..6d731ae6 100644 --- a/transport/sing-shadowtls/shadowtls.go +++ b/transport/sing-shadowtls/shadowtls.go @@ -5,6 +5,7 @@ import ( "crypto/tls" "net" + "github.com/Dreamacro/clash/component/ca" tlsC "github.com/Dreamacro/clash/component/tls" "github.com/Dreamacro/clash/log" @@ -39,12 +40,9 @@ func NewShadowTLS(ctx context.Context, conn net.Conn, option *ShadowTLSOption) ( } var err error - if len(option.Fingerprint) == 0 { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { - return nil, err - } + tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) + if err != nil { + return nil, err } tlsHandshake := shadowtls.DefaultTLSHandshakeFunc(option.Password, tlsConfig) diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 710905ad..6dfcfe11 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -14,6 +14,7 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/pool" + "github.com/Dreamacro/clash/component/ca" tlsC "github.com/Dreamacro/clash/component/tls" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" @@ -77,13 +78,10 @@ func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error 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 - } + var err error + tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint) + if err != nil { + return nil, err } if len(t.option.ClientFingerprint) != 0 { @@ -112,7 +110,7 @@ func (t *Trojan) StreamConn(ctx context.Context, conn net.Conn) (net.Conn, error ctx, cancel := context.WithTimeout(context.Background(), C.DefaultTLSTimeout) defer cancel() - err := tlsConn.HandshakeContext(ctx) + err = tlsConn.HandshakeContext(ctx) return tlsConn, err } diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 25483670..066a3e2a 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -6,7 +6,7 @@ import ( "net" "net/http" - tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/component/ca" "github.com/Dreamacro/clash/transport/vmess" ) @@ -43,13 +43,10 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn, InsecureSkipVerify: option.SkipCertVerify, NextProtos: []string{"http/1.1"}, } - if len(option.Fingerprint) == 0 { - config.TLSConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - var err error - if config.TLSConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint); err != nil { - return nil, err - } + var err error + config.TLSConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, option.Fingerprint) + if err != nil { + return nil, err } if host := config.Headers.Get("Host"); host != "" { diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 54813029..8bcb6513 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -6,6 +6,7 @@ import ( "errors" "net" + "github.com/Dreamacro/clash/component/ca" tlsC "github.com/Dreamacro/clash/component/tls" ) @@ -25,13 +26,10 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn NextProtos: cfg.NextProtos, } - if len(cfg.FingerPrint) == 0 { - tlsConfig = tlsC.GetGlobalTLSConfig(tlsConfig) - } else { - var err error - if tlsConfig, err = tlsC.GetSpecifiedFingerprintTLSConfig(tlsConfig, cfg.FingerPrint); err != nil { - return nil, err - } + var err error + tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, cfg.FingerPrint) + if err != nil { + return nil, err } if len(cfg.ClientFingerprint) != 0 { @@ -51,7 +49,7 @@ func StreamTLSConn(ctx context.Context, conn net.Conn, cfg *TLSConfig) (net.Conn tlsConn := tls.Client(conn, tlsConfig) - err := tlsConn.HandshakeContext(ctx) + err = tlsConn.HandshakeContext(ctx) return tlsConn, err } From bf619d858615ebce70e58f931a12bde29ec8ea5e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 22 Sep 2023 23:33:24 +0800 Subject: [PATCH 439/530] fix: socks5 udp not working on loopback --- adapter/outbound/direct.go | 3 ++- adapter/outbound/socks5.go | 2 +- dns/util.go | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index 720f96f9..75e999a6 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -3,6 +3,7 @@ package outbound import ( "context" "errors" + "net/netip" N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/component/dialer" @@ -40,7 +41,7 @@ func (d *Direct) ListenPacketContext(ctx context.Context, metadata *C.Metadata, } metadata.DstIP = ip } - pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", metadata.DstIP), "", d.Base.DialOptions(opts...)...) + pc, err := dialer.NewDialer(d.Base.DialOptions(opts...)...).ListenPacket(ctx, "udp", "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort)) if err != nil { return nil, err } diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index d857172e..864500c5 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -156,7 +156,7 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, bindUDPAddr.IP = serverAddr.IP } - pc, err := dialer.ListenPacket(ctx, dialer.ParseNetwork("udp", bindUDPAddr.AddrPort().Addr()), "", ss.Base.DialOptions(opts...)...) + pc, err := cDialer.ListenPacket(ctx, "udp", "", bindUDPAddr.AddrPort()) if err != nil { return } diff --git a/dns/util.go b/dns/util.go index 08daadbd..29de4e2a 100644 --- a/dns/util.go +++ b/dns/util.go @@ -290,7 +290,7 @@ func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName st DstPort: uint16(uintPort), } if proxyAdapter == nil { - return dialer.ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", opts...) + return dialer.NewDialer(opts...).ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort)) } if !proxyAdapter.SupportUDP() { From 0207a7ac96caac7f43798c99a5ef13ef86d9a8b8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 23 Sep 2023 14:01:18 +0800 Subject: [PATCH 440/530] chore: resolver read system hosts file --- component/resolver/host.go | 42 +++++++++++++++++++----------- component/resolver/host_windows.go | 19 ++++++++++++++ 2 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 component/resolver/host_windows.go diff --git a/component/resolver/host.go b/component/resolver/host.go index 3b7e9a37..d6eb5873 100644 --- a/component/resolver/host.go +++ b/component/resolver/host.go @@ -4,6 +4,7 @@ import ( "errors" "net/netip" "strings" + _ "unsafe" "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/trie" @@ -20,28 +21,39 @@ func NewHosts(hosts *trie.DomainTrie[HostValue]) Hosts { } } +// lookupStaticHost looks up the addresses and the canonical name for the given host from /etc/hosts. +// +//go:linkname lookupStaticHost net.lookupStaticHost +func lookupStaticHost(host string) ([]string, string) + // Return the search result and whether to match the parameter `isDomain` func (h *Hosts) Search(domain string, isDomain bool) (*HostValue, bool) { - value := h.DomainTrie.Search(domain) - if value == nil { - return nil, false - } - hostValue := value.Data() - for { - if isDomain && hostValue.IsDomain { - return &hostValue, true - } else { - if node := h.DomainTrie.Search(hostValue.Domain); node != nil { - hostValue = node.Data() + if value := h.DomainTrie.Search(domain); value != nil { + hostValue := value.Data() + for { + if isDomain && hostValue.IsDomain { + return &hostValue, true } else { - break + if node := h.DomainTrie.Search(hostValue.Domain); node != nil { + hostValue = node.Data() + } else { + break + } } } + if isDomain == hostValue.IsDomain { + return &hostValue, true + } + + return &hostValue, false } - if isDomain == hostValue.IsDomain { - return &hostValue, true + if !isDomain { + addr, _ := lookupStaticHost(domain) + if hostValue, err := NewHostValue(addr); err == nil { + return &hostValue, true + } } - return &hostValue, false + return nil, false } type HostValue struct { diff --git a/component/resolver/host_windows.go b/component/resolver/host_windows.go new file mode 100644 index 00000000..669f9547 --- /dev/null +++ b/component/resolver/host_windows.go @@ -0,0 +1,19 @@ +//go:build !go1.22 + +// a simple standard lib fix from: https://github.com/golang/go/commit/33d4a5105cf2b2d549922e909e9239a48b8cefcc + +package resolver + +import ( + "golang.org/x/sys/windows" + _ "unsafe" +) + +//go:linkname testHookHostsPath net.testHookHostsPath +var testHookHostsPath string + +func init() { + if dir, err := windows.GetSystemDirectory(); err == nil { + testHookHostsPath = dir + "/Drivers/etc/hosts" + } +} From 34f62a091926e3dd3a2cdcff8eae4c8a0021a011 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sat, 23 Sep 2023 17:54:20 +0800 Subject: [PATCH 441/530] feat: add provider proxies api --- hub/route/provider.go | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/hub/route/provider.go b/hub/route/provider.go index 1ba0d32c..c050a9f1 100644 --- a/hub/route/provider.go +++ b/hub/route/provider.go @@ -4,22 +4,35 @@ import ( "context" "net/http" + C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/constant/provider" "github.com/Dreamacro/clash/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" + "github.com/samber/lo" ) func proxyProviderRouter() http.Handler { r := chi.NewRouter() r.Get("/", getProviders) - r.Route("/{name}", func(r chi.Router) { + r.Route("/{providerName}", func(r chi.Router) { r.Use(parseProviderName, findProviderByName) r.Get("/", getProvider) r.Put("/", updateProvider) r.Get("/healthcheck", healthCheckProvider) + r.Mount("/", proxyProviderProxyRouter()) + }) + return r +} + +func proxyProviderProxyRouter() http.Handler { + r := chi.NewRouter() + r.Route("/{name}", func(r chi.Router) { + r.Use(parseProxyName, findProviderProxyByName) + r.Get("/", getProxy) + r.Get("/healthcheck", getProxyDelay) }) return r } @@ -54,7 +67,7 @@ func healthCheckProvider(w http.ResponseWriter, r *http.Request) { func parseProviderName(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - name := getEscapeParam(r, "name") + name := getEscapeParam(r, "providerName") ctx := context.WithValue(r.Context(), CtxKeyProviderName, name) next.ServeHTTP(w, r.WithContext(ctx)) }) @@ -76,6 +89,27 @@ func findProviderByName(next http.Handler) http.Handler { }) } +func findProviderProxyByName(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + var ( + name = r.Context().Value(CtxKeyProxyName).(string) + pd = r.Context().Value(CtxKeyProvider).(provider.ProxyProvider) + ) + proxy, exist := lo.Find(pd.Proxies(), func(proxy C.Proxy) bool { + return proxy.Name() == name + }) + + if !exist { + render.Status(r, http.StatusNotFound) + render.JSON(w, r, ErrNotFound) + return + } + + ctx := context.WithValue(r.Context(), CtxKeyProxy, proxy) + next.ServeHTTP(w, r.WithContext(ctx)) + }) +} + func ruleProviderRouter() http.Handler { r := chi.NewRouter() r.Get("/", getRuleProviders) From 8f515ecc051cae7bb31b7df9409114db639e3f17 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 23 Sep 2023 17:59:59 +0800 Subject: [PATCH 442/530] chore: updateUI API return 501 when config incomplete --- config/config.go | 13 +++---------- config/update_ui.go | 29 ++++++++++++++++++++++++++--- hub/executor/executor.go | 4 +++- hub/route/upgrade.go | 17 ++++++++++++----- 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/config/config.go b/config/config.go index d0e69e49..fd1a4116 100644 --- a/config/config.go +++ b/config/config.go @@ -9,7 +9,6 @@ import ( "net/url" "os" "path" - "path/filepath" "regexp" "strings" "time" @@ -582,9 +581,6 @@ func parseGeneral(cfg *RawConfig) (*General, error) { N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second } - if cfg.ExternalUIURL != "" { - ExternalUIURL = cfg.ExternalUIURL - } ExternalUIPath = cfg.ExternalUI // checkout externalUI exist if ExternalUIPath != "" { @@ -602,15 +598,12 @@ func parseGeneral(cfg *RawConfig) (*General, error) { // checkout UIpath/name exist if cfg.ExternalUIName != "" { ExternalUIName = cfg.ExternalUIName - ExternalUIFolder = filepath.Clean(path.Join(ExternalUIPath, cfg.ExternalUIName)) - if _, err := os.Stat(ExternalUIPath); os.IsNotExist(err) { - if err := os.MkdirAll(ExternalUIPath, os.ModePerm); err != nil { - return nil, err - } - } } else { ExternalUIFolder = ExternalUIPath } + if cfg.ExternalUIURL != "" { + ExternalUIURL = cfg.ExternalUIURL + } cfg.Tun.RedirectToTun = cfg.EBpf.RedirectToTun return &General{ diff --git a/config/update_ui.go b/config/update_ui.go index 5bc2596e..3526836e 100644 --- a/config/update_ui.go +++ b/config/update_ui.go @@ -2,6 +2,7 @@ package config import ( "archive/zip" + "errors" "fmt" "io" "os" @@ -19,15 +20,18 @@ var ( ExternalUIFolder string ExternalUIName string ) - +var ( + ErrImcompleteConf = errors.New("ExternalUI configure incomplete") +) var xdMutex sync.Mutex func UpdateUI() error { xdMutex.Lock() defer xdMutex.Unlock() - if ExternalUIPath == "" || ExternalUIFolder == "" { - return fmt.Errorf("ExternalUI configure incomplete") + err := prepare() + if err != nil { + return err } data, err := downloadForBytes(ExternalUIURL) @@ -60,6 +64,25 @@ func UpdateUI() error { return nil } +func prepare() error { + if ExternalUIPath == "" || ExternalUIURL == "" { + return ErrImcompleteConf + } + + if ExternalUIName != "" { + ExternalUIFolder = filepath.Clean(path.Join(ExternalUIPath, ExternalUIName)) + if _, err := os.Stat(ExternalUIPath); os.IsNotExist(err) { + if err := os.MkdirAll(ExternalUIPath, os.ModePerm); err != nil { + return err + } + } + } else { + ExternalUIFolder = ExternalUIPath + } + + return nil +} + func unzip(src, dest string) (string, error) { r, err := zip.OpenReader(src) if err != nil { diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 88cdfd6c..d1636754 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -2,7 +2,6 @@ package executor import ( "fmt" - "github.com/Dreamacro/clash/ntp" "net" "net/netip" "os" @@ -12,6 +11,8 @@ import ( "sync" "time" + "github.com/Dreamacro/clash/ntp" + "github.com/Dreamacro/clash/adapter" "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/adapter/outboundgroup" @@ -142,6 +143,7 @@ func GetGeneral() *config.General { AllowLan: listener.AllowLan(), BindAddress: listener.BindAddress(), }, + Controller: config.Controller{}, Mode: tunnel.Mode(), LogLevel: log.Level(), IPv6: !resolver.DisableIPv6, diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index be226616..28acb23a 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -1,6 +1,7 @@ package route import ( + "errors" "fmt" "net/http" "os" @@ -15,12 +16,12 @@ import ( func upgradeRouter() http.Handler { r := chi.NewRouter() - r.Post("/", upgrade) + r.Post("/", upgradeCore) r.Post("/ui", updateUI) return r } -func upgrade(w http.ResponseWriter, r *http.Request) { +func upgradeCore(w http.ResponseWriter, r *http.Request) { // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/home/controlupdate.go#L108 log.Infoln("start update") execPath, err := os.Executable() @@ -49,9 +50,15 @@ func upgrade(w http.ResponseWriter, r *http.Request) { func updateUI(w http.ResponseWriter, r *http.Request) { err := config.UpdateUI() if err != nil { - log.Warnln("%s", err) - render.Status(r, http.StatusInternalServerError) - render.JSON(w, r, newError(fmt.Sprintf("%s", err))) + if errors.Is(err, config.ErrImcompleteConf) { + log.Warnln("%s", err) + render.Status(r, http.StatusNotImplemented) + render.JSON(w, r, newError(fmt.Sprintf("%s", err))) + } else { + log.Warnln("%s", err) + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, newError(fmt.Sprintf("%s", err))) + } return } From 7c59916c2220ce49be36b480797b6ffacd92e679 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Sun, 24 Sep 2023 00:19:10 +0800 Subject: [PATCH 443/530] chore: update provider proxies api --- adapter/adapter.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/adapter/adapter.go b/adapter/adapter.go index 13f7f06f..e9ce59bb 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -217,6 +217,10 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In if alive { record.Delay = t } + p.history.Put(record) + if p.history.Len() > defaultHistoriesNum { + p.history.Pop() + } state, ok := p.extra.Load(url) if !ok { From 0d300a35404c9403c56ed47f4c8c7c7b41c28087 Mon Sep 17 00:00:00 2001 From: PuerNya Date: Sun, 24 Sep 2023 15:39:14 +0800 Subject: [PATCH 444/530] chore: handle provider proxies in proxies api --- hub/route/proxies.go | 4 ++-- tunnel/tunnel.go | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/hub/route/proxies.go b/hub/route/proxies.go index 36c9d1b1..c1e30b21 100644 --- a/hub/route/proxies.go +++ b/hub/route/proxies.go @@ -46,7 +46,7 @@ func parseProxyName(next http.Handler) http.Handler { func findProxyByName(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { name := r.Context().Value(CtxKeyProxyName).(string) - proxies := tunnel.Proxies() + proxies := tunnel.ProxiesWithProviders() proxy, exist := proxies[name] if !exist { render.Status(r, http.StatusNotFound) @@ -60,7 +60,7 @@ func findProxyByName(next http.Handler) http.Handler { } func getProxies(w http.ResponseWriter, r *http.Request) { - proxies := tunnel.Proxies() + proxies := tunnel.ProxiesWithProviders() render.JSON(w, r, render.M{ "proxies": proxies, }) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index b7557e10..fd601d30 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -127,6 +127,20 @@ func Proxies() map[string]C.Proxy { return proxies } +func ProxiesWithProviders() map[string]C.Proxy { + allProxies := make(map[string]C.Proxy) + for name, proxy := range proxies { + allProxies[name] = proxy + } + for _, p := range providers { + for _, proxy := range p.Proxies() { + name := proxy.Name() + allProxies[name] = proxy + } + } + return allProxies +} + // Providers return all compatible providers func Providers() map[string]provider.ProxyProvider { return providers From e6366f7442d97785da3d6a31b12cf2e9a085386b Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 24 Sep 2023 19:00:51 +0800 Subject: [PATCH 445/530] chore: fix typo --- config/config.go | 1 + config/update_ui.go | 4 ++-- hub/route/upgrade.go | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index fd1a4116..a1ddde81 100644 --- a/config/config.go +++ b/config/config.go @@ -461,6 +461,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { 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", }, + ExternalUIURL: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip", } if err := yaml.Unmarshal(buf, rawCfg); err != nil { diff --git a/config/update_ui.go b/config/update_ui.go index 3526836e..27e0f382 100644 --- a/config/update_ui.go +++ b/config/update_ui.go @@ -21,7 +21,7 @@ var ( ExternalUIName string ) var ( - ErrImcompleteConf = errors.New("ExternalUI configure incomplete") + ErrIncompleteConf = errors.New("ExternalUI configure incomplete") ) var xdMutex sync.Mutex @@ -66,7 +66,7 @@ func UpdateUI() error { func prepare() error { if ExternalUIPath == "" || ExternalUIURL == "" { - return ErrImcompleteConf + return ErrIncompleteConf } if ExternalUIName != "" { diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index 28acb23a..7b486ee3 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -50,7 +50,7 @@ func upgradeCore(w http.ResponseWriter, r *http.Request) { func updateUI(w http.ResponseWriter, r *http.Request) { err := config.UpdateUI() if err != nil { - if errors.Is(err, config.ErrImcompleteConf) { + if errors.Is(err, config.ErrIncompleteConf) { log.Warnln("%s", err) render.Status(r, http.StatusNotImplemented) render.JSON(w, r, newError(fmt.Sprintf("%s", err))) From 67d7e53f7ae2d265a72bd03509723e63ccf19ef1 Mon Sep 17 00:00:00 2001 From: Kiva Date: Sun, 24 Sep 2023 19:27:55 +0800 Subject: [PATCH 446/530] feat: recovering `preHandleMetadata` failure from sniffing (#769) --- component/sniffer/dispatcher.go | 22 +++++++++++++--------- tunnel/tunnel.go | 17 +++++++++++++++-- 2 files changed, 28 insertions(+), 11 deletions(-) diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index f813eec2..a1c8a93f 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -35,7 +35,8 @@ type SnifferDispatcher struct { parsePureIp bool } -func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) { +// TCPSniff returns true if the connection is sniffed to have a domain +func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) bool { if (metadata.Host == "" && sd.parsePureIp) || sd.forceDomain.Has(metadata.Host) || (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) { inWhitelist := false overrideDest := false @@ -50,7 +51,7 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata } if !inWhitelist { - return + return false } sd.rwMux.RLock() @@ -58,18 +59,18 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata 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() - return + return false } sd.rwMux.RUnlock() if host, err := sd.sniffDomain(conn, metadata); err != nil { sd.cacheSniffFailed(metadata) log.Debugln("[Sniffer] All sniffing sniff failed with from [%s:%d] to [%s:%d]", metadata.SrcIP, metadata.SrcPort, metadata.String(), metadata.DstPort) - return + return false } else { if sd.skipSNI.Has(host) { log.Debugln("[Sniffer] Skip sni[%s]", host) - return + return false } sd.rwMux.RLock() @@ -77,20 +78,23 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata sd.rwMux.RUnlock() sd.replaceDomain(metadata, host, overrideDest) + return true } } + return false } func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string, overrideDest bool) { + // show log early, since the following code may mutate `metadata.Host` + log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s] success, replace domain [%s]-->[%s]", + metadata.SourceDetail(), + metadata.RemoteAddress(), + metadata.Host, host) metadata.SniffHost = host if overrideDest { metadata.Host = host } metadata.DNSMode = C.DNSNormal - log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s] success, replace domain [%s]-->[%s]", - metadata.SourceDetail(), - metadata.RemoteAddress(), - metadata.Host, host) } func (sd *SnifferDispatcher) Enable() bool { diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index fd601d30..ff64915a 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -419,15 +419,28 @@ func handleTCPConn(connCtx C.ConnContext) { return } + preHandleFailed := false if err := preHandleMetadata(metadata); err != nil { log.Debugln("[Metadata PreHandle] error: %s", err) - return + preHandleFailed = true } conn := connCtx.Conn() conn.ResetPeeked() // reset before sniffer if sniffer.Dispatcher.Enable() && sniffingEnable { - sniffer.Dispatcher.TCPSniff(conn, metadata) + // Try to sniff a domain when `preHandleMetadata` failed, this is usually + // caused by a "Fake DNS record missing" error when enhanced-mode is fake-ip. + if sniffer.Dispatcher.TCPSniff(conn, metadata) { + // we now have a domain name + preHandleFailed = false + } + } + + // If both trials have failed, we can do nothing but give up + if preHandleFailed { + log.Debugln("[Metadata PreHandle] failed to sniff a domain for connection %s --> %s, give up", + metadata.SourceDetail(), metadata.RemoteAddress()) + return } peekMutex := sync.Mutex{} From c0ba7987089813bcf870e59a5b76fd5fe94e149f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 25 Sep 2023 09:10:43 +0800 Subject: [PATCH 447/530] chore: share N.dialer code --- adapter/outbound/hysteria2.go | 40 ++--------------- adapter/outbound/singmux.go | 28 ++---------- adapter/outbound/wireguard.go | 40 ++--------------- component/proxydialer/sing.go | 82 +++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 96 deletions(-) create mode 100644 component/proxydialer/sing.go diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index e7ad91df..57c15a12 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -19,7 +19,6 @@ import ( "github.com/metacubex/sing-quic/hysteria2" M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" ) func init() { @@ -31,7 +30,7 @@ type Hysteria2 struct { option *Hysteria2Option client *hysteria2.Client - dialer *hy2SingDialer + dialer proxydialer.SingDialer } type Hysteria2Option struct { @@ -53,40 +52,9 @@ type Hysteria2Option struct { CWND int `proxy:"cwnd,omitempty"` } -type hy2SingDialer struct { - dialer dialer.Dialer - proxyName string -} - -var _ N.Dialer = (*hy2SingDialer)(nil) - -func (d *hy2SingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - var cDialer C.Dialer = d.dialer - if len(d.proxyName) > 0 { - pd, err := proxydialer.NewByName(d.proxyName, d.dialer) - if err != nil { - return nil, err - } - cDialer = pd - } - return cDialer.DialContext(ctx, network, destination.String()) -} - -func (d *hy2SingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - var cDialer C.Dialer = d.dialer - if len(d.proxyName) > 0 { - pd, err := proxydialer.NewByName(d.proxyName, d.dialer) - if err != nil { - return nil, err - } - cDialer = pd - } - return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) -} - func (h *Hysteria2) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { options := h.Base.DialOptions(opts...) - h.dialer.dialer = dialer.NewDialer(options...) + h.dialer.SetDialer(dialer.NewDialer(options...)) c, err := h.client.DialConn(ctx, M.ParseSocksaddr(metadata.RemoteAddress())) if err != nil { return nil, err @@ -96,7 +64,7 @@ func (h *Hysteria2) DialContext(ctx context.Context, metadata *C.Metadata, opts func (h *Hysteria2) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { options := h.Base.DialOptions(opts...) - h.dialer.dialer = dialer.NewDialer(options...) + h.dialer.SetDialer(dialer.NewDialer(options...)) pc, err := h.client.ListenPacket(ctx) if err != nil { return nil, err @@ -149,7 +117,7 @@ func NewHysteria2(option Hysteria2Option) (*Hysteria2, error) { tlsConfig.NextProtos = option.ALPN } - singDialer := &hy2SingDialer{dialer: dialer.NewDialer(), proxyName: option.DialerProxy} + singDialer := proxydialer.NewByNameSingDialer(option.DialerProxy, dialer.NewDialer()) clientOptions := hysteria2.ClientOptions{ Context: context.TODO(), diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index 9a977318..c9f50ce9 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -3,7 +3,6 @@ package outbound import ( "context" "errors" - "net" "runtime" CN "github.com/Dreamacro/clash/common/net" @@ -15,14 +14,13 @@ import ( mux "github.com/sagernet/sing-mux" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" ) type SingMux struct { C.ProxyAdapter base ProxyBase client *mux.Client - dialer *muxSingDialer + dialer proxydialer.SingDialer onlyTcp bool } @@ -41,27 +39,9 @@ type ProxyBase interface { DialOptions(opts ...dialer.Option) []dialer.Option } -type muxSingDialer struct { - dialer dialer.Dialer - proxy C.ProxyAdapter - statistic bool -} - -var _ N.Dialer = (*muxSingDialer)(nil) - -func (d *muxSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - var cDialer C.Dialer = proxydialer.New(d.proxy, d.dialer, d.statistic) - return cDialer.DialContext(ctx, network, destination.String()) -} - -func (d *muxSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - var cDialer C.Dialer = proxydialer.New(d.proxy, d.dialer, d.statistic) - return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) -} - func (s *SingMux) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { options := s.base.DialOptions(opts...) - s.dialer.dialer = dialer.NewDialer(options...) + s.dialer.SetDialer(dialer.NewDialer(options...)) c, err := s.client.DialContext(ctx, "tcp", M.ParseSocksaddr(metadata.RemoteAddress())) if err != nil { return nil, err @@ -74,7 +54,7 @@ func (s *SingMux) ListenPacketContext(ctx context.Context, metadata *C.Metadata, return s.ProxyAdapter.ListenPacketContext(ctx, metadata, opts...) } options := s.base.DialOptions(opts...) - s.dialer.dialer = dialer.NewDialer(options...) + s.dialer.SetDialer(dialer.NewDialer(options...)) // sing-mux use stream-oriented udp with a special address, so we need a net.UDPAddr if !metadata.Resolved() { @@ -114,7 +94,7 @@ func closeSingMux(s *SingMux) { } func NewSingMux(option SingMuxOption, proxy C.ProxyAdapter, base ProxyBase) (C.ProxyAdapter, error) { - singDialer := &muxSingDialer{dialer: dialer.NewDialer(), proxy: proxy, statistic: option.Statistic} + singDialer := proxydialer.NewSingDialer(proxy, dialer.NewDialer(), option.Statistic) client, err := mux.NewClient(mux.Options{ Dialer: singDialer, Protocol: option.Protocol, diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index c1050ac6..6a11a234 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -27,7 +27,6 @@ import ( "github.com/sagernet/sing/common/debug" E "github.com/sagernet/sing/common/exceptions" M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" "github.com/sagernet/wireguard-go/device" ) @@ -36,7 +35,7 @@ type WireGuard struct { bind *wireguard.ClientBind device *device.Device tunDevice wireguard.Device - dialer *wgSingDialer + dialer proxydialer.SingDialer startOnce sync.Once startErr error resolver *dns.Resolver @@ -70,37 +69,6 @@ type WireGuardPeerOption struct { AllowedIPs []string `proxy:"allowed-ips,omitempty"` } -type wgSingDialer struct { - dialer dialer.Dialer - proxyName string -} - -var _ N.Dialer = (*wgSingDialer)(nil) - -func (d *wgSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { - var cDialer C.Dialer = d.dialer - if len(d.proxyName) > 0 { - pd, err := proxydialer.NewByName(d.proxyName, d.dialer) - if err != nil { - return nil, err - } - cDialer = pd - } - return cDialer.DialContext(ctx, network, destination.String()) -} - -func (d *wgSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { - var cDialer C.Dialer = d.dialer - if len(d.proxyName) > 0 { - pd, err := proxydialer.NewByName(d.proxyName, d.dialer) - if err != nil { - return nil, err - } - cDialer = pd - } - return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) -} - type wgSingErrorHandler struct { name string } @@ -168,7 +136,7 @@ func NewWireGuard(option WireGuardOption) (*WireGuard, error) { rmark: option.RoutingMark, prefer: C.NewDNSPrefer(option.IPVersion), }, - dialer: &wgSingDialer{dialer: dialer.NewDialer(), proxyName: option.DialerProxy}, + dialer: proxydialer.NewByNameSingDialer(option.DialerProxy, dialer.NewDialer()), } runtime.SetFinalizer(outbound, closeWireGuard) @@ -355,7 +323,7 @@ func closeWireGuard(w *WireGuard) { func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { options := w.Base.DialOptions(opts...) - w.dialer.dialer = dialer.NewDialer(options...) + w.dialer.SetDialer(dialer.NewDialer(options...)) var conn net.Conn w.startOnce.Do(func() { w.startErr = w.tunDevice.Start() @@ -387,7 +355,7 @@ func (w *WireGuard) DialContext(ctx context.Context, metadata *C.Metadata, opts func (w *WireGuard) ListenPacketContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.PacketConn, err error) { options := w.Base.DialOptions(opts...) - w.dialer.dialer = dialer.NewDialer(options...) + w.dialer.SetDialer(dialer.NewDialer(options...)) var pc net.PacketConn w.startOnce.Do(func() { w.startErr = w.tunDevice.Start() diff --git a/component/proxydialer/sing.go b/component/proxydialer/sing.go new file mode 100644 index 00000000..9b116527 --- /dev/null +++ b/component/proxydialer/sing.go @@ -0,0 +1,82 @@ +package proxydialer + +import ( + "context" + "net" + + C "github.com/Dreamacro/clash/constant" + + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" +) + +type SingDialer interface { + N.Dialer + SetDialer(dialer C.Dialer) +} + +type singDialer proxyDialer + +var _ N.Dialer = (*singDialer)(nil) + +func (d *singDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + return (*proxyDialer)(d).DialContext(ctx, network, destination.String()) +} + +func (d *singDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + return (*proxyDialer)(d).ListenPacket(ctx, "udp", "", destination.AddrPort()) +} + +func (d *singDialer) SetDialer(dialer C.Dialer) { + (*proxyDialer)(d).dialer = dialer +} + +func NewSingDialer(proxy C.ProxyAdapter, dialer C.Dialer, statistic bool) SingDialer { + return (*singDialer)(&proxyDialer{ + proxy: proxy, + dialer: dialer, + statistic: statistic, + }) +} + +type byNameSingDialer struct { + dialer C.Dialer + proxyName string +} + +var _ N.Dialer = (*byNameSingDialer)(nil) + +func (d *byNameSingDialer) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { + var cDialer C.Dialer = d.dialer + if len(d.proxyName) > 0 { + pd, err := NewByName(d.proxyName, d.dialer) + if err != nil { + return nil, err + } + cDialer = pd + } + return cDialer.DialContext(ctx, network, destination.String()) +} + +func (d *byNameSingDialer) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { + var cDialer C.Dialer = d.dialer + if len(d.proxyName) > 0 { + pd, err := NewByName(d.proxyName, d.dialer) + if err != nil { + return nil, err + } + cDialer = pd + } + return cDialer.ListenPacket(ctx, "udp", "", destination.AddrPort()) +} + +func (d *byNameSingDialer) SetDialer(dialer C.Dialer) { + d.dialer = dialer +} + +func NewByNameSingDialer(proxyName string, dialer C.Dialer) SingDialer { + return &byNameSingDialer{ + dialer: dialer, + proxyName: proxyName, + } +} From 0dfe696300d70eef66dcebf718bb2571d0dc05bd Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 25 Sep 2023 09:11:20 +0800 Subject: [PATCH 448/530] chore: ntp service support `dialer-proxy` --- config/config.go | 7 +++++-- hub/executor/executor.go | 8 ++++++-- ntp/service.go | 21 +++++++++++++-------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/config/config.go b/config/config.go index a1ddde81..e240f9b9 100644 --- a/config/config.go +++ b/config/config.go @@ -93,10 +93,11 @@ type Controller struct { // NTP config type NTP struct { Enable bool `yaml:"enable"` - WriteToSystem bool `yaml:"write-to-system"` Server string `yaml:"server"` Port int `yaml:"port"` Interval int `yaml:"interval"` + DialerProxy string `yaml:"dialer-proxy"` + WriteToSystem bool `yaml:"write-to-system"` } // DNS config @@ -183,10 +184,11 @@ type Config struct { type RawNTP struct { Enable bool `yaml:"enable"` - WriteToSystem bool `yaml:"write-to-system"` Server string `yaml:"server"` ServerPort int `yaml:"server-port"` Interval int `yaml:"interval"` + DialerProxy string `yaml:"dialer-proxy"` + WriteToSystem bool `yaml:"write-to-system"` } type RawDNS struct { @@ -1200,6 +1202,7 @@ func paresNTP(rawCfg *RawConfig) *NTP { Server: cfg.Server, Port: cfg.ServerPort, Interval: cfg.Interval, + DialerProxy: cfg.DialerProxy, WriteToSystem: cfg.WriteToSystem, } return ntpCfg diff --git a/hub/executor/executor.go b/hub/executor/executor.go index d1636754..1831584f 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -190,8 +190,12 @@ func updateExperimental(c *config.Config) { func updateNTP(c *config.NTP) { if c.Enable { - ntp.ReCreateNTPService(net.JoinHostPort(c.Server, strconv.Itoa(c.Port)), - time.Duration(c.Interval), c.WriteToSystem) + ntp.ReCreateNTPService( + net.JoinHostPort(c.Server, strconv.Itoa(c.Port)), + time.Duration(c.Interval), + c.DialerProxy, + c.WriteToSystem, + ) } } diff --git a/ntp/service.go b/ntp/service.go index 3234180d..c5506197 100644 --- a/ntp/service.go +++ b/ntp/service.go @@ -2,12 +2,15 @@ package ntp import ( "context" - "github.com/Dreamacro/clash/log" - M "github.com/sagernet/sing/common/metadata" - N "github.com/sagernet/sing/common/network" - "github.com/sagernet/sing/common/ntp" "sync" "time" + + "github.com/Dreamacro/clash/component/dialer" + "github.com/Dreamacro/clash/component/proxydialer" + "github.com/Dreamacro/clash/log" + + M "github.com/sagernet/sing/common/metadata" + "github.com/sagernet/sing/common/ntp" ) var offset time.Duration @@ -15,6 +18,7 @@ var service *Service type Service struct { server M.Socksaddr + dialer proxydialer.SingDialer ticker *time.Ticker ctx context.Context cancel context.CancelFunc @@ -23,16 +27,17 @@ type Service struct { running bool } -func ReCreateNTPService(server string, interval time.Duration, syncSystemTime bool) { +func ReCreateNTPService(server string, interval time.Duration, dialerProxy string, syncSystemTime bool) { if service != nil { service.Stop() } ctx, cancel := context.WithCancel(context.Background()) service = &Service{ + server: M.ParseSocksaddr(server), + dialer: proxydialer.NewByNameSingDialer(dialerProxy, dialer.NewDialer()), + ticker: time.NewTicker(interval * time.Minute), ctx: ctx, cancel: cancel, - server: M.ParseSocksaddr(server), - ticker: time.NewTicker(interval * time.Minute), syncSystemTime: syncSystemTime, } service.Start() @@ -70,7 +75,7 @@ func (srv *Service) update() { var response *ntp.Response var err error for i := 0; i < 3; i++ { - response, err = ntp.Exchange(context.Background(), N.SystemDialer, srv.server) + response, err = ntp.Exchange(context.Background(), srv.dialer, srv.server) if err != nil { if i == 2 { log.Errorln("Initialize NTP time failed: %s", err) From fdd327d58da49b0bf21b0908bc7e3d475eae63a3 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Mon, 25 Sep 2023 13:28:11 +0800 Subject: [PATCH 449/530] fix: fail to set KeepAliveIntervall #715 --- common/net/tcpip.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/net/tcpip.go b/common/net/tcpip.go index 7bc31edd..0499e54c 100644 --- a/common/net/tcpip.go +++ b/common/net/tcpip.go @@ -51,6 +51,6 @@ func SplitHostPort(s string) (host, port string, hasPort bool, err error) { func TCPKeepAlive(c net.Conn) { if tcp, ok := c.(*net.TCPConn); ok { _ = tcp.SetKeepAlive(true) - _ = tcp.SetKeepAlivePeriod(KeepAliveInterval * time.Second) + _ = tcp.SetKeepAlivePeriod(KeepAliveInterval) } } From fb99412193de303ceea52e30fc1c762f576651f3 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 26 Sep 2023 08:51:25 +0800 Subject: [PATCH 450/530] chore: update quic-go to 0.39.0 --- go.mod | 8 ++--- go.sum | 30 +++++-------------- transport/hysteria/congestion/brutal.go | 2 +- transport/tuic/common/congestion.go | 2 -- .../tuic/congestion/bandwidth_sampler.go | 4 +-- transport/tuic/congestion/bbr_sender.go | 4 +-- transport/tuic/congestion/cubic_sender.go | 27 +---------------- 7 files changed, 18 insertions(+), 59 deletions(-) diff --git a/go.mod b/go.mod index 6c67a38a..74f5d0a7 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ 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.38.1-0.20230909013832-033f6a2115cf - github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81 + github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731 + github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.12 @@ -69,7 +69,6 @@ require ( github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.3.0 // 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 github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect @@ -85,7 +84,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.3 // indirect + github.com/quic-go/qtls-go1-20 v0.3.4 // 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 @@ -99,6 +98,7 @@ 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 + go.uber.org/mock v0.3.0 // indirect golang.org/x/mod v0.12.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect diff --git a/go.sum b/go.sum index 0105d57d..d251a6b7 100644 --- a/go.sum +++ b/go.sum @@ -51,8 +51,6 @@ github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEe 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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -95,12 +93,12 @@ 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.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= -github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= +github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731 h1:F+xz1KCwUfCud5eWHKZr0QsWOeA+mqIFvn90r8hq+R8= +github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140 h1:qiTekhMDwY2vXARJx1D9EIEdtllbL7+ZBzHX9DQpWs4= github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81 h1:6g+ohVa8FQLXz/ATmped/4kWuK0HKvhy1hwzQXyF0EI= -github.com/metacubex/sing-quic v0.0.0-20230921160948-82175eb07a81/go.mod h1:oGpQmqe5tj3sPdPWCNLbBoUSwqd+Z6SqVO7TlMNVnH4= +github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= +github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= @@ -139,8 +137,8 @@ github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErp github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= 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.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= -github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= +github.com/quic-go/qtls-go1-20 v0.3.4/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= @@ -197,7 +195,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/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= github.com/zhangyunhao116/fastrand v0.3.0 h1:7bwe124xcckPulX6fxtr2lFdO2KQqaefdtbk+mqO/Ig= @@ -208,6 +205,8 @@ 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.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= +go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= +go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= 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.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= @@ -216,16 +215,13 @@ golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjs golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= 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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.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.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= 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= 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= @@ -235,10 +231,7 @@ golang.org/x/sys v0.0.0-20190804053845-51ab0e2deafa/go.mod h1:h1NjWce9XRLGQEsW7w 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= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -248,23 +241,16 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.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.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= -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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= diff --git a/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 9992f6a0..88bf6f34 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -85,7 +85,7 @@ func (b *BrutalSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes b.updateAckRate(currentTimestamp) } -func (b *BrutalSender) OnPacketLost(number congestion.PacketNumber, lostBytes congestion.ByteCount, +func (b *BrutalSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { currentTimestamp := time.Now().Unix() slot := currentTimestamp % pktInfoSlotCount diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index 36ee01a1..158f22d6 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -23,7 +23,6 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { congestion.DefaultClock{}, congestion.GetInitialPacketSize(quicConn.RemoteAddr()), false, - nil, ), ) case "new_reno": @@ -32,7 +31,6 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { congestion.DefaultClock{}, congestion.GetInitialPacketSize(quicConn.RemoteAddr()), true, - nil, ), ) case "bbr": diff --git a/transport/tuic/congestion/bandwidth_sampler.go b/transport/tuic/congestion/bandwidth_sampler.go index b82d391f..e415fe7a 100644 --- a/transport/tuic/congestion/bandwidth_sampler.go +++ b/transport/tuic/congestion/bandwidth_sampler.go @@ -296,9 +296,9 @@ func (s *BandwidthSampler) onPacketAckedInner(ackTime time.Time, lastAckedPacket return sample } -// OnPacketLost Informs the sampler that a packet is considered lost and it should no +// OnCongestionEvent Informs the sampler that a packet is considered lost and it should no // longer keep track of it. -func (s *BandwidthSampler) OnPacketLost(packetNumber congestion.PacketNumber) SendTimeState { +func (s *BandwidthSampler) OnCongestionEvent(packetNumber congestion.PacketNumber) SendTimeState { ok, sentPacket := s.connectionStats.Remove(packetNumber) sendTimeState := SendTimeState{ isValid: ok, diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index e78819c7..2c842300 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -374,7 +374,7 @@ func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes con } -func (b *bbrSender) OnPacketLost(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { +func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { eventTime := time.Now() totalBytesAckedBefore := b.sampler.totalBytesAcked isRoundStart, minRttExpired := false, false @@ -620,7 +620,7 @@ func (b *bbrSender) ShouldExtendMinRttExpiry() bool { } func (b *bbrSender) DiscardLostPackets(number congestion.PacketNumber, lostBytes congestion.ByteCount) { - b.sampler.OnPacketLost(number) + b.sampler.OnCongestionEvent(number) if b.mode == STARTUP { // if b.rttStats != nil { // TODO: slow start. diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go index ca20b420..e058ac7d 100644 --- a/transport/tuic/congestion/cubic_sender.go +++ b/transport/tuic/congestion/cubic_sender.go @@ -5,7 +5,6 @@ import ( "time" "github.com/metacubex/quic-go/congestion" - "github.com/metacubex/quic-go/logging" ) const ( @@ -54,9 +53,6 @@ type cubicSender struct { initialMaxCongestionWindow congestion.ByteCount maxDatagramSize congestion.ByteCount - - lastState logging.CongestionState - tracer logging.ConnectionTracer } var ( @@ -68,7 +64,6 @@ func NewCubicSender( clock Clock, initialMaxDatagramSize congestion.ByteCount, reno bool, - tracer logging.ConnectionTracer, ) *cubicSender { return newCubicSender( clock, @@ -76,7 +71,6 @@ func NewCubicSender( initialMaxDatagramSize, initialCongestionWindow*initialMaxDatagramSize, MaxCongestionWindowPackets*initialMaxDatagramSize, - tracer, ) } @@ -86,7 +80,6 @@ func newCubicSender( initialMaxDatagramSize, initialCongestionWindow, initialMaxCongestionWindow congestion.ByteCount, - tracer logging.ConnectionTracer, ) *cubicSender { c := &cubicSender{ largestSentPacketNumber: InvalidPacketNumber, @@ -99,14 +92,9 @@ func newCubicSender( cubic: NewCubic(clock), clock: clock, reno: reno, - tracer: tracer, maxDatagramSize: initialMaxDatagramSize, } c.pacer = newPacer(c.BandwidthEstimate) - if c.tracer != nil { - c.lastState = logging.CongestionStateSlowStart - c.tracer.UpdatedCongestionState(logging.CongestionStateSlowStart) - } return c } @@ -167,7 +155,6 @@ func (c *cubicSender) MaybeExitSlowStart() { c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/c.maxDatagramSize) { // exit slow start c.slowStartThreshold = c.congestionWindow - c.maybeTraceStateChange(logging.CongestionStateCongestionAvoidance) } } @@ -187,14 +174,13 @@ func (c *cubicSender) OnPacketAcked( } } -func (c *cubicSender) OnPacketLost(packetNumber congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { +func (c *cubicSender) OnCongestionEvent(packetNumber congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets // already sent should be treated as a single loss event, since it's expected. if packetNumber <= c.largestSentAtLastCutback { return } c.lastCutbackExitedSlowstart = c.InSlowStart() - c.maybeTraceStateChange(logging.CongestionStateRecovery) if c.reno { c.congestionWindow = congestion.ByteCount(float64(c.congestionWindow) * renoBeta) @@ -223,7 +209,6 @@ func (c *cubicSender) maybeIncreaseCwnd( // the current window. if !c.isCwndLimited(priorInFlight) { c.cubic.OnApplicationLimited() - c.maybeTraceStateChange(logging.CongestionStateApplicationLimited) return } if c.congestionWindow >= c.maxCongestionWindow() { @@ -232,11 +217,9 @@ func (c *cubicSender) maybeIncreaseCwnd( if c.InSlowStart() { // TCP slow start, exponential growth, increase by one for each ACK. c.congestionWindow += c.maxDatagramSize - c.maybeTraceStateChange(logging.CongestionStateSlowStart) return } // Congestion avoidance - c.maybeTraceStateChange(logging.CongestionStateCongestionAvoidance) if c.reno { // Classic Reno congestion avoidance. c.numAckedPackets++ @@ -297,14 +280,6 @@ func (c *cubicSender) OnConnectionMigration() { c.slowStartThreshold = c.initialMaxCongestionWindow } -func (c *cubicSender) maybeTraceStateChange(new logging.CongestionState) { - if c.tracer == nil || new == c.lastState { - return - } - c.tracer.UpdatedCongestionState(new) - c.lastState = new -} - func (c *cubicSender) SetMaxDatagramSize(s congestion.ByteCount) { if s < c.maxDatagramSize { panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", c.maxDatagramSize, s)) From 21fb5f75b8f383b343601402722130a90cb95d44 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 26 Sep 2023 09:06:00 +0800 Subject: [PATCH 451/530] fix: gvisor panic --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 74f5d0a7..3c26f0ae 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.12 + github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 github.com/miekg/dns v1.1.56 @@ -105,4 +105,4 @@ require ( golang.org/x/tools v0.13.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 diff --git a/go.sum b/go.sum index d251a6b7..584a797f 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.39.1-0.20230926003849-db956da2a731 h1:F+xz1KCwUfCud5eWHKZr0QsWOeA+mqIFvn90r8hq+R8= github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= -github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140 h1:qiTekhMDwY2vXARJx1D9EIEdtllbL7+ZBzHX9DQpWs4= -github.com/metacubex/sing v0.0.0-20230921160249-edb949c9c140/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 h1:MkYAvDyhb7cwuqL4ZLKU3Oi6tYjFnz1sz5LS82JmtDo= +github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.12 h1:Jgmz0k3ddRiJ8zfS4X7j6B/iSy6GnOdDEU0nhqiZcK4= -github.com/metacubex/sing-tun v0.1.12/go.mod h1:X2P/H1HqXwqGcguGXWDVDhSS1GmDxVi13OmbtDedZ2M= +github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee h1:hbbq181N4ZaDbhk/iJ0iA+3xfI/6v+j3nWeN5Who1xQ= +github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee/go.mod h1:X2P/H1HqXwqGcguGXWDVDhSS1GmDxVi13OmbtDedZ2M= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 h1:mXFpxfR/1nADh+GoT8maWEvc6LO6uatPsARD8WzUDMA= From e0458a8fdef6c0d722c5c2c383f62ae6ffe96da9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 28 Sep 2023 18:59:31 +0800 Subject: [PATCH 452/530] chore: decrease goroutine used in core tunnel --- adapter/inbound/addition.go | 11 +++++ constant/listener.go | 2 +- constant/tunnel.go | 10 +++++ hub/executor/executor.go | 30 ++++++-------- hub/route/configs.go | 22 ++++------ listener/autoredir/tcp.go | 8 ++-- listener/http/client.go | 4 +- listener/http/proxy.go | 8 ++-- listener/http/server.go | 8 ++-- listener/http/upgrade.go | 4 +- listener/inbound/base.go | 2 +- listener/inbound/http.go | 4 +- listener/inbound/hysteria2.go | 4 +- listener/inbound/mixed.go | 6 +-- listener/inbound/redir.go | 4 +- listener/inbound/shadowsocks.go | 4 +- listener/inbound/socks.go | 6 +-- listener/inbound/tproxy.go | 6 +-- listener/inbound/tuic.go | 4 +- listener/inbound/tun.go | 4 +- listener/inbound/tunnel.go | 12 +++--- listener/inbound/vmess.go | 4 +- listener/inner/tcp.go | 10 ++--- listener/listener.go | 64 ++++++++++++++--------------- listener/mixed/mixed.go | 12 +++--- listener/redir/tcp.go | 9 ++-- listener/shadowsocks/tcp.go | 14 +++---- listener/shadowsocks/udp.go | 11 ++--- listener/sing/sing.go | 47 ++++----------------- listener/sing_hysteria2/server.go | 5 +-- listener/sing_shadowsocks/server.go | 17 ++++---- listener/sing_tun/server.go | 5 +-- listener/sing_vmess/server.go | 13 +++--- listener/socks/tcp.go | 18 ++++---- listener/socks/udp.go | 11 ++--- listener/tproxy/packet.go | 20 ++++----- listener/tproxy/tproxy.go | 8 ++-- listener/tproxy/udp.go | 20 ++++----- listener/tuic/server.go | 12 ++---- listener/tunnel/tcp.go | 8 ++-- listener/tunnel/udp.go | 11 ++--- tunnel/tunnel.go | 39 ++++++++++++++---- 42 files changed, 252 insertions(+), 269 deletions(-) create mode 100644 constant/tunnel.go diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 47307ed7..327d00e9 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -1,6 +1,8 @@ package inbound import ( + "net" + C "github.com/Dreamacro/clash/constant" ) @@ -33,3 +35,12 @@ func WithSpecialProxy(specialProxy string) Addition { metadata.SpecialProxy = specialProxy } } + +func WithSrcAddr(addr net.Addr) Addition { + return func(metadata *C.Metadata) { + if ip, port, err := parseAddr(addr); err == nil { + metadata.SrcIP = ip + metadata.SrcPort = port + } + } +} diff --git a/constant/listener.go b/constant/listener.go index 6f9f169b..f69b4a9b 100644 --- a/constant/listener.go +++ b/constant/listener.go @@ -16,7 +16,7 @@ type MultiAddrListener interface { type InboundListener interface { Name() string - Listen(tcpIn chan<- ConnContext, udpIn chan<- PacketAdapter, natTable NatTable) error + Listen(tunnel Tunnel) error Close() error Address() string RawAddress() string diff --git a/constant/tunnel.go b/constant/tunnel.go new file mode 100644 index 00000000..39f8936a --- /dev/null +++ b/constant/tunnel.go @@ -0,0 +1,10 @@ +package constant + +type Tunnel interface { + // HandleTCPConn will handle a tcp connection blocking + HandleTCPConn(connCtx ConnContext) + // HandleUDPPacket will handle a udp packet nonblocking + HandleUDPPacket(packet PacketAdapter) + // NatTable return nat table + NatTable() NatTable +} diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 1831584f..a50d3539 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -118,7 +118,7 @@ func ApplyConfig(cfg *config.Config, force bool) { } func initInnerTcp() { - inner.New(tunnel.TCPIn()) + inner.New(tunnel.Tunnel) } func GetGeneral() *config.General { @@ -157,11 +157,7 @@ func GetGeneral() *config.General { } func updateListeners(general *config.General, listeners map[string]C.InboundListener, force bool) { - tcpIn := tunnel.TCPIn() - udpIn := tunnel.UDPIn() - natTable := tunnel.NatTable() - - listener.PatchInboundListeners(listeners, tcpIn, udpIn, natTable, true) + listener.PatchInboundListeners(listeners, tunnel.Tunnel, true) if !force { return } @@ -171,15 +167,15 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList bindAddress := general.BindAddress listener.SetBindAddress(bindAddress) - listener.ReCreateHTTP(general.Port, tcpIn) - listener.ReCreateSocks(general.SocksPort, tcpIn, udpIn) - listener.ReCreateRedir(general.RedirPort, tcpIn, udpIn, natTable) - listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tcpIn, udpIn) - listener.ReCreateTProxy(general.TProxyPort, tcpIn, udpIn, natTable) - listener.ReCreateMixed(general.MixedPort, tcpIn, udpIn) - listener.ReCreateShadowSocks(general.ShadowSocksConfig, tcpIn, udpIn) - listener.ReCreateVmess(general.VmessConfig, tcpIn, udpIn) - listener.ReCreateTuic(LC.TuicServer(general.TuicServer), tcpIn, udpIn) + listener.ReCreateHTTP(general.Port, tunnel.Tunnel) + listener.ReCreateSocks(general.SocksPort, tunnel.Tunnel) + listener.ReCreateRedir(general.RedirPort, tunnel.Tunnel) + listener.ReCreateAutoRedir(general.EBpf.AutoRedir, tunnel.Tunnel) + listener.ReCreateTProxy(general.TProxyPort, tunnel.Tunnel) + listener.ReCreateMixed(general.MixedPort, tunnel.Tunnel) + listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel) + listener.ReCreateVmess(general.VmessConfig, tunnel.Tunnel) + listener.ReCreateTuic(general.TuicServer, tunnel.Tunnel) } func updateExperimental(c *config.Config) { @@ -339,7 +335,7 @@ func updateTun(general *config.General) { if general == nil { return } - listener.ReCreateTun(LC.Tun(general.Tun), tunnel.TCPIn(), tunnel.UDPIn()) + listener.ReCreateTun(general.Tun, tunnel.Tunnel) listener.ReCreateRedirToTun(general.Tun.RedirectToTun) } @@ -367,7 +363,7 @@ func updateSniffer(sniffer *config.Sniffer) { } func updateTunnels(tunnels []LC.Tunnel) { - listener.PatchTunnel(tunnels, tunnel.TCPIn(), tunnel.UDPIn()) + listener.PatchTunnel(tunnels, tunnel.Tunnel) } func updateGeneral(general *config.General) { diff --git a/hub/route/configs.go b/hub/route/configs.go index cb7c93f6..1f29de0c 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -249,19 +249,15 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { ports := P.GetPorts() - tcpIn := tunnel.TCPIn() - udpIn := tunnel.UDPIn() - natTable := tunnel.NatTable() - - P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tcpIn) - P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tcpIn, udpIn) - P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tcpIn, udpIn, natTable) - P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tcpIn, udpIn, natTable) - P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tcpIn, udpIn) - P.ReCreateTun(pointerOrDefaultTun(general.Tun, P.LastTunConf), tcpIn, udpIn) - P.ReCreateShadowSocks(pointerOrDefaultString(general.ShadowSocksConfig, ports.ShadowSocksConfig), tcpIn, udpIn) - P.ReCreateVmess(pointerOrDefaultString(general.VmessConfig, ports.VmessConfig), tcpIn, udpIn) - P.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, P.LastTuicConf), tcpIn, udpIn) + P.ReCreateHTTP(pointerOrDefault(general.Port, ports.Port), tunnel.Tunnel) + P.ReCreateSocks(pointerOrDefault(general.SocksPort, ports.SocksPort), tunnel.Tunnel) + P.ReCreateRedir(pointerOrDefault(general.RedirPort, ports.RedirPort), tunnel.Tunnel) + P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tunnel.Tunnel) + P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tunnel.Tunnel) + P.ReCreateTun(pointerOrDefaultTun(general.Tun, P.LastTunConf), tunnel.Tunnel) + P.ReCreateShadowSocks(pointerOrDefaultString(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel) + P.ReCreateVmess(pointerOrDefaultString(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel) + P.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, P.LastTuicConf), tunnel.Tunnel) if general.Mode != nil { tunnel.SetMode(*general.Mode) diff --git a/listener/autoredir/tcp.go b/listener/autoredir/tcp.go index c390d89a..57df45f3 100644 --- a/listener/autoredir/tcp.go +++ b/listener/autoredir/tcp.go @@ -43,7 +43,7 @@ func (l *Listener) SetLookupFunc(lookupFunc func(netip.AddrPort) (socks5.Addr, e l.lookupFunc = lookupFunc } -func (l *Listener) handleRedir(conn net.Conn, in chan<- C.ConnContext) { +func (l *Listener) handleRedir(conn net.Conn, tunnel C.Tunnel) { if l.lookupFunc == nil { log.Errorln("[Auto Redirect] lookup function is nil") return @@ -58,10 +58,10 @@ func (l *Listener) handleRedir(conn net.Conn, in chan<- C.ConnContext) { N.TCPKeepAlive(conn) - in <- inbound.NewSocket(target, conn, C.REDIR, l.additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.REDIR, l.additions...)) } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-REDIR"), @@ -87,7 +87,7 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go rl.handleRedir(c, in) + go rl.handleRedir(c, tunnel) } }() diff --git a/listener/http/client.go b/listener/http/client.go index 15c21f91..76c7c8eb 100644 --- a/listener/http/client.go +++ b/listener/http/client.go @@ -12,7 +12,7 @@ import ( "github.com/Dreamacro/clash/transport/socks5" ) -func newClient(source net.Addr, in chan<- C.ConnContext, additions ...inbound.Addition) *http.Client { +func newClient(source net.Addr, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client { return &http.Client{ Transport: &http.Transport{ // from http.DefaultTransport @@ -32,7 +32,7 @@ func newClient(source net.Addr, in chan<- C.ConnContext, additions ...inbound.Ad left, right := net.Pipe() - in <- inbound.NewHTTP(dstAddr, source, right, additions...) + go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, source, right, additions...)) return left, nil }, diff --git a/listener/http/proxy.go b/listener/http/proxy.go index a95f7195..a267fbad 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -14,8 +14,8 @@ import ( "github.com/Dreamacro/clash/log" ) -func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { - client := newClient(c.RemoteAddr(), in, additions...) +func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { + client := newClient(c.RemoteAddr(), tunnel, additions...) defer client.CloseIdleConnections() conn := N.NewBufferedConn(c) @@ -48,7 +48,7 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[strin break // close connection } - in <- inbound.NewHTTPS(request, conn, additions...) + tunnel.HandleTCPConn(inbound.NewHTTPS(request, conn, additions...)) return // hijack connection } @@ -61,7 +61,7 @@ func HandleConn(c net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[strin request.RequestURI = "" if isUpgradeRequest(request) { - handleUpgrade(conn, request, in, additions...) + handleUpgrade(conn, request, tunnel, additions...) return // hijack connection } diff --git a/listener/http/server.go b/listener/http/server.go index 8819af11..0377d3b6 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -30,11 +30,11 @@ func (l *Listener) Close() error { return l.listener.Close() } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { - return NewWithAuthenticate(addr, in, true, additions...) +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { + return NewWithAuthenticate(addr, tunnel, true, additions...) } -func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool, additions ...inbound.Addition) (*Listener, error) { +func NewWithAuthenticate(addr string, tunnel C.Tunnel, authenticate bool, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-HTTP"), @@ -65,7 +65,7 @@ func NewWithAuthenticate(addr string, in chan<- C.ConnContext, authenticate bool } continue } - go HandleConn(conn, in, c, additions...) + go HandleConn(conn, tunnel, c, additions...) } }() diff --git a/listener/http/upgrade.go b/listener/http/upgrade.go index 90e28f0a..e67928ce 100644 --- a/listener/http/upgrade.go +++ b/listener/http/upgrade.go @@ -25,7 +25,7 @@ func isUpgradeRequest(req *http.Request) bool { return false } -func handleUpgrade(conn net.Conn, request *http.Request, in chan<- C.ConnContext, additions ...inbound.Addition) { +func handleUpgrade(conn net.Conn, request *http.Request, tunnel C.Tunnel, additions ...inbound.Addition) { defer conn.Close() removeProxyHeaders(request.Header) @@ -43,7 +43,7 @@ func handleUpgrade(conn net.Conn, request *http.Request, in chan<- C.ConnContext left, right := net.Pipe() - in <- inbound.NewHTTP(dstAddr, conn.RemoteAddr(), right, additions...) + go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, conn.RemoteAddr(), right, additions...)) var bufferedLeft *N.BufferedConn if request.TLS != nil { diff --git a/listener/inbound/base.go b/listener/inbound/base.go index b132ac6c..83695bb1 100644 --- a/listener/inbound/base.go +++ b/listener/inbound/base.go @@ -61,7 +61,7 @@ func (b *Base) RawAddress() string { } // Listen implements constant.InboundListener -func (*Base) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (*Base) Listen(tunnel C.Tunnel) error { return nil } diff --git a/listener/inbound/http.go b/listener/inbound/http.go index a93f9684..99577177 100644 --- a/listener/inbound/http.go +++ b/listener/inbound/http.go @@ -42,9 +42,9 @@ func (h *HTTP) Address() string { } // Listen implements constant.InboundListener -func (h *HTTP) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (h *HTTP) Listen(tunnel C.Tunnel) error { var err error - h.l, err = http.New(h.RawAddress(), tcpIn, h.Additions()...) + h.l, err = http.New(h.RawAddress(), tunnel, h.Additions()...) if err != nil { return err } diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go index 430d0e68..df537a41 100644 --- a/listener/inbound/hysteria2.go +++ b/listener/inbound/hysteria2.go @@ -77,9 +77,9 @@ func (t *Hysteria2) Address() string { } // Listen implements constant.InboundListener -func (t *Hysteria2) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *Hysteria2) Listen(tunnel C.Tunnel) error { var err error - t.l, err = sing_hysteria2.New(t.ts, tcpIn, udpIn, t.Additions()...) + t.l, err = sing_hysteria2.New(t.ts, tunnel, t.Additions()...) if err != nil { return err } diff --git a/listener/inbound/mixed.go b/listener/inbound/mixed.go index dbba264c..ce445bda 100644 --- a/listener/inbound/mixed.go +++ b/listener/inbound/mixed.go @@ -50,14 +50,14 @@ func (m *Mixed) Address() string { } // Listen implements constant.InboundListener -func (m *Mixed) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (m *Mixed) Listen(tunnel C.Tunnel) error { var err error - m.l, err = mixed.New(m.RawAddress(), tcpIn, m.Additions()...) + m.l, err = mixed.New(m.RawAddress(), tunnel, m.Additions()...) if err != nil { return err } if m.udp { - m.lUDP, err = socks.NewUDP(m.RawAddress(), udpIn, m.Additions()...) + m.lUDP, err = socks.NewUDP(m.RawAddress(), tunnel, m.Additions()...) if err != nil { return err } diff --git a/listener/inbound/redir.go b/listener/inbound/redir.go index 4b88d895..085bf3a8 100644 --- a/listener/inbound/redir.go +++ b/listener/inbound/redir.go @@ -42,9 +42,9 @@ func (r *Redir) Address() string { } // Listen implements constant.InboundListener -func (r *Redir) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (r *Redir) Listen(tunnel C.Tunnel) error { var err error - r.l, err = redir.New(r.RawAddress(), tcpIn, r.Additions()...) + r.l, err = redir.New(r.RawAddress(), tunnel, r.Additions()...) if err != nil { return err } diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go index 4659f4d7..fa5b3082 100644 --- a/listener/inbound/shadowsocks.go +++ b/listener/inbound/shadowsocks.go @@ -59,9 +59,9 @@ func (s *ShadowSocks) Address() string { } // Listen implements constant.InboundListener -func (s *ShadowSocks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (s *ShadowSocks) Listen(tunnel C.Tunnel) error { var err error - s.l, err = sing_shadowsocks.New(s.ss, tcpIn, udpIn, s.Additions()...) + s.l, err = sing_shadowsocks.New(s.ss, tunnel, s.Additions()...) if err != nil { return err } diff --git a/listener/inbound/socks.go b/listener/inbound/socks.go index aac2ee23..09580a57 100644 --- a/listener/inbound/socks.go +++ b/listener/inbound/socks.go @@ -68,13 +68,13 @@ func (s *Socks) Address() string { } // Listen implements constant.InboundListener -func (s *Socks) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (s *Socks) Listen(tunnel C.Tunnel) error { var err error - if s.stl, err = socks.New(s.RawAddress(), tcpIn, s.Additions()...); err != nil { + if s.stl, err = socks.New(s.RawAddress(), tunnel, s.Additions()...); err != nil { return err } if s.udp { - if s.sul, err = socks.NewUDP(s.RawAddress(), udpIn, s.Additions()...); err != nil { + if s.sul, err = socks.NewUDP(s.RawAddress(), tunnel, s.Additions()...); err != nil { return err } } diff --git a/listener/inbound/tproxy.go b/listener/inbound/tproxy.go index 00cd0849..682188f5 100644 --- a/listener/inbound/tproxy.go +++ b/listener/inbound/tproxy.go @@ -49,14 +49,14 @@ func (t *TProxy) Address() string { } // Listen implements constant.InboundListener -func (t *TProxy) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *TProxy) Listen(tunnel C.Tunnel) error { var err error - t.lTCP, err = tproxy.New(t.RawAddress(), tcpIn, t.Additions()...) + t.lTCP, err = tproxy.New(t.RawAddress(), tunnel, t.Additions()...) if err != nil { return err } if t.udp { - t.lUDP, err = tproxy.NewUDP(t.RawAddress(), udpIn, natTable, t.Additions()...) + t.lUDP, err = tproxy.NewUDP(t.RawAddress(), tunnel, t.Additions()...) if err != nil { return err } diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index bf448d31..e7b51392 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -73,9 +73,9 @@ func (t *Tuic) Address() string { } // Listen implements constant.InboundListener -func (t *Tuic) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *Tuic) Listen(tunnel C.Tunnel) error { var err error - t.l, err = tuic.New(t.ts, tcpIn, udpIn, t.Additions()...) + t.l, err = tuic.New(t.ts, tunnel, t.Additions()...) if err != nil { return err } diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index eb16d2dd..3151e6b0 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -113,9 +113,9 @@ func (t *Tun) Address() string { } // Listen implements constant.InboundListener -func (t *Tun) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *Tun) Listen(tunnel C.Tunnel) error { var err error - t.l, err = sing_tun.New(t.tun, tcpIn, udpIn, t.Additions()...) + t.l, err = sing_tun.New(t.tun, tunnel, t.Additions()...) if err != nil { return err } diff --git a/listener/inbound/tunnel.go b/listener/inbound/tunnel.go index 41d024ef..2af663a5 100644 --- a/listener/inbound/tunnel.go +++ b/listener/inbound/tunnel.go @@ -4,7 +4,7 @@ import ( "fmt" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/tunnel" + LT "github.com/Dreamacro/clash/listener/tunnel" "github.com/Dreamacro/clash/log" ) @@ -21,8 +21,8 @@ func (o TunnelOption) Equal(config C.InboundConfig) bool { type Tunnel struct { *Base config *TunnelOption - ttl *tunnel.Listener - tul *tunnel.PacketConn + ttl *LT.Listener + tul *LT.PacketConn } func NewTunnel(options *TunnelOption) (*Tunnel, error) { @@ -74,16 +74,16 @@ func (t *Tunnel) Address() string { } // Listen implements constant.InboundListener -func (t *Tunnel) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (t *Tunnel) Listen(tunnel C.Tunnel) error { var err error for _, network := range t.config.Network { switch network { case "tcp": - if t.ttl, err = tunnel.New(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tcpIn, t.Additions()...); err != nil { + if t.ttl, err = LT.New(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...); err != nil { return err } case "udp": - if t.tul, err = tunnel.NewUDP(t.RawAddress(), t.config.Target, t.config.SpecialProxy, udpIn, t.Additions()...); err != nil { + if t.tul, err = LT.NewUDP(t.RawAddress(), t.config.Target, t.config.SpecialProxy, tunnel, t.Additions()...); err != nil { return err } default: diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 70e840a5..fa2c30f1 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -69,7 +69,7 @@ func (v *Vmess) Address() string { } // Listen implements constant.InboundListener -func (v *Vmess) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) error { +func (v *Vmess) Listen(tunnel C.Tunnel) error { var err error users := make([]LC.VmessUser, len(v.config.Users)) for i, v := range v.config.Users { @@ -79,7 +79,7 @@ func (v *Vmess) Listen(tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, AlterID: v.AlterID, } } - v.l, err = sing_vmess.New(v.vs, tcpIn, udpIn, v.Additions()...) + v.l, err = sing_vmess.New(v.vs, tunnel, v.Additions()...) if err != nil { return err } diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index 9ba87e2f..4a54a82f 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -8,19 +8,19 @@ import ( C "github.com/Dreamacro/clash/constant" ) -var tcpIn chan<- C.ConnContext +var tunnel C.Tunnel -func New(in chan<- C.ConnContext) { - tcpIn = in +func New(t C.Tunnel) { + tunnel = t } func HandleTcp(address string) (conn net.Conn, err error) { - if tcpIn == nil { + if tunnel == nil { return nil, errors.New("tcp uninitialized") } // executor Parsed conn1, conn2 := net.Pipe() context := inbound.NewInner(conn2, address) - tcpIn <- context + go tunnel.HandleTCPConn(context) return conn1, nil } diff --git a/listener/listener.go b/listener/listener.go index b1d59d49..afbcf14c 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -23,7 +23,7 @@ import ( "github.com/Dreamacro/clash/listener/socks" "github.com/Dreamacro/clash/listener/tproxy" "github.com/Dreamacro/clash/listener/tuic" - "github.com/Dreamacro/clash/listener/tunnel" + LT "github.com/Dreamacro/clash/listener/tunnel" "github.com/Dreamacro/clash/log" "github.com/samber/lo" @@ -42,8 +42,8 @@ var ( tproxyUDPListener *tproxy.UDPListener mixedListener *mixed.Listener mixedUDPLister *socks.UDPListener - tunnelTCPListeners = map[string]*tunnel.Listener{} - tunnelUDPListeners = map[string]*tunnel.PacketConn{} + tunnelTCPListeners = map[string]*LT.Listener{} + tunnelUDPListeners = map[string]*LT.PacketConn{} inboundListeners = map[string]C.InboundListener{} tunLister *sing_tun.Listener shadowSocksListener C.MultiAddrListener @@ -112,7 +112,7 @@ func SetBindAddress(host string) { bindAddress = host } -func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) { +func ReCreateHTTP(port int, tunnel C.Tunnel) { httpMux.Lock() defer httpMux.Unlock() @@ -137,7 +137,7 @@ func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) { return } - httpListener, err = http.New(addr, tcpIn) + httpListener, err = http.New(addr, tunnel) if err != nil { log.Errorln("Start HTTP server error: %s", err.Error()) return @@ -146,7 +146,7 @@ func ReCreateHTTP(port int, tcpIn chan<- C.ConnContext) { log.Infoln("HTTP proxy listening at: %s", httpListener.Address()) } -func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateSocks(port int, tunnel C.Tunnel) { socksMux.Lock() defer socksMux.Unlock() @@ -188,12 +188,12 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd return } - tcpListener, err := socks.New(addr, tcpIn) + tcpListener, err := socks.New(addr, tunnel) if err != nil { return } - udpListener, err := socks.NewUDP(addr, udpIn) + udpListener, err := socks.NewUDP(addr, tunnel) if err != nil { tcpListener.Close() return @@ -205,7 +205,7 @@ func ReCreateSocks(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd log.Infoln("SOCKS proxy listening at: %s", socksListener.Address()) } -func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) { +func ReCreateRedir(port int, tunnel C.Tunnel) { redirMux.Lock() defer redirMux.Unlock() @@ -238,12 +238,12 @@ func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd return } - redirListener, err = redir.New(addr, tcpIn) + redirListener, err = redir.New(addr, tunnel) if err != nil { return } - redirUDPListener, err = tproxy.NewUDP(addr, udpIn, natTable) + redirUDPListener, err = tproxy.NewUDP(addr, tunnel) if err != nil { log.Warnln("Failed to start Redir UDP Listener: %s", err) } @@ -251,7 +251,7 @@ func ReCreateRedir(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd log.Infoln("Redirect proxy listening at: %s", redirListener.Address()) } -func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateShadowSocks(shadowSocksConfig string, tunnel C.Tunnel) { ssMux.Lock() defer ssMux.Unlock() @@ -292,7 +292,7 @@ func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, u return } - listener, err := sing_shadowsocks.New(ssConfig, tcpIn, udpIn) + listener, err := sing_shadowsocks.New(ssConfig, tunnel) if err != nil { return } @@ -305,7 +305,7 @@ func ReCreateShadowSocks(shadowSocksConfig string, tcpIn chan<- C.ConnContext, u return } -func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateVmess(vmessConfig string, tunnel C.Tunnel) { vmessMux.Lock() defer vmessMux.Unlock() @@ -344,7 +344,7 @@ func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- return } - listener, err := sing_vmess.New(vsConfig, tcpIn, udpIn) + listener, err := sing_vmess.New(vsConfig, tunnel) if err != nil { return } @@ -357,7 +357,7 @@ func ReCreateVmess(vmessConfig string, tcpIn chan<- C.ConnContext, udpIn chan<- return } -func ReCreateTuic(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateTuic(config LC.TuicServer, tunnel C.Tunnel) { tuicMux.Lock() defer func() { LastTuicConf = config @@ -389,7 +389,7 @@ func ReCreateTuic(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- return } - listener, err := tuic.New(config, tcpIn, udpIn) + listener, err := tuic.New(config, tunnel) if err != nil { return } @@ -402,7 +402,7 @@ func ReCreateTuic(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- return } -func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable) { +func ReCreateTProxy(port int, tunnel C.Tunnel) { tproxyMux.Lock() defer tproxyMux.Unlock() @@ -435,12 +435,12 @@ func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketA return } - tproxyListener, err = tproxy.New(addr, tcpIn) + tproxyListener, err = tproxy.New(addr, tunnel) if err != nil { return } - tproxyUDPListener, err = tproxy.NewUDP(addr, udpIn, natTable) + tproxyUDPListener, err = tproxy.NewUDP(addr, tunnel) if err != nil { log.Warnln("Failed to start TProxy UDP Listener: %s", err) } @@ -448,7 +448,7 @@ func ReCreateTProxy(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketA log.Infoln("TProxy server listening at: %s", tproxyListener.Address()) } -func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateMixed(port int, tunnel C.Tunnel) { mixedMux.Lock() defer mixedMux.Unlock() @@ -489,12 +489,12 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd return } - mixedListener, err = mixed.New(addr, tcpIn) + mixedListener, err = mixed.New(addr, tunnel) if err != nil { return } - mixedUDPLister, err = socks.NewUDP(addr, udpIn) + mixedUDPLister, err = socks.NewUDP(addr, tunnel) if err != nil { mixedListener.Close() return @@ -503,7 +503,7 @@ func ReCreateMixed(port int, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAd log.Infoln("Mixed(http+socks) proxy listening at: %s", mixedListener.Address()) } -func ReCreateTun(tunConf LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func ReCreateTun(tunConf LC.Tun, tunnel C.Tunnel) { tunMux.Lock() defer func() { LastTunConf = tunConf @@ -531,7 +531,7 @@ func ReCreateTun(tunConf LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.Pack return } - lister, err := sing_tun.New(tunConf, tcpIn, udpIn) + lister, err := sing_tun.New(tunConf, tunnel) if err != nil { return } @@ -573,7 +573,7 @@ func ReCreateRedirToTun(ifaceNames []string) { log.Infoln("Attached tc ebpf program to interfaces %v", tcProgram.RawNICs()) } -func ReCreateAutoRedir(ifaceNames []string, tcpIn chan<- C.ConnContext, _ chan<- C.PacketAdapter) { +func ReCreateAutoRedir(ifaceNames []string, tunnel C.Tunnel) { autoRedirMux.Lock() defer autoRedirMux.Unlock() @@ -614,7 +614,7 @@ func ReCreateAutoRedir(ifaceNames []string, tcpIn chan<- C.ConnContext, _ chan<- addr := genAddr("*", C.TcpAutoRedirPort, true) - autoRedirListener, err = autoredir.New(addr, tcpIn) + autoRedirListener, err = autoredir.New(addr, tunnel) if err != nil { return } @@ -629,7 +629,7 @@ func ReCreateAutoRedir(ifaceNames []string, tcpIn chan<- C.ConnContext, _ chan<- log.Infoln("Auto redirect proxy listening at: %s, attached tc ebpf program to interfaces %v", autoRedirListener.Address(), autoRedirProgram.RawNICs()) } -func PatchTunnel(tunnels []LC.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) { +func PatchTunnel(tunnels []LC.Tunnel, tunnel C.Tunnel) { tunnelMux.Lock() defer tunnelMux.Unlock() @@ -699,7 +699,7 @@ func PatchTunnel(tunnels []LC.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- C for _, elm := range needCreate { key := fmt.Sprintf("%s/%s/%s", elm.addr, elm.target, elm.proxy) if elm.network == "tcp" { - l, err := tunnel.New(elm.addr, elm.target, elm.proxy, tcpIn) + l, err := LT.New(elm.addr, elm.target, elm.proxy, tunnel) if err != nil { log.Errorln("Start tunnel %s error: %s", elm.target, err.Error()) continue @@ -707,7 +707,7 @@ func PatchTunnel(tunnels []LC.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- C tunnelTCPListeners[key] = l log.Infoln("Tunnel(tcp/%s) proxy %s listening at: %s", elm.target, elm.proxy, tunnelTCPListeners[key].Address()) } else { - l, err := tunnel.NewUDP(elm.addr, elm.target, elm.proxy, udpIn) + l, err := LT.NewUDP(elm.addr, elm.target, elm.proxy, tunnel) if err != nil { log.Errorln("Start tunnel %s error: %s", elm.target, err.Error()) continue @@ -718,7 +718,7 @@ func PatchTunnel(tunnels []LC.Tunnel, tcpIn chan<- C.ConnContext, udpIn chan<- C } } -func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, natTable C.NatTable, dropOld bool) { +func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tunnel C.Tunnel, dropOld bool) { inboundMux.Lock() defer inboundMux.Unlock() @@ -730,7 +730,7 @@ func PatchInboundListeners(newListenerMap map[string]C.InboundListener, tcpIn ch continue } } - if err := newListener.Listen(tcpIn, udpIn, natTable); err != nil { + if err := newListener.Listen(tunnel); err != nil { log.Errorln("Listener %s listen err: %s", name, err.Error()) continue } diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index 7241927d..d2ede096 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -36,7 +36,7 @@ func (l *Listener) Close() error { return l.listener.Close() } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-MIXED"), @@ -62,14 +62,14 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go handleConn(c, in, ml.cache, additions...) + go handleConn(c, tunnel, ml.cache, additions...) } }() return ml, nil } -func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { +func handleConn(conn net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { N.TCPKeepAlive(conn) bufConn := N.NewBufferedConn(conn) @@ -80,10 +80,10 @@ func handleConn(conn net.Conn, in chan<- C.ConnContext, cache *cache.LruCache[st switch head[0] { case socks4.Version: - socks.HandleSocks4(bufConn, in, additions...) + socks.HandleSocks4(bufConn, tunnel, additions...) case socks5.Version: - socks.HandleSocks5(bufConn, in, additions...) + socks.HandleSocks5(bufConn, tunnel, additions...) default: - http.HandleConn(bufConn, in, cache, additions...) + http.HandleConn(bufConn, tunnel, cache, additions...) } } diff --git a/listener/redir/tcp.go b/listener/redir/tcp.go index 9a843af8..6419760f 100644 --- a/listener/redir/tcp.go +++ b/listener/redir/tcp.go @@ -30,7 +30,7 @@ func (l *Listener) Close() error { return l.listener.Close() } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-REDIR"), @@ -55,18 +55,19 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go handleRedir(c, in, additions...) + go handleRedir(c, tunnel, additions...) } }() return rl, nil } -func handleRedir(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { + +func handleRedir(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { target, err := parserPacket(conn) if err != nil { conn.Close() return } N.TCPKeepAlive(conn) - in <- inbound.NewSocket(target, conn, C.REDIR, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.REDIR, additions...)) } diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index 2d0958a0..8959e6ba 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -22,7 +22,7 @@ type Listener struct { var _listener *Listener -func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter) (*Listener, error) { +func New(config LC.ShadowsocksServer, tunnel C.Tunnel) (*Listener, error) { pickCipher, err := core.PickCipher(config.Cipher, nil, config.Password) if err != nil { return nil, err @@ -36,7 +36,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C if config.Udp { //UDP - ul, err := NewUDP(addr, pickCipher, udpIn) + ul, err := NewUDP(addr, pickCipher, tunnel) if err != nil { return nil, err } @@ -60,7 +60,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C continue } N.TCPKeepAlive(c) - go sl.HandleConn(c, tcpIn) + go sl.HandleConn(c, tunnel) } }() } @@ -99,7 +99,7 @@ func (l *Listener) AddrList() (addrList []net.Addr) { return } -func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { conn = l.pickCipher.StreamConn(conn) conn = N.NewDeadlineConn(conn) // embed ss can't handle readDeadline correctly @@ -108,12 +108,12 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions _ = conn.Close() return } - in <- inbound.NewSocket(target, conn, C.SHADOWSOCKS, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.SHADOWSOCKS, additions...)) } -func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) bool { +func HandleShadowSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) bool { if _listener != nil && _listener.pickCipher != nil { - go _listener.HandleConn(conn, in, additions...) + go _listener.HandleConn(conn, tunnel, additions...) return true } return false diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index af610431..cc055853 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -17,7 +17,7 @@ type UDPListener struct { closed bool } -func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UDPListener, error) { +func NewUDP(addr string, pickCipher core.Cipher, tunnel C.Tunnel) (*UDPListener, error) { l, err := net.ListenPacket("udp", addr) if err != nil { return nil, err @@ -42,7 +42,7 @@ func NewUDP(addr string, pickCipher core.Cipher, in chan<- C.PacketAdapter) (*UD } continue } - handleSocksUDP(conn, in, data, put, remoteAddr) + handleSocksUDP(conn, tunnel, data, put, remoteAddr) } }() @@ -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, additions ...inbound.Addition) { +func handleSocksUDP(pc net.PacketConn, tunnel C.Tunnel, 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 @@ -76,8 +76,5 @@ func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, pu payload: payload, put: put, } - select { - case in <- inbound.NewPacket(target, packet, C.SHADOWSOCKS, additions...): - default: - } + tunnel.HandleUDPPacket(inbound.NewPacket(target, packet, C.SHADOWSOCKS, additions...)) } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index d5731bbf..a9bee564 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -28,43 +28,12 @@ import ( const UDPTimeout = 5 * time.Minute type ListenerHandler struct { - TcpIn chan<- C.ConnContext - UdpIn chan<- C.PacketAdapter + Tunnel C.Tunnel Type C.Type Additions []inbound.Addition UDPTimeout time.Duration } -type waitCloseConn struct { - N.ExtendedConn - wg *sync.WaitGroup - close sync.Once - rAddr net.Addr -} - -func (c *waitCloseConn) Close() error { // call from handleTCPConn(connCtx C.ConnContext) - c.close.Do(func() { - c.wg.Done() - }) - return c.ExtendedConn.Close() -} - -func (c *waitCloseConn) RemoteAddr() net.Addr { - return c.rAddr -} - -func (c *waitCloseConn) Upstream() any { - return c.ExtendedConn -} - -func (c *waitCloseConn) ReaderReplaceable() bool { - return true -} - -func (c *waitCloseConn) WriterReplaceable() bool { - return true -} - func UpstreamMetadata(metadata M.Metadata) M.Metadata { return M.Metadata{ Source: metadata.Source, @@ -117,14 +86,14 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta return h.ParseSpecialFqdn(ctx, conn, metadata) } target := socks5.ParseAddr(metadata.Destination.String()) - wg := &sync.WaitGroup{} - defer wg.Wait() // this goroutine must exit after conn.Close() - wg.Add(1) if deadline.NeedAdditionalReadDeadline(conn) { conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline } - h.TcpIn <- inbound.NewSocket(target, &waitCloseConn{ExtendedConn: N.NewExtendedConn(conn), wg: wg, rAddr: metadata.Source.TCPAddr()}, h.Type, combineAdditions(ctx, h.Additions)...) + connCtx := inbound.NewSocket(target, conn, h.Type, combineAdditions(ctx, h.Additions)...) + inbound.WithSrcAddr(metadata.Source.TCPAddr()).Apply(connCtx.Metadata()) // set srcAddr from sing's metadata + + h.Tunnel.HandleTCPConn(connCtx) // this goroutine must exit after conn unused return nil } @@ -177,10 +146,8 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. lAddr: conn.LocalAddr(), buff: buff, } - select { - case h.UdpIn <- inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...): - default: - } + + h.Tunnel.HandleUDPPacket(inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...)) } return nil } diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index 4e0a7c07..3628a2ce 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -32,7 +32,7 @@ type Listener struct { services []*hysteria2.Service[string] } -func New(config LC.Hysteria2Server, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (*Listener, error) { +func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { var sl *Listener var err error if len(additions) == 0 { @@ -43,8 +43,7 @@ func New(config LC.Hysteria2Server, tcpIn chan<- C.ConnContext, udpIn chan<- C.P } h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.HYSTERIA2, Additions: additions, } diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index d0e137a7..51baeaa1 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -35,7 +35,7 @@ type Listener struct { var _listener *Listener -func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (C.MultiAddrListener, error) { +func New(config LC.ShadowsocksServer, tunnel C.Tunnel, additions ...inbound.Addition) (C.MultiAddrListener, error) { var sl *Listener var err error if len(additions) == 0 { @@ -51,8 +51,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C udpTimeout := int64(sing.UDPTimeout.Seconds()) h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.SHADOWSOCKS, Additions: additions, } @@ -68,7 +67,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C sl.service, err = shadowaead_2022.NewServiceWithPassword(config.Cipher, config.Password, udpTimeout, h, ntp.Now) default: err = fmt.Errorf("shadowsocks: unsupported method: %s", config.Cipher) - return embedSS.New(config, tcpIn, udpIn) + return embedSS.New(config, tunnel) } if err != nil { return nil, err @@ -148,7 +147,7 @@ func New(config LC.ShadowsocksServer, tcpIn chan<- C.ConnContext, udpIn chan<- C } N.TCPKeepAlive(c) - go sl.HandleConn(c, tcpIn) + go sl.HandleConn(c, tunnel) } }() } @@ -188,7 +187,7 @@ func (l *Listener) AddrList() (addrList []net.Addr) { return } -func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { ctx := sing.WithAdditions(context.TODO(), additions...) err := l.service.NewConnection(ctx, conn, M.Metadata{ Protocol: "shadowsocks", @@ -200,10 +199,10 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions } } -func HandleShadowSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) bool { +func HandleShadowSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) bool { if _listener != nil && _listener.service != nil { - go _listener.HandleConn(conn, in, additions...) + go _listener.HandleConn(conn, tunnel, additions...) return true } - return embedSS.HandleShadowSocks(conn, in, additions...) + return embedSS.HandleShadowSocks(conn, tunnel, additions...) } diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 66fe8cd5..4ca6fc30 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -88,7 +88,7 @@ func checkTunName(tunName string) (ok bool) { return true } -func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (l *Listener, err error) { +func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Listener, err error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-TUN"), @@ -152,8 +152,7 @@ func New(options LC.Tun, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapte handler := &ListenerHandler{ ListenerHandler: sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.TUN, Additions: additions, UDPTimeout: time.Second * time.Duration(udpTimeout), diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index 06f3e051..d28213c8 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -27,7 +27,7 @@ type Listener struct { var _listener *Listener -func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (sl *Listener, err error) { +func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) (sl *Listener, err error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-VMESS"), @@ -38,8 +38,7 @@ func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packe }() } h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.VMESS, Additions: additions, } @@ -87,7 +86,7 @@ func New(config LC.VmessServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packe } N.TCPKeepAlive(c) - go sl.HandleConn(c, tcpIn) + go sl.HandleConn(c, tunnel) } }() } @@ -122,7 +121,7 @@ func (l *Listener) AddrList() (addrList []net.Addr) { return } -func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) HandleConn(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { ctx := sing.WithAdditions(context.TODO(), additions...) err := l.service.NewConnection(ctx, conn, metadata.Metadata{ Protocol: "vmess", @@ -134,9 +133,9 @@ func (l *Listener) HandleConn(conn net.Conn, in chan<- C.ConnContext, additions } } -func HandleVmess(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) bool { +func HandleVmess(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) bool { if _listener != nil && _listener.service != nil { - go _listener.HandleConn(conn, in, additions...) + go _listener.HandleConn(conn, tunnel, additions...) return true } return false diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index 2fd252a3..89b23562 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -34,7 +34,7 @@ func (l *Listener) Close() error { return l.listener.Close() } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-SOCKS"), @@ -59,14 +59,14 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go handleSocks(c, in, additions...) + go handleSocks(c, tunnel, additions...) } }() return sl, nil } -func handleSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func handleSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { N.TCPKeepAlive(conn) bufConn := N.NewBufferedConn(conn) head, err := bufConn.Peek(1) @@ -77,24 +77,24 @@ func handleSocks(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Ad switch head[0] { case socks4.Version: - HandleSocks4(bufConn, in, additions...) + HandleSocks4(bufConn, tunnel, additions...) case socks5.Version: - HandleSocks5(bufConn, in, additions...) + HandleSocks5(bufConn, tunnel, additions...) default: conn.Close() } } -func HandleSocks4(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func HandleSocks4(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { addr, _, err := socks4.ServerHandshake(conn, authStore.Authenticator()) if err != nil { conn.Close() return } - in <- inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS4, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(socks5.ParseAddr(addr), conn, C.SOCKS4, additions...)) } -func HandleSocks5(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func HandleSocks5(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator()) if err != nil { conn.Close() @@ -105,5 +105,5 @@ func HandleSocks5(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.A io.Copy(io.Discard, conn) return } - in <- inbound.NewSocket(target, conn, C.SOCKS5, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.SOCKS5, additions...)) } diff --git a/listener/socks/udp.go b/listener/socks/udp.go index 31858f74..2f786e95 100644 --- a/listener/socks/udp.go +++ b/listener/socks/udp.go @@ -33,7 +33,7 @@ func (l *UDPListener) Close() error { return l.packetConn.Close() } -func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*UDPListener, error) { +func NewUDP(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*UDPListener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-SOCKS"), @@ -66,14 +66,14 @@ func NewUDP(addr string, in chan<- C.PacketAdapter, additions ...inbound.Additio } continue } - handleSocksUDP(l, in, data, put, remoteAddr, additions...) + handleSocksUDP(l, tunnel, data, put, remoteAddr, additions...) } }() return sl, nil } -func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, put func(), addr net.Addr, additions ...inbound.Addition) { +func handleSocksUDP(pc net.PacketConn, tunnel C.Tunnel, 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 @@ -88,8 +88,5 @@ func handleSocksUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, pu payload: payload, put: put, } - select { - case in <- inbound.NewPacket(target, packet, C.SOCKS5, additions...): - default: - } + tunnel.HandleUDPPacket(inbound.NewPacket(target, packet, C.SOCKS5, additions...)) } diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index b73339a1..24fff09a 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -13,11 +13,10 @@ import ( ) type packet struct { - pc net.PacketConn - lAddr netip.AddrPort - buf []byte - in chan<- C.PacketAdapter - natTable C.NatTable + pc net.PacketConn + lAddr netip.AddrPort + buf []byte + tunnel C.Tunnel } func (c *packet) Data() []byte { @@ -26,7 +25,7 @@ func (c *packet) Data() []byte { // WriteBack opens a new socket binding `addr` to write UDP packet back func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { - tc, err := createOrGetLocalConn(addr, c.LocalAddr(), c.in, c.natTable) + tc, err := createOrGetLocalConn(addr, c.LocalAddr(), c.tunnel) if err != nil { n = 0 return @@ -52,9 +51,10 @@ func (c *packet) InAddr() net.Addr { // this function listen at rAddr and write to lAddr // for here, rAddr is the ip/port client want to access // lAddr is the ip/port client opened -func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natTable C.NatTable) (*net.UDPConn, error) { +func createOrGetLocalConn(rAddr, lAddr net.Addr, tunnel C.Tunnel) (*net.UDPConn, error) { remote := rAddr.String() local := lAddr.String() + natTable := tunnel.NatTable() localConn := natTable.GetForLocalConn(local, remote) // localConn not exist if localConn == nil { @@ -76,7 +76,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natT natTable.DeleteLockForLocalConn(local, remote) cond.Broadcast() }() - conn, err := listenLocalConn(rAddr, lAddr, in, natTable) + conn, err := listenLocalConn(rAddr, lAddr, tunnel) if err != nil { log.Errorln("listenLocalConn failed with error: %s, packet loss (rAddr[%T]=%s lAddr[%T]=%s)", err.Error(), rAddr, remote, lAddr, local) return nil, err @@ -90,7 +90,7 @@ func createOrGetLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natT // this function listen at rAddr // and send what received to program itself, then send to real remote -func listenLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natTable C.NatTable) (*net.UDPConn, error) { +func listenLocalConn(rAddr, lAddr net.Addr, tunnel C.Tunnel) (*net.UDPConn, error) { additions := []inbound.Addition{ inbound.WithInName("DEFAULT-TPROXY"), inbound.WithSpecialRules(""), @@ -113,7 +113,7 @@ func listenLocalConn(rAddr, lAddr net.Addr, in chan<- C.PacketAdapter, natTable } // since following localPackets are pass through this socket which listen rAddr // I choose current listener as packet's packet conn - handlePacketConn(lc, in, natTable, buf[:br], lAddr.(*net.UDPAddr).AddrPort(), rAddr.(*net.UDPAddr).AddrPort(), additions...) + handlePacketConn(lc, tunnel, buf[:br], lAddr.(*net.UDPAddr).AddrPort(), rAddr.(*net.UDPAddr).AddrPort(), additions...) } }() return lc, nil diff --git a/listener/tproxy/tproxy.go b/listener/tproxy/tproxy.go index 8c868609..319d5c30 100644 --- a/listener/tproxy/tproxy.go +++ b/listener/tproxy/tproxy.go @@ -31,13 +31,13 @@ func (l *Listener) Close() error { return l.listener.Close() } -func (l *Listener) handleTProxy(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) handleTProxy(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { target := socks5.ParseAddrToSocksAddr(conn.LocalAddr()) N.TCPKeepAlive(conn) - in <- inbound.NewSocket(target, conn, C.TPROXY, additions...) + tunnel.HandleTCPConn(inbound.NewSocket(target, conn, C.TPROXY, additions...)) } -func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-TPROXY"), @@ -74,7 +74,7 @@ func New(addr string, in chan<- C.ConnContext, additions ...inbound.Addition) (* } continue } - go rl.handleTProxy(c, in, additions...) + go rl.handleTProxy(c, tunnel, additions...) } }() diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go index d3727180..c8460def 100644 --- a/listener/tproxy/udp.go +++ b/listener/tproxy/udp.go @@ -32,7 +32,7 @@ func (l *UDPListener) Close() error { return l.packetConn.Close() } -func NewUDP(addr string, in chan<- C.PacketAdapter, natTable C.NatTable, additions ...inbound.Addition) (*UDPListener, error) { +func NewUDP(addr string, tunnel C.Tunnel, additions ...inbound.Addition) (*UDPListener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-TPROXY"), @@ -83,24 +83,20 @@ func NewUDP(addr string, in chan<- C.PacketAdapter, natTable C.NatTable, additio // try to unmap 4in6 address lAddr = netip.AddrPortFrom(lAddr.Addr().Unmap(), lAddr.Port()) } - handlePacketConn(l, in, natTable, buf[:n], lAddr, rAddr, additions...) + handlePacketConn(l, tunnel, buf[:n], lAddr, rAddr, additions...) } }() return rl, nil } -func handlePacketConn(pc net.PacketConn, in chan<- C.PacketAdapter, natTable C.NatTable, buf []byte, lAddr, rAddr netip.AddrPort, additions ...inbound.Addition) { +func handlePacketConn(pc net.PacketConn, tunnel C.Tunnel, buf []byte, lAddr, rAddr netip.AddrPort, additions ...inbound.Addition) { target := socks5.AddrFromStdAddrPort(rAddr) pkt := &packet{ - pc: pc, - lAddr: lAddr, - buf: buf, - in: in, - natTable: natTable, - } - select { - case in <- inbound.NewPacket(target, pkt, C.TPROXY, additions...): - default: + pc: pc, + lAddr: lAddr, + buf: buf, + tunnel: tunnel, } + tunnel.HandleUDPPacket(inbound.NewPacket(target, pkt, C.TPROXY, additions...)) } diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 125c53e1..bfead7f3 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -31,7 +31,7 @@ type Listener struct { servers []*tuic.Server } -func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.PacketAdapter, additions ...inbound.Addition) (*Listener, error) { +func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { if len(additions) == 0 { additions = []inbound.Addition{ inbound.WithInName("DEFAULT-TUIC"), @@ -39,8 +39,7 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet } } h := &sing.ListenerHandler{ - TcpIn: tcpIn, - UdpIn: udpIn, + Tunnel: tunnel, Type: C.TUIC, Additions: additions, } @@ -106,7 +105,7 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet }() return nil } - tcpIn <- connCtx + go tunnel.HandleTCPConn(connCtx) return nil } handleUdpFn := func(addr socks5.Addr, packet C.UDPPacket, _additions ...inbound.Addition) error { @@ -115,10 +114,7 @@ func New(config LC.TuicServer, tcpIn chan<- C.ConnContext, udpIn chan<- C.Packet newAdditions = slices.Clone(additions) newAdditions = append(newAdditions, _additions...) } - select { - case udpIn <- inbound.NewPacket(addr, packet, C.TUIC, newAdditions...): - default: - } + tunnel.HandleUDPPacket(inbound.NewPacket(addr, packet, C.TUIC, newAdditions...)) return nil } diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index d660d2b8..8cc527fb 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -34,14 +34,14 @@ func (l *Listener) Close() error { return l.listener.Close() } -func (l *Listener) handleTCP(conn net.Conn, in chan<- C.ConnContext, additions ...inbound.Addition) { +func (l *Listener) handleTCP(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { N.TCPKeepAlive(conn) ctx := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...) ctx.Metadata().SpecialProxy = l.proxy - in <- ctx + tunnel.HandleTCPConn(ctx) } -func New(addr, target, proxy string, in chan<- C.ConnContext, additions ...inbound.Addition) (*Listener, error) { +func New(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { l, err := inbound.Listen("tcp", addr) if err != nil { return nil, err @@ -68,7 +68,7 @@ func New(addr, target, proxy string, in chan<- C.ConnContext, additions ...inbou } continue } - go rl.handleTCP(c, in, additions...) + go rl.handleTCP(c, tunnel, additions...) } }() diff --git a/listener/tunnel/udp.go b/listener/tunnel/udp.go index 0795084c..c2f1dcc3 100644 --- a/listener/tunnel/udp.go +++ b/listener/tunnel/udp.go @@ -34,7 +34,7 @@ func (l *PacketConn) Close() error { return l.conn.Close() } -func NewUDP(addr, target, proxy string, in chan<- C.PacketAdapter, additions ...inbound.Addition) (*PacketConn, error) { +func NewUDP(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addition) (*PacketConn, error) { l, err := net.ListenPacket("udp", addr) if err != nil { return nil, err @@ -62,14 +62,14 @@ func NewUDP(addr, target, proxy string, in chan<- C.PacketAdapter, additions ... } continue } - sl.handleUDP(l, in, buf[:n], remoteAddr, additions...) + sl.handleUDP(l, tunnel, buf[:n], remoteAddr, additions...) } }() return sl, nil } -func (l *PacketConn) handleUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf []byte, addr net.Addr, additions ...inbound.Addition) { +func (l *PacketConn) handleUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, addr net.Addr, additions ...inbound.Addition) { packet := &packet{ pc: pc, rAddr: addr, @@ -78,8 +78,5 @@ func (l *PacketConn) handleUDP(pc net.PacketConn, in chan<- C.PacketAdapter, buf ctx := inbound.NewPacket(l.target, packet, C.TUNNEL, additions...) ctx.Metadata().SpecialProxy = l.proxy - select { - case in <- ctx: - default: - } + tunnel.HandleUDPPacket(ctx) } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index ff64915a..1e73a833 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -49,6 +49,25 @@ var ( fakeIPRange netip.Prefix ) +type tunnel struct{} + +var Tunnel C.Tunnel = tunnel{} + +func (t tunnel) HandleTCPConn(connCtx C.ConnContext) { + handleTCPConn(connCtx) +} + +func (t tunnel) HandleUDPPacket(packet C.PacketAdapter) { + select { + case udpQueue <- packet: + default: + } +} + +func (t tunnel) NatTable() C.NatTable { + return natTable +} + func OnSuspend() { status.Store(Suspend) } @@ -90,11 +109,13 @@ func init() { } // TCPIn return fan-in queue +// Deprecated: using Tunnel instead func TCPIn() chan<- C.ConnContext { return tcpQueue } // UDPIn return fan-in udp queue +// Deprecated: using Tunnel instead func UDPIn() chan<- C.PacketAdapter { return udpQueue } @@ -197,10 +218,6 @@ func isHandle(t C.Type) bool { func processUDP() { queue := udpQueue for conn := range queue { - if !isHandle(conn.Metadata().Type) { - conn.Drop() - continue - } handleUDPConn(conn) } } @@ -216,10 +233,6 @@ func process() { queue := tcpQueue for conn := range queue { - if !isHandle(conn.Metadata().Type) { - _ = conn.Conn().Close() - continue - } go handleTCPConn(conn) } } @@ -284,6 +297,11 @@ func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, r } func handleUDPConn(packet C.PacketAdapter) { + if !isHandle(packet.Metadata().Type) { + packet.Drop() + return + } + metadata := packet.Metadata() if !metadata.Valid() { packet.Drop() @@ -409,6 +427,11 @@ func handleUDPConn(packet C.PacketAdapter) { } func handleTCPConn(connCtx C.ConnContext) { + if !isHandle(connCtx.Metadata().Type) { + _ = connCtx.Conn().Close() + return + } + defer func(conn net.Conn) { _ = conn.Close() }(connCtx.Conn()) From c2b06a02bf8884b572955aed59303ec8e9cd821e Mon Sep 17 00:00:00 2001 From: Andrei Shevchuk Date: Fri, 29 Sep 2023 00:36:25 +0000 Subject: [PATCH 453/530] feat: add reload signal support (#780) Backport Clash feature by @septs, see Dreamacro/clash#2908 --- main.go | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/main.go b/main.go index e13b8dc8..e9f66058 100644 --- a/main.go +++ b/main.go @@ -115,7 +115,20 @@ func main() { defer executor.Shutdown() - sigCh := make(chan os.Signal, 1) - signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) - <-sigCh + termSign := make(chan os.Signal, 1) + hupSign := make(chan os.Signal, 1) + signal.Notify(termSign, syscall.SIGINT, syscall.SIGTERM) + signal.Notify(hupSign, syscall.SIGHUP) + for { + select { + case <-termSign: + return + case <-hupSign: + if cfg, err := executor.ParseWithPath(C.Path.Config()); err == nil { + executor.ApplyConfig(cfg, true) + } else { + log.Errorln("Parse config error: %s", err.Error()) + } + } + } } From 0ed3c5a5ec7df9319a797c057b5420b578e9467d Mon Sep 17 00:00:00 2001 From: septs Date: Fri, 29 Sep 2023 08:42:57 +0800 Subject: [PATCH 454/530] chore: improve subscription userinfo parsing (#781) do not use regex parsing for `Subscription-UserInfo` header field --- adapter/provider/subscription_info.go | 54 ++++++++------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/adapter/provider/subscription_info.go b/adapter/provider/subscription_info.go index fc6992e2..8b90601c 100644 --- a/adapter/provider/subscription_info.go +++ b/adapter/provider/subscription_info.go @@ -1,7 +1,6 @@ package provider import ( - "github.com/dlclark/regexp2" "strconv" "strings" ) @@ -13,45 +12,24 @@ type SubscriptionInfo struct { Expire int64 } -func NewSubscriptionInfo(str string) (si *SubscriptionInfo, err error) { - si = &SubscriptionInfo{} - str = strings.ToLower(str) - reTraffic := regexp2.MustCompile("upload=(\\d+); download=(\\d+); total=(\\d+)", 0) - reExpire := regexp2.MustCompile("expire=(\\d+)", 0) - - match, err := reTraffic.FindStringMatch(str) - if err != nil || match == nil { - return nil, err - } - group := match.Groups() - si.Upload, err = str2uint64(group[1].String()) - if err != nil { - return nil, err - } - - si.Download, err = str2uint64(group[2].String()) - if err != nil { - return nil, err - } - - si.Total, err = str2uint64(group[3].String()) - if err != nil { - return nil, err - } - - match, _ = reExpire.FindStringMatch(str) - if match != nil { - group = match.Groups() - si.Expire, err = str2uint64(group[1].String()) +func NewSubscriptionInfo(userinfo string) (si *SubscriptionInfo, err error) { + userinfo = strings.ToLower(userinfo) + userinfo = strings.ReplaceAll(userinfo, " ", "") + si = new(SubscriptionInfo) + for _, field := range strings.Split(userinfo, ";") { + switch name, value, _ := strings.Cut(field, "="); name { + case "upload": + si.Upload, err = strconv.ParseInt(value, 10, 64) + case "download": + si.Download, err = strconv.ParseInt(value, 10, 64) + case "total": + si.Total, err = strconv.ParseInt(value, 10, 64) + case "expire": + si.Expire, err = strconv.ParseInt(value, 10, 64) + } if err != nil { - return nil, err + return } } - return } - -func str2uint64(str string) (int64, error) { - i, err := strconv.ParseInt(str, 10, 64) - return i, err -} From 10e7c533d72665a352cd065250ffb4a97ef58f0d Mon Sep 17 00:00:00 2001 From: NyaMisty Date: Fri, 29 Sep 2023 08:50:50 +0800 Subject: [PATCH 455/530] feat: support clash premium's structured log stream (#735) * feat: support clash premium's structured log stream New version of Clash for Windows uses `ws://external-controller/logs?token=&level=info&format=structured` to get real time log. When Clash Premium Core reveices `format=structured`, it returns a different form of JSON log entry. Supporting this feature will allow better Clash for Windows integration Signed-off-by: Misty --- hub/route/server.go | 41 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/hub/route/server.go b/hub/route/server.go index d2fecd05..3d0df95e 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -293,6 +293,16 @@ type Log struct { Type string `json:"type"` Payload string `json:"payload"` } +type LogStructuredField struct { + Key string `json:"key"` + Value string `json:"value"` +} +type LogStructured struct { + Time string `json:"time"` + Level string `json:"level"` + Message string `json:"message"` + Fields []LogStructuredField `json:"fields"` +} func getLogs(w http.ResponseWriter, r *http.Request) { levelText := r.URL.Query().Get("level") @@ -300,6 +310,12 @@ func getLogs(w http.ResponseWriter, r *http.Request) { levelText = "info" } + formatText := r.URL.Query().Get("format") + isStructured := false + if formatText == "structured" { + isStructured = true + } + level, ok := log.LogLevelMapping[levelText] if !ok { render.Status(r, http.StatusBadRequest) @@ -342,11 +358,26 @@ func getLogs(w http.ResponseWriter, r *http.Request) { } buf.Reset() - if err := json.NewEncoder(buf).Encode(Log{ - Type: logM.Type(), - Payload: logM.Payload, - }); err != nil { - break + if !isStructured { + if err := json.NewEncoder(buf).Encode(Log{ + Type: logM.Type(), + Payload: logM.Payload, + }); err != nil { + break + } + } else { + newLevel := logM.Type() + if newLevel == "warning" { + newLevel = "warn" + } + if err := json.NewEncoder(buf).Encode(LogStructured{ + Time: time.Now().Format(time.TimeOnly), + Level: newLevel, + Message: logM.Payload, + Fields: []LogStructuredField{}, + }); err != nil { + break + } } var err error From 265a6b9b685ec01073fb63951efaea4f5a153b21 Mon Sep 17 00:00:00 2001 From: Kiva Date: Fri, 29 Sep 2023 08:51:13 +0800 Subject: [PATCH 456/530] chore: reduce string split immediately after string concat (#773) --- adapter/outbound/hysteria.go | 2 +- adapter/outbound/hysteria2.go | 2 +- adapter/outbound/shadowsocks.go | 4 ++-- adapter/outbound/singmux.go | 2 +- adapter/outbound/vmess.go | 6 +++--- transport/hysteria/core/client.go | 6 +----- 6 files changed, 9 insertions(+), 13 deletions(-) diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 8a9d6258..5a41274c 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -46,7 +46,7 @@ type Hysteria struct { } func (h *Hysteria) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { - tcpConn, err := h.client.DialTCP(metadata.RemoteAddress(), h.genHdc(ctx, opts...)) + tcpConn, err := h.client.DialTCP(metadata.String(), metadata.DstPort, h.genHdc(ctx, opts...)) if err != nil { return nil, err } diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index 57c15a12..6ed4cd8c 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -55,7 +55,7 @@ type Hysteria2Option struct { func (h *Hysteria2) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { options := h.Base.DialOptions(opts...) h.dialer.SetDialer(dialer.NewDialer(options...)) - c, err := h.client.DialConn(ctx, M.ParseSocksaddr(metadata.RemoteAddress())) + c, err := h.client.DialConn(ctx, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) if err != nil { return nil, err } diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index f744ec53..40868d04 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -123,9 +123,9 @@ func (ss *ShadowSocks) StreamConnContext(ctx context.Context, c net.Conn, metada } } if useEarly { - return ss.method.DialEarlyConn(c, M.ParseSocksaddr(metadata.RemoteAddress())), nil + return ss.method.DialEarlyConn(c, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)), nil } else { - return ss.method.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + return ss.method.DialConn(c, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) } } diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index c9f50ce9..fb6b1c29 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -42,7 +42,7 @@ type ProxyBase interface { func (s *SingMux) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (_ C.Conn, err error) { options := s.base.DialOptions(opts...) s.dialer.SetDialer(dialer.NewDialer(options...)) - c, err := s.client.DialContext(ctx, "tcp", M.ParseSocksaddr(metadata.RemoteAddress())) + c, err := s.client.DialContext(ctx, "tcp", M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) if err != nil { return nil, err } diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index db654580..326f0c6f 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -260,10 +260,10 @@ func (v *Vmess) streamConn(c net.Conn, metadata *C.Metadata) (conn net.Conn, err } else { if N.NeedHandshake(c) { conn = v.client.DialEarlyConn(c, - M.ParseSocksaddr(metadata.RemoteAddress())) + M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) } else { conn, err = v.client.DialConn(c, - M.ParseSocksaddr(metadata.RemoteAddress())) + M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) } } if err != nil { @@ -284,7 +284,7 @@ func (v *Vmess) DialContext(ctx context.Context, metadata *C.Metadata, opts ...d safeConnClose(c, err) }(c) - c, err = v.client.DialConn(c, M.ParseSocksaddr(metadata.RemoteAddress())) + c, err = v.client.DialConn(c, M.ParseSocksaddrHostPort(metadata.String(), metadata.DstPort)) if err != nil { return nil, err } diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index a219e76c..ecc8a6f1 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -194,11 +194,7 @@ func (c *Client) openStreamWithReconnect(dialer utils.PacketDialer) (quic.Connec return c.quicSession, &wrappedQUICStream{stream}, err } -func (c *Client) DialTCP(addr string, dialer utils.PacketDialer) (net.Conn, error) { - host, port, err := utils.SplitHostPort(addr) - if err != nil { - return nil, err - } +func (c *Client) DialTCP(host string, port uint16, dialer utils.PacketDialer) (net.Conn, error) { session, stream, err := c.openStreamWithReconnect(dialer) if err != nil { return nil, err From 02397868fc065fe881920959ddf02a0ffcf5c532 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 29 Sep 2023 13:26:59 +0800 Subject: [PATCH 457/530] docs: support reload in service --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 51cecc2d..bbf5cf43 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,7 @@ AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE Restart=always ExecStartPre=/usr/bin/sleep 1s ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta +ExecReload=/bin/kill -HUP $MAINPID [Install] WantedBy=multi-user.target From 5f6de610e10b818d87ea98d756213db2a3262d74 Mon Sep 17 00:00:00 2001 From: yaling888 <73897884+yaling888@users.noreply.github.com> Date: Sat, 2 Sep 2023 20:56:42 +0800 Subject: [PATCH 458/530] Fix: should check all ips need to fallback (#2915) --- dns/resolver.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/dns/resolver.go b/dns/resolver.go index 89e36214..3a530918 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -18,6 +18,7 @@ import ( "github.com/Dreamacro/clash/log" D "github.com/miekg/dns" + "github.com/samber/lo" "golang.org/x/sync/singleflight" ) @@ -200,7 +201,7 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M isIPReq := isIPRequest(q) if isIPReq { - cache=true + cache = true return r.ipExchange(ctx, m) } @@ -332,7 +333,10 @@ func (r *Resolver) ipExchange(ctx context.Context, m *D.Msg) (msg *D.Msg, err er res := <-msgCh if res.Error == nil { if ips := msgToIP(res.Msg); len(ips) != 0 { - if !r.shouldIPFallback(ips[0]) { + shouldNotFallback := lo.EveryBy(ips, func(ip netip.Addr) bool { + return !r.shouldIPFallback(ip) + }) + if shouldNotFallback { msg, err = res.Msg, res.Error // no need to wait for fallback result return } From a526bb70ea27a401419acc4b2942577705229f99 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 30 Sep 2023 13:39:50 +0800 Subject: [PATCH 459/530] chore: fix bbr bugs --- go.mod | 4 +- go.sum | 8 +- transport/hysteria/congestion/brutal.go | 4 + transport/tuic/congestion/bbr_sender.go | 178 ++++++++-------------- transport/tuic/congestion/cubic_sender.go | 4 + 5 files changed, 79 insertions(+), 119 deletions(-) diff --git a/go.mod b/go.mod index 3c26f0ae..826eb0ba 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ 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.39.1-0.20230926003849-db956da2a731 - github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 + github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55 + github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee diff --git a/go.sum b/go.sum index 584a797f..d6c96aaa 100644 --- a/go.sum +++ b/go.sum @@ -93,12 +93,12 @@ 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.39.1-0.20230926003849-db956da2a731 h1:F+xz1KCwUfCud5eWHKZr0QsWOeA+mqIFvn90r8hq+R8= -github.com/metacubex/quic-go v0.39.1-0.20230926003849-db956da2a731/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55 h1:cAqp0BFOTr/1TpFicH1dA1q/6fp7E/JkqHBORfohqr4= +github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 h1:MkYAvDyhb7cwuqL4ZLKU3Oi6tYjFnz1sz5LS82JmtDo= github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= -github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= +github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c h1:j7PKIUUhOAxJaLf/NmUKuIs9R06xNoYizwYgqf5HSrA= +github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c/go.mod h1:TPAXFCHCtzW9Dm+wq1l1R/p0v/S/xmuRU0qfPR7WlOA= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= diff --git a/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 88bf6f34..67067917 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -100,6 +100,10 @@ func (b *BrutalSender) OnCongestionEvent(number congestion.PacketNumber, lostByt b.updateAckRate(currentTimestamp) } +func (b *BrutalSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + // Stub +} + func (b *BrutalSender) SetMaxDatagramSize(size congestion.ByteCount) { b.maxDatagramSize = size b.pacer.SetMaxDatagramSize(size) diff --git a/transport/tuic/congestion/bbr_sender.go b/transport/tuic/congestion/bbr_sender.go index 2c842300..8c18c616 100644 --- a/transport/tuic/congestion/bbr_sender.go +++ b/transport/tuic/congestion/bbr_sender.go @@ -347,15 +347,36 @@ func (b *bbrSender) MaybeExitSlowStart() { } func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes congestion.ByteCount, priorInFlight congestion.ByteCount, eventTime time.Time) { + // Stub +} + +func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { + // Stub +} + +func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { totalBytesAckedBefore := b.sampler.totalBytesAcked isRoundStart, minRttExpired := false, false - lastAckedPacket := number - isRoundStart = b.UpdateRoundTripCounter(lastAckedPacket) - minRttExpired = b.UpdateBandwidthAndMinRtt(eventTime, number, ackedBytes) - b.UpdateRecoveryState(false, isRoundStart) - bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore - excessAcked := b.UpdateAckAggregationBytes(eventTime, bytesAcked) + if lostPackets != nil { + b.DiscardLostPackets(lostPackets) + } + + // Input the new data into the BBR model of the connection. + var excessAcked congestion.ByteCount + if len(ackedPackets) > 0 { + lastAckedPacket := ackedPackets[len(ackedPackets)-1].PacketNumber + isRoundStart = b.UpdateRoundTripCounter(lastAckedPacket) + minRttExpired = b.UpdateBandwidthAndMinRtt(eventTime, ackedPackets) + b.UpdateRecoveryState(len(lostPackets) > 0, isRoundStart) + bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore + excessAcked = b.UpdateAckAggregationBytes(eventTime, bytesAcked) + } + + // Handle logic specific to PROBE_BW mode. + if b.mode == PROBE_BW { + b.UpdateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) > 0) + } // Handle logic specific to STARTUP and DRAIN modes. if isRoundStart && !b.isAtFullBandwidth { @@ -366,38 +387,12 @@ func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes con // Handle logic specific to PROBE_RTT. b.MaybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired) - // After the model is updated, recalculate the pacing rate and congestion - // window. - b.CalculatePacingRate() - b.CalculateCongestionWindow(bytesAcked, excessAcked) - b.CalculateRecoveryWindow(bytesAcked, congestion.ByteCount(0)) - -} - -func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { - eventTime := time.Now() - totalBytesAckedBefore := b.sampler.totalBytesAcked - isRoundStart, minRttExpired := false, false - - b.DiscardLostPackets(number, lostBytes) - - // Input the new data into the BBR model of the connection. - var excessAcked congestion.ByteCount - - // Handle logic specific to PROBE_BW mode. - if b.mode == PROBE_BW { - b.UpdateGainCyclePhase(time.Now(), priorInFlight, true) - } - - // Handle logic specific to STARTUP and DRAIN modes. - b.MaybeExitStartupOrDrain(eventTime) - - // Handle logic specific to PROBE_RTT. - b.MaybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired) - // Calculate number of packets acked and lost. bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore - bytesLost := lostBytes + bytesLost := congestion.ByteCount(0) + for _, packet := range lostPackets { + bytesLost += packet.BytesLost + } // After the model is updated, recalculate the pacing rate and congestion // window. @@ -406,53 +401,6 @@ func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes b.CalculateRecoveryWindow(bytesAcked, bytesLost) } -//func (b *bbrSender) OnCongestionEvent(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets, lostPackets []*congestion.Packet) { -// totalBytesAckedBefore := b.sampler.totalBytesAcked -// isRoundStart, minRttExpired := false, false -// -// if lostPackets != nil { -// b.DiscardLostPackets(lostPackets) -// } -// -// // Input the new data into the BBR model of the connection. -// var excessAcked congestion.ByteCount -// if len(ackedPackets) > 0 { -// lastAckedPacket := ackedPackets[len(ackedPackets)-1].PacketNumber -// isRoundStart = b.UpdateRoundTripCounter(lastAckedPacket) -// minRttExpired = b.UpdateBandwidthAndMinRtt(eventTime, ackedPackets) -// b.UpdateRecoveryState(lastAckedPacket, len(lostPackets) > 0, isRoundStart) -// bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore -// excessAcked = b.UpdateAckAggregationBytes(eventTime, bytesAcked) -// } -// -// // Handle logic specific to PROBE_BW mode. -// if b.mode == PROBE_BW { -// b.UpdateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) > 0) -// } -// -// // Handle logic specific to STARTUP and DRAIN modes. -// if isRoundStart && !b.isAtFullBandwidth { -// b.CheckIfFullBandwidthReached() -// } -// b.MaybeExitStartupOrDrain(eventTime) -// -// // Handle logic specific to PROBE_RTT. -// b.MaybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired) -// -// // Calculate number of packets acked and lost. -// bytesAcked := b.sampler.totalBytesAcked - totalBytesAckedBefore -// bytesLost := congestion.ByteCount(0) -// for _, packet := range lostPackets { -// bytesLost += packet.Length -// } -// -// // After the model is updated, recalculate the pacing rate and congestion -// // window. -// b.CalculatePacingRate() -// b.CalculateCongestionWindow(bytesAcked, excessAcked) -// b.CalculateRecoveryWindow(bytesAcked, bytesLost) -//} - //func (b *bbrSender) SetNumEmulatedConnections(n int) { // //} @@ -553,30 +501,32 @@ func (b *bbrSender) UpdateRoundTripCounter(lastAckedPacket congestion.PacketNumb return false } -func (b *bbrSender) UpdateBandwidthAndMinRtt(now time.Time, number congestion.PacketNumber, ackedBytes congestion.ByteCount) bool { +func (b *bbrSender) UpdateBandwidthAndMinRtt(now time.Time, ackedPackets []congestion.AckedPacketInfo) bool { sampleMinRtt := InfiniteRTT - if !b.alwaysGetBwSampleWhenAcked && ackedBytes == 0 { - // Skip acked packets with 0 in flight bytes when updating bandwidth. - return false - } - bandwidthSample := b.sampler.OnPacketAcked(now, number) - if b.alwaysGetBwSampleWhenAcked && !bandwidthSample.stateAtSend.isValid { - // From the sampler's perspective, the packet has never been sent, or the - // packet has been acked or marked as lost previously. - return false - } - b.lastSampleIsAppLimited = bandwidthSample.stateAtSend.isAppLimited - // has_non_app_limited_sample_ |= - // !bandwidth_sample.state_at_send.is_app_limited; - if !bandwidthSample.stateAtSend.isAppLimited { - b.hasNoAppLimitedSample = true - } - if bandwidthSample.rtt > 0 { - sampleMinRtt = minRtt(sampleMinRtt, bandwidthSample.rtt) - } - if !bandwidthSample.stateAtSend.isAppLimited || bandwidthSample.bandwidth > b.BandwidthEstimate() { - b.maxBandwidth.Update(int64(bandwidthSample.bandwidth), b.roundTripCount) + for _, packet := range ackedPackets { + if !b.alwaysGetBwSampleWhenAcked && packet.BytesAcked == 0 { + // Skip acked packets with 0 in flight bytes when updating bandwidth. + return false + } + bandwidthSample := b.sampler.OnPacketAcked(now, packet.PacketNumber) + if b.alwaysGetBwSampleWhenAcked && !bandwidthSample.stateAtSend.isValid { + // From the sampler's perspective, the packet has never been sent, or the + // packet has been acked or marked as lost previously. + return false + } + b.lastSampleIsAppLimited = bandwidthSample.stateAtSend.isAppLimited + // has_non_app_limited_sample_ |= + // !bandwidth_sample.state_at_send.is_app_limited; + if !bandwidthSample.stateAtSend.isAppLimited { + b.hasNoAppLimitedSample = true + } + if bandwidthSample.rtt > 0 { + sampleMinRtt = minRtt(sampleMinRtt, bandwidthSample.rtt) + } + if !bandwidthSample.stateAtSend.isAppLimited || bandwidthSample.bandwidth > b.BandwidthEstimate() { + b.maxBandwidth.Update(int64(bandwidthSample.bandwidth), b.roundTripCount) + } } // If none of the RTT samples are valid, return immediately. @@ -619,14 +569,16 @@ func (b *bbrSender) ShouldExtendMinRttExpiry() bool { return false } -func (b *bbrSender) DiscardLostPackets(number congestion.PacketNumber, lostBytes congestion.ByteCount) { - b.sampler.OnCongestionEvent(number) - if b.mode == STARTUP { - // if b.rttStats != nil { - // TODO: slow start. - // } - if b.startupRateReductionMultiplier != 0 { - b.startupBytesLost += lostBytes +func (b *bbrSender) DiscardLostPackets(lostPackets []congestion.LostPacketInfo) { + for _, packet := range lostPackets { + b.sampler.OnCongestionEvent(packet.PacketNumber) + if b.mode == STARTUP { + // if b.rttStats != nil { + // TODO: slow start. + // } + if b.startupRateReductionMultiplier != 0 { + b.startupBytesLost += packet.BytesLost + } } } } diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go index e058ac7d..f544cd74 100644 --- a/transport/tuic/congestion/cubic_sender.go +++ b/transport/tuic/congestion/cubic_sender.go @@ -197,6 +197,10 @@ func (c *cubicSender) OnCongestionEvent(packetNumber congestion.PacketNumber, lo c.numAckedPackets = 0 } +func (b *cubicSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + // Stub +} + // Called when we receive an ack. Normal TCP tracks how many packets one ack // represents, but quic has a separate ack for each packet. func (c *cubicSender) maybeIncreaseCwnd( From fedad26c136adb09929c6ab807b77f7ff42efded Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 30 Sep 2023 18:26:39 +0800 Subject: [PATCH 460/530] chore: support relative path for hy2/tuic inbound cert --- listener/sing_hysteria2/server.go | 3 +++ listener/tuic/server.go | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index 3628a2ce..7897bd84 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -50,6 +50,9 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi sl = &Listener{false, config, nil, nil} + config.Certificate = C.Path.Resolve(config.Certificate) + config.PrivateKey = C.Path.Resolve(config.PrivateKey) + cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) if err != nil { return nil, err diff --git a/listener/tuic/server.go b/listener/tuic/server.go index bfead7f3..12a6ac6d 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -43,6 +43,10 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( Type: C.TUIC, Additions: additions, } + + config.Certificate = C.Path.Resolve(config.Certificate) + config.PrivateKey = C.Path.Resolve(config.PrivateKey) + cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) if err != nil { return nil, err From 828b5ad8bb8b33cc8fc256e2a7e29d350570840e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 30 Sep 2023 23:55:56 +0800 Subject: [PATCH 461/530] chore: add new bbr implementation --- transport/tuic/common/congestion.go | 29 +- transport/tuic/congestion/cubic.go | 213 ---- transport/tuic/congestion/cubic_sender.go | 297 ------ .../tuic/congestion/hybrid_slow_start.go | 112 --- transport/tuic/congestion/minmax.go | 56 -- transport/tuic/congestion_v2/bandwidth.go | 27 + .../tuic/congestion_v2/bandwidth_sampler.go | 874 +++++++++++++++++ transport/tuic/congestion_v2/bbr_sender.go | 927 ++++++++++++++++++ transport/tuic/congestion_v2/clock.go | 18 + transport/tuic/congestion_v2/minmax_go120.go | 19 + transport/tuic/congestion_v2/minmax_go121.go | 13 + transport/tuic/congestion_v2/pacer.go | 71 ++ .../packet_number_indexed_queue.go | 199 ++++ transport/tuic/congestion_v2/ringbuffer.go | 118 +++ .../tuic/congestion_v2/windowed_filter.go | 162 +++ 15 files changed, 2440 insertions(+), 695 deletions(-) delete mode 100644 transport/tuic/congestion/cubic.go delete mode 100644 transport/tuic/congestion/cubic_sender.go delete mode 100644 transport/tuic/congestion/hybrid_slow_start.go delete mode 100644 transport/tuic/congestion/minmax.go create mode 100644 transport/tuic/congestion_v2/bandwidth.go create mode 100644 transport/tuic/congestion_v2/bandwidth_sampler.go create mode 100644 transport/tuic/congestion_v2/bbr_sender.go create mode 100644 transport/tuic/congestion_v2/clock.go create mode 100644 transport/tuic/congestion_v2/minmax_go120.go create mode 100644 transport/tuic/congestion_v2/minmax_go121.go create mode 100644 transport/tuic/congestion_v2/pacer.go create mode 100644 transport/tuic/congestion_v2/packet_number_indexed_queue.go create mode 100644 transport/tuic/congestion_v2/ringbuffer.go create mode 100644 transport/tuic/congestion_v2/windowed_filter.go diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index 158f22d6..1176ebd6 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -2,6 +2,7 @@ package common import ( "github.com/Dreamacro/clash/transport/tuic/congestion" + congestionv2 "github.com/Dreamacro/clash/transport/tuic/congestion_v2" "github.com/metacubex/quic-go" c "github.com/metacubex/quic-go/congestion" @@ -17,23 +18,7 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { cwnd = 32 } switch cc { - case "cubic": - quicConn.SetCongestionControl( - congestion.NewCubicSender( - congestion.DefaultClock{}, - congestion.GetInitialPacketSize(quicConn.RemoteAddr()), - false, - ), - ) - case "new_reno": - quicConn.SetCongestionControl( - congestion.NewCubicSender( - congestion.DefaultClock{}, - congestion.GetInitialPacketSize(quicConn.RemoteAddr()), - true, - ), - ) - case "bbr": + case "bbr_meta_v1": quicConn.SetCongestionControl( congestion.NewBBRSender( congestion.DefaultClock{}, @@ -42,5 +27,15 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { congestion.DefaultBBRMaxCongestionWindow*congestion.InitialMaxDatagramSize, ), ) + case "bbr_meta_v2": + fallthrough + case "bbr": + quicConn.SetCongestionControl( + congestionv2.NewBbrSender( + congestionv2.DefaultClock{}, + congestionv2.GetInitialPacketSize(quicConn.RemoteAddr()), + c.ByteCount(cwnd), + ), + ) } } diff --git a/transport/tuic/congestion/cubic.go b/transport/tuic/congestion/cubic.go deleted file mode 100644 index dd491a32..00000000 --- a/transport/tuic/congestion/cubic.go +++ /dev/null @@ -1,213 +0,0 @@ -package congestion - -import ( - "math" - "time" - - "github.com/metacubex/quic-go/congestion" -) - -// This cubic implementation is based on the one found in Chromiums's QUIC -// implementation, in the files net/quic/congestion_control/cubic.{hh,cc}. - -// Constants based on TCP defaults. -// The following constants are in 2^10 fractions of a second instead of ms to -// allow a 10 shift right to divide. - -// 1024*1024^3 (first 1024 is from 0.100^3) -// where 0.100 is 100 ms which is the scaling round trip time. -const ( - cubeScale = 40 - cubeCongestionWindowScale = 410 - cubeFactor congestion.ByteCount = 1 << cubeScale / cubeCongestionWindowScale / maxDatagramSize - // TODO: when re-enabling cubic, make sure to use the actual packet size here - maxDatagramSize = congestion.ByteCount(InitialPacketSizeIPv4) -) - -const defaultNumConnections = 1 - -// Default Cubic backoff factor -const beta float32 = 0.7 - -// Additional backoff factor when loss occurs in the concave part of the Cubic -// curve. This additional backoff factor is expected to give up bandwidth to -// new concurrent flows and speed up convergence. -const betaLastMax float32 = 0.85 - -// Cubic implements the cubic algorithm from TCP -type Cubic struct { - clock Clock - - // Number of connections to simulate. - numConnections int - - // Time when this cycle started, after last loss event. - epoch time.Time - - // Max congestion window used just before last loss event. - // Note: to improve fairness to other streams an additional back off is - // applied to this value if the new value is below our latest value. - lastMaxCongestionWindow congestion.ByteCount - - // Number of acked bytes since the cycle started (epoch). - ackedBytesCount congestion.ByteCount - - // TCP Reno equivalent congestion window in packets. - estimatedTCPcongestionWindow congestion.ByteCount - - // Origin point of cubic function. - originPointCongestionWindow congestion.ByteCount - - // Time to origin point of cubic function in 2^10 fractions of a second. - timeToOriginPoint uint32 - - // Last congestion window in packets computed by cubic function. - lastTargetCongestionWindow congestion.ByteCount -} - -// NewCubic returns a new Cubic instance -func NewCubic(clock Clock) *Cubic { - c := &Cubic{ - clock: clock, - numConnections: defaultNumConnections, - } - c.Reset() - return c -} - -// Reset is called after a timeout to reset the cubic state -func (c *Cubic) Reset() { - c.epoch = time.Time{} - c.lastMaxCongestionWindow = 0 - c.ackedBytesCount = 0 - c.estimatedTCPcongestionWindow = 0 - c.originPointCongestionWindow = 0 - c.timeToOriginPoint = 0 - c.lastTargetCongestionWindow = 0 -} - -func (c *Cubic) alpha() float32 { - // TCPFriendly alpha is described in Section 3.3 of the CUBIC paper. Note that - // beta here is a cwnd multiplier, and is equal to 1-beta from the paper. - // We derive the equivalent alpha for an N-connection emulation as: - b := c.beta() - return 3 * float32(c.numConnections) * float32(c.numConnections) * (1 - b) / (1 + b) -} - -func (c *Cubic) beta() float32 { - // kNConnectionBeta is the backoff factor after loss for our N-connection - // emulation, which emulates the effective backoff of an ensemble of N - // TCP-Reno connections on a single loss event. The effective multiplier is - // computed as: - return (float32(c.numConnections) - 1 + beta) / float32(c.numConnections) -} - -func (c *Cubic) betaLastMax() float32 { - // betaLastMax is the additional backoff factor after loss for our - // N-connection emulation, which emulates the additional backoff of - // an ensemble of N TCP-Reno connections on a single loss event. The - // effective multiplier is computed as: - return (float32(c.numConnections) - 1 + betaLastMax) / float32(c.numConnections) -} - -// OnApplicationLimited is called on ack arrival when sender is unable to use -// the available congestion window. Resets Cubic state during quiescence. -func (c *Cubic) OnApplicationLimited() { - // When sender is not using the available congestion window, the window does - // not grow. But to be RTT-independent, Cubic assumes that the sender has been - // using the entire window during the time since the beginning of the current - // "epoch" (the end of the last loss recovery period). Since - // application-limited periods break this assumption, we reset the epoch when - // in such a period. This reset effectively freezes congestion window growth - // through application-limited periods and allows Cubic growth to continue - // when the entire window is being used. - c.epoch = time.Time{} -} - -// CongestionWindowAfterPacketLoss computes a new congestion window to use after -// a loss event. Returns the new congestion window in packets. The new -// congestion window is a multiplicative decrease of our current window. -func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow congestion.ByteCount) congestion.ByteCount { - if currentCongestionWindow+maxDatagramSize < c.lastMaxCongestionWindow { - // We never reached the old max, so assume we are competing with another - // flow. Use our extra back off factor to allow the other flow to go up. - c.lastMaxCongestionWindow = congestion.ByteCount(c.betaLastMax() * float32(currentCongestionWindow)) - } else { - c.lastMaxCongestionWindow = currentCongestionWindow - } - c.epoch = time.Time{} // Reset time. - return congestion.ByteCount(float32(currentCongestionWindow) * c.beta()) -} - -// CongestionWindowAfterAck computes a new congestion window to use after a received ACK. -// Returns the new congestion window in packets. The new congestion window -// follows a cubic function that depends on the time passed since last -// packet loss. -func (c *Cubic) CongestionWindowAfterAck( - ackedBytes congestion.ByteCount, - currentCongestionWindow congestion.ByteCount, - delayMin time.Duration, - eventTime time.Time, -) congestion.ByteCount { - c.ackedBytesCount += ackedBytes - - if c.epoch.IsZero() { - // First ACK after a loss event. - c.epoch = eventTime // Start of epoch. - c.ackedBytesCount = ackedBytes // Reset count. - // Reset estimated_tcp_congestion_window_ to be in sync with cubic. - c.estimatedTCPcongestionWindow = currentCongestionWindow - if c.lastMaxCongestionWindow <= currentCongestionWindow { - c.timeToOriginPoint = 0 - c.originPointCongestionWindow = currentCongestionWindow - } else { - c.timeToOriginPoint = uint32(math.Cbrt(float64(cubeFactor * (c.lastMaxCongestionWindow - currentCongestionWindow)))) - c.originPointCongestionWindow = c.lastMaxCongestionWindow - } - } - - // Change the time unit from microseconds to 2^10 fractions per second. Take - // the round trip time in account. This is done to allow us to use shift as a - // divide operator. - elapsedTime := int64(eventTime.Add(delayMin).Sub(c.epoch)/time.Microsecond) << 10 / (1000 * 1000) - - // Right-shifts of negative, signed numbers have implementation-dependent - // behavior, so force the offset to be positive, as is done in the kernel. - offset := int64(c.timeToOriginPoint) - elapsedTime - if offset < 0 { - offset = -offset - } - - deltaCongestionWindow := congestion.ByteCount(cubeCongestionWindowScale*offset*offset*offset) * maxDatagramSize >> cubeScale - var targetCongestionWindow congestion.ByteCount - if elapsedTime > int64(c.timeToOriginPoint) { - targetCongestionWindow = c.originPointCongestionWindow + deltaCongestionWindow - } else { - targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow - } - // Limit the CWND increase to half the acked bytes. - targetCongestionWindow = Min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) - - // Increase the window by approximately Alpha * 1 MSS of bytes every - // time we ack an estimated tcp window of bytes. For small - // congestion windows (less than 25), the formula below will - // increase slightly slower than linearly per estimated tcp window - // of bytes. - c.estimatedTCPcongestionWindow += congestion.ByteCount(float32(c.ackedBytesCount) * c.alpha() * float32(maxDatagramSize) / float32(c.estimatedTCPcongestionWindow)) - c.ackedBytesCount = 0 - - // We have a new cubic congestion window. - c.lastTargetCongestionWindow = targetCongestionWindow - - // Compute target congestion_window based on cubic target and estimated TCP - // congestion_window, use highest (fastest). - if targetCongestionWindow < c.estimatedTCPcongestionWindow { - targetCongestionWindow = c.estimatedTCPcongestionWindow - } - return targetCongestionWindow -} - -// SetNumConnections sets the number of emulated connections -func (c *Cubic) SetNumConnections(n int) { - c.numConnections = n -} diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go deleted file mode 100644 index f544cd74..00000000 --- a/transport/tuic/congestion/cubic_sender.go +++ /dev/null @@ -1,297 +0,0 @@ -package congestion - -import ( - "fmt" - "time" - - "github.com/metacubex/quic-go/congestion" -) - -const ( - maxBurstPackets = 3 - renoBeta = 0.7 // Reno backoff factor. - minCongestionWindowPackets = 2 - initialCongestionWindow = 32 -) - -const InvalidPacketNumber congestion.PacketNumber = -1 -const MaxCongestionWindowPackets = 20000 -const MaxByteCount = congestion.ByteCount(1<<62 - 1) - -type cubicSender struct { - hybridSlowStart HybridSlowStart - rttStats congestion.RTTStatsProvider - cubic *Cubic - pacer *pacer - clock Clock - - reno bool - - // Track the largest packet that has been sent. - largestSentPacketNumber congestion.PacketNumber - - // Track the largest packet that has been acked. - largestAckedPacketNumber congestion.PacketNumber - - // Track the largest packet number outstanding when a CWND cutback occurs. - largestSentAtLastCutback congestion.PacketNumber - - // Whether the last loss event caused us to exit slowstart. - // Used for stats collection of slowstartPacketsLost - lastCutbackExitedSlowstart bool - - // Congestion window in bytes. - congestionWindow congestion.ByteCount - - // Slow start congestion window in bytes, aka ssthresh. - slowStartThreshold congestion.ByteCount - - // ACK counter for the Reno implementation. - numAckedPackets uint64 - - initialCongestionWindow congestion.ByteCount - initialMaxCongestionWindow congestion.ByteCount - - maxDatagramSize congestion.ByteCount -} - -var ( - _ congestion.CongestionControl = &cubicSender{} -) - -// NewCubicSender makes a new cubic sender -func NewCubicSender( - clock Clock, - initialMaxDatagramSize congestion.ByteCount, - reno bool, -) *cubicSender { - return newCubicSender( - clock, - reno, - initialMaxDatagramSize, - initialCongestionWindow*initialMaxDatagramSize, - MaxCongestionWindowPackets*initialMaxDatagramSize, - ) -} - -func newCubicSender( - clock Clock, - reno bool, - initialMaxDatagramSize, - initialCongestionWindow, - initialMaxCongestionWindow congestion.ByteCount, -) *cubicSender { - c := &cubicSender{ - largestSentPacketNumber: InvalidPacketNumber, - largestAckedPacketNumber: InvalidPacketNumber, - largestSentAtLastCutback: InvalidPacketNumber, - initialCongestionWindow: initialCongestionWindow, - initialMaxCongestionWindow: initialMaxCongestionWindow, - congestionWindow: initialCongestionWindow, - slowStartThreshold: MaxByteCount, - cubic: NewCubic(clock), - clock: clock, - reno: reno, - maxDatagramSize: initialMaxDatagramSize, - } - c.pacer = newPacer(c.BandwidthEstimate) - return c -} - -func (c *cubicSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { - c.rttStats = provider -} - -// TimeUntilSend returns when the next packet should be sent. -func (c *cubicSender) TimeUntilSend(_ congestion.ByteCount) time.Time { - return c.pacer.TimeUntilSend() -} - -func (c *cubicSender) HasPacingBudget(now time.Time) bool { - return c.pacer.Budget(now) >= c.maxDatagramSize -} - -func (c *cubicSender) maxCongestionWindow() congestion.ByteCount { - return c.maxDatagramSize * MaxCongestionWindowPackets -} - -func (c *cubicSender) minCongestionWindow() congestion.ByteCount { - return c.maxDatagramSize * minCongestionWindowPackets -} - -func (c *cubicSender) OnPacketSent( - sentTime time.Time, - _ congestion.ByteCount, - packetNumber congestion.PacketNumber, - bytes congestion.ByteCount, - isRetransmittable bool, -) { - c.pacer.SentPacket(sentTime, bytes) - if !isRetransmittable { - return - } - c.largestSentPacketNumber = packetNumber - c.hybridSlowStart.OnPacketSent(packetNumber) -} - -func (c *cubicSender) CanSend(bytesInFlight congestion.ByteCount) bool { - return bytesInFlight < c.GetCongestionWindow() -} - -func (c *cubicSender) InRecovery() bool { - return c.largestAckedPacketNumber != InvalidPacketNumber && c.largestAckedPacketNumber <= c.largestSentAtLastCutback -} - -func (c *cubicSender) InSlowStart() bool { - return c.GetCongestionWindow() < c.slowStartThreshold -} - -func (c *cubicSender) GetCongestionWindow() congestion.ByteCount { - return c.congestionWindow -} - -func (c *cubicSender) MaybeExitSlowStart() { - if c.InSlowStart() && - c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/c.maxDatagramSize) { - // exit slow start - c.slowStartThreshold = c.congestionWindow - } -} - -func (c *cubicSender) OnPacketAcked( - ackedPacketNumber congestion.PacketNumber, - ackedBytes congestion.ByteCount, - priorInFlight congestion.ByteCount, - eventTime time.Time, -) { - c.largestAckedPacketNumber = Max(ackedPacketNumber, c.largestAckedPacketNumber) - if c.InRecovery() { - return - } - c.maybeIncreaseCwnd(ackedPacketNumber, ackedBytes, priorInFlight, eventTime) - if c.InSlowStart() { - c.hybridSlowStart.OnPacketAcked(ackedPacketNumber) - } -} - -func (c *cubicSender) OnCongestionEvent(packetNumber congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { - // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets - // already sent should be treated as a single loss event, since it's expected. - if packetNumber <= c.largestSentAtLastCutback { - return - } - c.lastCutbackExitedSlowstart = c.InSlowStart() - - if c.reno { - c.congestionWindow = congestion.ByteCount(float64(c.congestionWindow) * renoBeta) - } else { - c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow) - } - if minCwnd := c.minCongestionWindow(); c.congestionWindow < minCwnd { - c.congestionWindow = minCwnd - } - c.slowStartThreshold = c.congestionWindow - c.largestSentAtLastCutback = c.largestSentPacketNumber - // reset packet count from congestion avoidance mode. We start - // counting again when we're out of recovery. - c.numAckedPackets = 0 -} - -func (b *cubicSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { - // Stub -} - -// Called when we receive an ack. Normal TCP tracks how many packets one ack -// represents, but quic has a separate ack for each packet. -func (c *cubicSender) maybeIncreaseCwnd( - _ congestion.PacketNumber, - ackedBytes congestion.ByteCount, - priorInFlight congestion.ByteCount, - eventTime time.Time, -) { - // Do not increase the congestion window unless the sender is close to using - // the current window. - if !c.isCwndLimited(priorInFlight) { - c.cubic.OnApplicationLimited() - return - } - if c.congestionWindow >= c.maxCongestionWindow() { - return - } - if c.InSlowStart() { - // TCP slow start, exponential growth, increase by one for each ACK. - c.congestionWindow += c.maxDatagramSize - return - } - // Congestion avoidance - if c.reno { - // Classic Reno congestion avoidance. - c.numAckedPackets++ - if c.numAckedPackets >= uint64(c.congestionWindow/c.maxDatagramSize) { - c.congestionWindow += c.maxDatagramSize - c.numAckedPackets = 0 - } - } else { - c.congestionWindow = Min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) - } -} - -func (c *cubicSender) isCwndLimited(bytesInFlight congestion.ByteCount) bool { - congestionWindow := c.GetCongestionWindow() - if bytesInFlight >= congestionWindow { - return true - } - availableBytes := congestionWindow - bytesInFlight - slowStartLimited := c.InSlowStart() && bytesInFlight > congestionWindow/2 - return slowStartLimited || availableBytes <= maxBurstPackets*c.maxDatagramSize -} - -// BandwidthEstimate returns the current bandwidth estimate -func (c *cubicSender) BandwidthEstimate() Bandwidth { - if c.rttStats == nil { - return infBandwidth - } - srtt := c.rttStats.SmoothedRTT() - if srtt == 0 { - // If we haven't measured an rtt, the bandwidth estimate is unknown. - return infBandwidth - } - return BandwidthFromDelta(c.GetCongestionWindow(), srtt) -} - -// OnRetransmissionTimeout is called on an retransmission timeout -func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) { - c.largestSentAtLastCutback = InvalidPacketNumber - if !packetsRetransmitted { - return - } - c.hybridSlowStart.Restart() - c.cubic.Reset() - c.slowStartThreshold = c.congestionWindow / 2 - c.congestionWindow = c.minCongestionWindow() -} - -// OnConnectionMigration is called when the connection is migrated (?) -func (c *cubicSender) OnConnectionMigration() { - c.hybridSlowStart.Restart() - c.largestSentPacketNumber = InvalidPacketNumber - c.largestAckedPacketNumber = InvalidPacketNumber - c.largestSentAtLastCutback = InvalidPacketNumber - c.lastCutbackExitedSlowstart = false - c.cubic.Reset() - c.numAckedPackets = 0 - c.congestionWindow = c.initialCongestionWindow - c.slowStartThreshold = c.initialMaxCongestionWindow -} - -func (c *cubicSender) SetMaxDatagramSize(s congestion.ByteCount) { - if s < c.maxDatagramSize { - panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", c.maxDatagramSize, s)) - } - cwndIsMinCwnd := c.congestionWindow == c.minCongestionWindow() - c.maxDatagramSize = s - if cwndIsMinCwnd { - c.congestionWindow = c.minCongestionWindow() - } - c.pacer.SetMaxDatagramSize(s) -} diff --git a/transport/tuic/congestion/hybrid_slow_start.go b/transport/tuic/congestion/hybrid_slow_start.go deleted file mode 100644 index 7586774e..00000000 --- a/transport/tuic/congestion/hybrid_slow_start.go +++ /dev/null @@ -1,112 +0,0 @@ -package congestion - -import ( - "time" - - "github.com/metacubex/quic-go/congestion" -) - -// Note(pwestin): the magic clamping numbers come from the original code in -// tcp_cubic.c. -const hybridStartLowWindow = congestion.ByteCount(16) - -// Number of delay samples for detecting the increase of delay. -const hybridStartMinSamples = uint32(8) - -// Exit slow start if the min rtt has increased by more than 1/8th. -const hybridStartDelayFactorExp = 3 // 2^3 = 8 -// The original paper specifies 2 and 8ms, but those have changed over time. -const ( - hybridStartDelayMinThresholdUs = int64(4000) - hybridStartDelayMaxThresholdUs = int64(16000) -) - -// HybridSlowStart implements the TCP hybrid slow start algorithm -type HybridSlowStart struct { - endPacketNumber congestion.PacketNumber - lastSentPacketNumber congestion.PacketNumber - started bool - currentMinRTT time.Duration - rttSampleCount uint32 - hystartFound bool -} - -// StartReceiveRound is called for the start of each receive round (burst) in the slow start phase. -func (s *HybridSlowStart) StartReceiveRound(lastSent congestion.PacketNumber) { - s.endPacketNumber = lastSent - s.currentMinRTT = 0 - s.rttSampleCount = 0 - s.started = true -} - -// IsEndOfRound returns true if this ack is the last packet number of our current slow start round. -func (s *HybridSlowStart) IsEndOfRound(ack congestion.PacketNumber) bool { - return s.endPacketNumber < ack -} - -// ShouldExitSlowStart should be called on every new ack frame, since a new -// RTT measurement can be made then. -// rtt: the RTT for this ack packet. -// minRTT: is the lowest delay (RTT) we have seen during the session. -// congestionWindow: the congestion window in packets. -func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT time.Duration, congestionWindow congestion.ByteCount) bool { - if !s.started { - // Time to start the hybrid slow start. - s.StartReceiveRound(s.lastSentPacketNumber) - } - if s.hystartFound { - return true - } - // Second detection parameter - delay increase detection. - // Compare the minimum delay (s.currentMinRTT) of the current - // burst of packets relative to the minimum delay during the session. - // Note: we only look at the first few(8) packets in each burst, since we - // only want to compare the lowest RTT of the burst relative to previous - // bursts. - s.rttSampleCount++ - if s.rttSampleCount <= hybridStartMinSamples { - if s.currentMinRTT == 0 || s.currentMinRTT > latestRTT { - s.currentMinRTT = latestRTT - } - } - // We only need to check this once per round. - if s.rttSampleCount == hybridStartMinSamples { - // Divide minRTT by 8 to get a rtt increase threshold for exiting. - minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp) - // Ensure the rtt threshold is never less than 2ms or more than 16ms. - minRTTincreaseThresholdUs = Min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) - minRTTincreaseThreshold := time.Duration(Max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond - - if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) { - s.hystartFound = true - } - } - // Exit from slow start if the cwnd is greater than 16 and - // increasing delay is found. - return congestionWindow >= hybridStartLowWindow && s.hystartFound -} - -// OnPacketSent is called when a packet was sent -func (s *HybridSlowStart) OnPacketSent(packetNumber congestion.PacketNumber) { - s.lastSentPacketNumber = packetNumber -} - -// OnPacketAcked gets invoked after ShouldExitSlowStart, so it's best to end -// the round when the final packet of the burst is received and start it on -// the next incoming ack. -func (s *HybridSlowStart) OnPacketAcked(ackedPacketNumber congestion.PacketNumber) { - if s.IsEndOfRound(ackedPacketNumber) { - s.started = false - } -} - -// Started returns true if started -func (s *HybridSlowStart) Started() bool { - return s.started -} - -// Restart the slow start phase -func (s *HybridSlowStart) Restart() { - s.started = false - s.hystartFound = false -} diff --git a/transport/tuic/congestion/minmax.go b/transport/tuic/congestion/minmax.go deleted file mode 100644 index 0a8f4ad4..00000000 --- a/transport/tuic/congestion/minmax.go +++ /dev/null @@ -1,56 +0,0 @@ -package congestion - -import ( - "math" - "time" -) - -// InfDuration is a duration of infinite length -const InfDuration = time.Duration(math.MaxInt64) - -// MinNonZeroDuration return the minimum duration that's not zero. -func MinNonZeroDuration(a, b time.Duration) time.Duration { - if a == 0 { - return b - } - if b == 0 { - return a - } - return Min(a, b) -} - -// AbsDuration returns the absolute value of a time duration -func AbsDuration(d time.Duration) time.Duration { - if d >= 0 { - return d - } - return -d -} - -// MinTime returns the earlier time -func MinTime(a, b time.Time) time.Time { - if a.After(b) { - return b - } - return a -} - -// MinNonZeroTime returns the earlist time that is not time.Time{} -// If both a and b are time.Time{}, it returns time.Time{} -func MinNonZeroTime(a, b time.Time) time.Time { - if a.IsZero() { - return b - } - if b.IsZero() { - return a - } - return MinTime(a, b) -} - -// MaxTime returns the later time -func MaxTime(a, b time.Time) time.Time { - if a.After(b) { - return a - } - return b -} diff --git a/transport/tuic/congestion_v2/bandwidth.go b/transport/tuic/congestion_v2/bandwidth.go new file mode 100644 index 00000000..df39a077 --- /dev/null +++ b/transport/tuic/congestion_v2/bandwidth.go @@ -0,0 +1,27 @@ +package congestion + +import ( + "math" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +const ( + infBandwidth = Bandwidth(math.MaxUint64) +) + +// Bandwidth of a connection +type Bandwidth uint64 + +const ( + // BitsPerSecond is 1 bit per second + BitsPerSecond Bandwidth = 1 + // BytesPerSecond is 1 byte per second + BytesPerSecond = 8 * BitsPerSecond +) + +// BandwidthFromDelta calculates the bandwidth from a number of bytes and a time delta +func BandwidthFromDelta(bytes congestion.ByteCount, delta time.Duration) Bandwidth { + return Bandwidth(bytes) * Bandwidth(time.Second) / Bandwidth(delta) * BytesPerSecond +} diff --git a/transport/tuic/congestion_v2/bandwidth_sampler.go b/transport/tuic/congestion_v2/bandwidth_sampler.go new file mode 100644 index 00000000..9028df64 --- /dev/null +++ b/transport/tuic/congestion_v2/bandwidth_sampler.go @@ -0,0 +1,874 @@ +package congestion + +import ( + "math" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +const ( + infRTT = time.Duration(math.MaxInt64) + defaultConnectionStateMapQueueSize = 256 + defaultCandidatesBufferSize = 256 +) + +type roundTripCount uint64 + +// SendTimeState is a subset of ConnectionStateOnSentPacket which is returned +// to the caller when the packet is acked or lost. +type sendTimeState struct { + // Whether other states in this object is valid. + isValid bool + // Whether the sender is app limited at the time the packet was sent. + // App limited bandwidth sample might be artificially low because the sender + // did not have enough data to send in order to saturate the link. + isAppLimited bool + // Total number of sent bytes at the time the packet was sent. + // Includes the packet itself. + totalBytesSent congestion.ByteCount + // Total number of acked bytes at the time the packet was sent. + totalBytesAcked congestion.ByteCount + // Total number of lost bytes at the time the packet was sent. + totalBytesLost congestion.ByteCount + // Total number of inflight bytes at the time the packet was sent. + // Includes the packet itself. + // It should be equal to |total_bytes_sent| minus the sum of + // |total_bytes_acked|, |total_bytes_lost| and total neutered bytes. + bytesInFlight congestion.ByteCount +} + +func newSendTimeState( + isAppLimited bool, + totalBytesSent congestion.ByteCount, + totalBytesAcked congestion.ByteCount, + totalBytesLost congestion.ByteCount, + bytesInFlight congestion.ByteCount, +) *sendTimeState { + return &sendTimeState{ + isValid: true, + isAppLimited: isAppLimited, + totalBytesSent: totalBytesSent, + totalBytesAcked: totalBytesAcked, + totalBytesLost: totalBytesLost, + bytesInFlight: bytesInFlight, + } +} + +type extraAckedEvent struct { + // The excess bytes acknowlwedged in the time delta for this event. + extraAcked congestion.ByteCount + + // The bytes acknowledged and time delta from the event. + bytesAcked congestion.ByteCount + timeDelta time.Duration + // The round trip of the event. + round roundTripCount +} + +func maxExtraAckedEventFunc(a, b extraAckedEvent) int { + if a.extraAcked > b.extraAcked { + return 1 + } else if a.extraAcked < b.extraAcked { + return -1 + } + return 0 +} + +// BandwidthSample +type bandwidthSample struct { + // The bandwidth at that particular sample. Zero if no valid bandwidth sample + // is available. + bandwidth Bandwidth + // The RTT measurement at this particular sample. Zero if no RTT sample is + // available. Does not correct for delayed ack time. + rtt time.Duration + // |send_rate| is computed from the current packet being acked('P') and an + // earlier packet that is acked before P was sent. + sendRate Bandwidth + // States captured when the packet was sent. + stateAtSend sendTimeState +} + +func newBandwidthSample() *bandwidthSample { + return &bandwidthSample{ + sendRate: infBandwidth, + } +} + +// MaxAckHeightTracker is part of the BandwidthSampler. It is called after every +// ack event to keep track the degree of ack aggregation(a.k.a "ack height"). +type maxAckHeightTracker struct { + // Tracks the maximum number of bytes acked faster than the estimated + // bandwidth. + maxAckHeightFilter *WindowedFilter[extraAckedEvent, roundTripCount] + // The time this aggregation started and the number of bytes acked during it. + aggregationEpochStartTime time.Time + aggregationEpochBytes congestion.ByteCount + // The last sent packet number before the current aggregation epoch started. + lastSentPacketNumberBeforeEpoch congestion.PacketNumber + // The number of ack aggregation epochs ever started, including the ongoing + // one. Stats only. + numAckAggregationEpochs uint64 + ackAggregationBandwidthThreshold float64 + startNewAggregationEpochAfterFullRound bool + reduceExtraAckedOnBandwidthIncrease bool +} + +func newMaxAckHeightTracker(windowLength roundTripCount) *maxAckHeightTracker { + return &maxAckHeightTracker{ + maxAckHeightFilter: NewWindowedFilter(windowLength, maxExtraAckedEventFunc), + lastSentPacketNumberBeforeEpoch: invalidPacketNumber, + ackAggregationBandwidthThreshold: 1.0, + } +} + +func (m *maxAckHeightTracker) Get() congestion.ByteCount { + return m.maxAckHeightFilter.GetBest().extraAcked +} + +func (m *maxAckHeightTracker) Update( + bandwidthEstimate Bandwidth, + isNewMaxBandwidth bool, + roundTripCount roundTripCount, + lastSentPacketNumber congestion.PacketNumber, + lastAckedPacketNumber congestion.PacketNumber, + ackTime time.Time, + bytesAcked congestion.ByteCount, +) congestion.ByteCount { + forceNewEpoch := false + + if m.reduceExtraAckedOnBandwidthIncrease && isNewMaxBandwidth { + // Save and clear existing entries. + best := m.maxAckHeightFilter.GetBest() + secondBest := m.maxAckHeightFilter.GetSecondBest() + thirdBest := m.maxAckHeightFilter.GetThirdBest() + m.maxAckHeightFilter.Clear() + + // Reinsert the heights into the filter after recalculating. + expectedBytesAcked := bytesFromBandwidthAndTimeDelta(bandwidthEstimate, best.timeDelta) + if expectedBytesAcked < best.bytesAcked { + best.extraAcked = best.bytesAcked - expectedBytesAcked + m.maxAckHeightFilter.Update(best, best.round) + } + expectedBytesAcked = bytesFromBandwidthAndTimeDelta(bandwidthEstimate, secondBest.timeDelta) + if expectedBytesAcked < secondBest.bytesAcked { + secondBest.extraAcked = secondBest.bytesAcked - expectedBytesAcked + m.maxAckHeightFilter.Update(secondBest, secondBest.round) + } + expectedBytesAcked = bytesFromBandwidthAndTimeDelta(bandwidthEstimate, thirdBest.timeDelta) + if expectedBytesAcked < thirdBest.bytesAcked { + thirdBest.extraAcked = thirdBest.bytesAcked - expectedBytesAcked + m.maxAckHeightFilter.Update(thirdBest, thirdBest.round) + } + } + + // If any packet sent after the start of the epoch has been acked, start a new + // epoch. + if m.startNewAggregationEpochAfterFullRound && + m.lastSentPacketNumberBeforeEpoch != invalidPacketNumber && + lastAckedPacketNumber != invalidPacketNumber && + lastAckedPacketNumber > m.lastSentPacketNumberBeforeEpoch { + forceNewEpoch = true + } + if m.aggregationEpochStartTime.IsZero() || forceNewEpoch { + m.aggregationEpochBytes = bytesAcked + m.aggregationEpochStartTime = ackTime + m.lastSentPacketNumberBeforeEpoch = lastSentPacketNumber + m.numAckAggregationEpochs++ + return 0 + } + + // Compute how many bytes are expected to be delivered, assuming max bandwidth + // is correct. + aggregationDelta := ackTime.Sub(m.aggregationEpochStartTime) + expectedBytesAcked := bytesFromBandwidthAndTimeDelta(bandwidthEstimate, aggregationDelta) + // Reset the current aggregation epoch as soon as the ack arrival rate is less + // than or equal to the max bandwidth. + if m.aggregationEpochBytes <= congestion.ByteCount(m.ackAggregationBandwidthThreshold*float64(expectedBytesAcked)) { + // Reset to start measuring a new aggregation epoch. + m.aggregationEpochBytes = bytesAcked + m.aggregationEpochStartTime = ackTime + m.lastSentPacketNumberBeforeEpoch = lastSentPacketNumber + m.numAckAggregationEpochs++ + return 0 + } + + m.aggregationEpochBytes += bytesAcked + + // Compute how many extra bytes were delivered vs max bandwidth. + extraBytesAcked := m.aggregationEpochBytes - expectedBytesAcked + newEvent := extraAckedEvent{ + extraAcked: expectedBytesAcked, + bytesAcked: m.aggregationEpochBytes, + timeDelta: aggregationDelta, + } + m.maxAckHeightFilter.Update(newEvent, roundTripCount) + return extraBytesAcked +} + +func (m *maxAckHeightTracker) SetFilterWindowLength(length roundTripCount) { + m.maxAckHeightFilter.SetWindowLength(length) +} + +func (m *maxAckHeightTracker) Reset(newHeight congestion.ByteCount, newTime roundTripCount) { + newEvent := extraAckedEvent{ + extraAcked: newHeight, + round: newTime, + } + m.maxAckHeightFilter.Reset(newEvent, newTime) +} + +func (m *maxAckHeightTracker) SetAckAggregationBandwidthThreshold(threshold float64) { + m.ackAggregationBandwidthThreshold = threshold +} + +func (m *maxAckHeightTracker) SetStartNewAggregationEpochAfterFullRound(value bool) { + m.startNewAggregationEpochAfterFullRound = value +} + +func (m *maxAckHeightTracker) SetReduceExtraAckedOnBandwidthIncrease(value bool) { + m.reduceExtraAckedOnBandwidthIncrease = value +} + +func (m *maxAckHeightTracker) AckAggregationBandwidthThreshold() float64 { + return m.ackAggregationBandwidthThreshold +} + +func (m *maxAckHeightTracker) NumAckAggregationEpochs() uint64 { + return m.numAckAggregationEpochs +} + +// AckPoint represents a point on the ack line. +type ackPoint struct { + ackTime time.Time + totalBytesAcked congestion.ByteCount +} + +// RecentAckPoints maintains the most recent 2 ack points at distinct times. +type recentAckPoints struct { + ackPoints [2]ackPoint +} + +func (r *recentAckPoints) Update(ackTime time.Time, totalBytesAcked congestion.ByteCount) { + if ackTime.Before(r.ackPoints[1].ackTime) { + r.ackPoints[1].ackTime = ackTime + } else if ackTime.After(r.ackPoints[1].ackTime) { + r.ackPoints[0] = r.ackPoints[1] + r.ackPoints[1].ackTime = ackTime + } + + r.ackPoints[1].totalBytesAcked = totalBytesAcked +} + +func (r *recentAckPoints) Clear() { + r.ackPoints[0] = ackPoint{} + r.ackPoints[1] = ackPoint{} +} + +func (r *recentAckPoints) MostRecentPoint() *ackPoint { + return &r.ackPoints[1] +} + +func (r *recentAckPoints) LessRecentPoint() *ackPoint { + if r.ackPoints[0].totalBytesAcked != 0 { + return &r.ackPoints[0] + } + + return &r.ackPoints[1] +} + +// ConnectionStateOnSentPacket represents the information about a sent packet +// and the state of the connection at the moment the packet was sent, +// specifically the information about the most recently acknowledged packet at +// that moment. +type connectionStateOnSentPacket struct { + // Time at which the packet is sent. + sentTime time.Time + // Size of the packet. + size congestion.ByteCount + // The value of |totalBytesSentAtLastAckedPacket| at the time the + // packet was sent. + totalBytesSentAtLastAckedPacket congestion.ByteCount + // The value of |lastAckedPacketSentTime| at the time the packet was + // sent. + lastAckedPacketSentTime time.Time + // The value of |lastAckedPacketAckTime| at the time the packet was + // sent. + lastAckedPacketAckTime time.Time + // Send time states that are returned to the congestion controller when the + // packet is acked or lost. + sendTimeState sendTimeState +} + +// Snapshot constructor. Records the current state of the bandwidth +// sampler. +// |bytes_in_flight| is the bytes in flight right after the packet is sent. +func newConnectionStateOnSentPacket( + sentTime time.Time, + size congestion.ByteCount, + bytesInFlight congestion.ByteCount, + sampler *bandwidthSampler, +) *connectionStateOnSentPacket { + return &connectionStateOnSentPacket{ + sentTime: sentTime, + size: size, + totalBytesSentAtLastAckedPacket: sampler.totalBytesSentAtLastAckedPacket, + lastAckedPacketSentTime: sampler.lastAckedPacketSentTime, + lastAckedPacketAckTime: sampler.lastAckedPacketAckTime, + sendTimeState: *newSendTimeState( + sampler.isAppLimited, + sampler.totalBytesSent, + sampler.totalBytesAcked, + sampler.totalBytesLost, + bytesInFlight, + ), + } +} + +// BandwidthSampler keeps track of sent and acknowledged packets and outputs a +// bandwidth sample for every packet acknowledged. The samples are taken for +// individual packets, and are not filtered; the consumer has to filter the +// bandwidth samples itself. In certain cases, the sampler will locally severely +// underestimate the bandwidth, hence a maximum filter with a size of at least +// one RTT is recommended. +// +// This class bases its samples on the slope of two curves: the number of bytes +// sent over time, and the number of bytes acknowledged as received over time. +// It produces a sample of both slopes for every packet that gets acknowledged, +// based on a slope between two points on each of the corresponding curves. Note +// that due to the packet loss, the number of bytes on each curve might get +// further and further away from each other, meaning that it is not feasible to +// compare byte values coming from different curves with each other. +// +// The obvious points for measuring slope sample are the ones corresponding to +// the packet that was just acknowledged. Let us denote them as S_1 (point at +// which the current packet was sent) and A_1 (point at which the current packet +// was acknowledged). However, taking a slope requires two points on each line, +// so estimating bandwidth requires picking a packet in the past with respect to +// which the slope is measured. +// +// For that purpose, BandwidthSampler always keeps track of the most recently +// acknowledged packet, and records it together with every outgoing packet. +// When a packet gets acknowledged (A_1), it has not only information about when +// it itself was sent (S_1), but also the information about the latest +// acknowledged packet right before it was sent (S_0 and A_0). +// +// Based on that data, send and ack rate are estimated as: +// +// send_rate = (bytes(S_1) - bytes(S_0)) / (time(S_1) - time(S_0)) +// ack_rate = (bytes(A_1) - bytes(A_0)) / (time(A_1) - time(A_0)) +// +// Here, the ack rate is intuitively the rate we want to treat as bandwidth. +// However, in certain cases (e.g. ack compression) the ack rate at a point may +// end up higher than the rate at which the data was originally sent, which is +// not indicative of the real bandwidth. Hence, we use the send rate as an upper +// bound, and the sample value is +// +// rate_sample = Min(send_rate, ack_rate) +// +// An important edge case handled by the sampler is tracking the app-limited +// samples. There are multiple meaning of "app-limited" used interchangeably, +// hence it is important to understand and to be able to distinguish between +// them. +// +// Meaning 1: connection state. The connection is said to be app-limited when +// there is no outstanding data to send. This means that certain bandwidth +// samples in the future would not be an accurate indication of the link +// capacity, and it is important to inform consumer about that. Whenever +// connection becomes app-limited, the sampler is notified via OnAppLimited() +// method. +// +// Meaning 2: a phase in the bandwidth sampler. As soon as the bandwidth +// sampler becomes notified about the connection being app-limited, it enters +// app-limited phase. In that phase, all *sent* packets are marked as +// app-limited. Note that the connection itself does not have to be +// app-limited during the app-limited phase, and in fact it will not be +// (otherwise how would it send packets?). The boolean flag below indicates +// whether the sampler is in that phase. +// +// Meaning 3: a flag on the sent packet and on the sample. If a sent packet is +// sent during the app-limited phase, the resulting sample related to the +// packet will be marked as app-limited. +// +// With the terminology issue out of the way, let us consider the question of +// what kind of situation it addresses. +// +// Consider a scenario where we first send packets 1 to 20 at a regular +// bandwidth, and then immediately run out of data. After a few seconds, we send +// packets 21 to 60, and only receive ack for 21 between sending packets 40 and +// 41. In this case, when we sample bandwidth for packets 21 to 40, the S_0/A_0 +// we use to compute the slope is going to be packet 20, a few seconds apart +// from the current packet, hence the resulting estimate would be extremely low +// and not indicative of anything. Only at packet 41 the S_0/A_0 will become 21, +// meaning that the bandwidth sample would exclude the quiescence. +// +// Based on the analysis of that scenario, we implement the following rule: once +// OnAppLimited() is called, all sent packets will produce app-limited samples +// up until an ack for a packet that was sent after OnAppLimited() was called. +// Note that while the scenario above is not the only scenario when the +// connection is app-limited, the approach works in other cases too. + +type congestionEventSample struct { + // The maximum bandwidth sample from all acked packets. + // QuicBandwidth::Zero() if no samples are available. + sampleMaxBandwidth Bandwidth + // Whether |sample_max_bandwidth| is from a app-limited sample. + sampleIsAppLimited bool + // The minimum rtt sample from all acked packets. + // QuicTime::Delta::Infinite() if no samples are available. + sampleRtt time.Duration + // For each packet p in acked packets, this is the max value of INFLIGHT(p), + // where INFLIGHT(p) is the number of bytes acked while p is inflight. + sampleMaxInflight congestion.ByteCount + // The send state of the largest packet in acked_packets, unless it is + // empty. If acked_packets is empty, it's the send state of the largest + // packet in lost_packets. + lastPacketSendState sendTimeState + // The number of extra bytes acked from this ack event, compared to what is + // expected from the flow's bandwidth. Larger value means more ack + // aggregation. + extraAcked congestion.ByteCount +} + +func newCongestionEventSample() *congestionEventSample { + return &congestionEventSample{ + sampleRtt: infRTT, + } +} + +type bandwidthSampler struct { + // The total number of congestion controlled bytes sent during the connection. + totalBytesSent congestion.ByteCount + + // The total number of congestion controlled bytes which were acknowledged. + totalBytesAcked congestion.ByteCount + + // The total number of congestion controlled bytes which were lost. + totalBytesLost congestion.ByteCount + + // The total number of congestion controlled bytes which have been neutered. + totalBytesNeutered congestion.ByteCount + + // The value of |total_bytes_sent_| at the time the last acknowledged packet + // was sent. Valid only when |last_acked_packet_sent_time_| is valid. + totalBytesSentAtLastAckedPacket congestion.ByteCount + + // The time at which the last acknowledged packet was sent. Set to + // QuicTime::Zero() if no valid timestamp is available. + lastAckedPacketSentTime time.Time + + // The time at which the most recent packet was acknowledged. + lastAckedPacketAckTime time.Time + + // The most recently sent packet. + lastSentPacket congestion.PacketNumber + + // The most recently acked packet. + lastAckedPacket congestion.PacketNumber + + // Indicates whether the bandwidth sampler is currently in an app-limited + // phase. + isAppLimited bool + + // The packet that will be acknowledged after this one will cause the sampler + // to exit the app-limited phase. + endOfAppLimitedPhase congestion.PacketNumber + + // Record of the connection state at the point where each packet in flight was + // sent, indexed by the packet number. + connectionStateMap *packetNumberIndexedQueue[connectionStateOnSentPacket] + + recentAckPoints recentAckPoints + a0Candidates RingBuffer[ackPoint] + + // Maximum number of tracked packets. + maxTrackedPackets congestion.ByteCount + + maxAckHeightTracker *maxAckHeightTracker + totalBytesAckedAfterLastAckEvent congestion.ByteCount + + // True if connection option 'BSAO' is set. + overestimateAvoidance bool + + // True if connection option 'BBRB' is set. + limitMaxAckHeightTrackerBySendRate bool +} + +func newBandwidthSampler(maxAckHeightTrackerWindowLength roundTripCount) *bandwidthSampler { + b := &bandwidthSampler{ + maxAckHeightTracker: newMaxAckHeightTracker(maxAckHeightTrackerWindowLength), + connectionStateMap: newPacketNumberIndexedQueue[connectionStateOnSentPacket](defaultConnectionStateMapQueueSize), + lastSentPacket: invalidPacketNumber, + lastAckedPacket: invalidPacketNumber, + endOfAppLimitedPhase: invalidPacketNumber, + } + + b.a0Candidates.Init(defaultCandidatesBufferSize) + + return b +} + +func (b *bandwidthSampler) MaxAckHeight() congestion.ByteCount { + return b.maxAckHeightTracker.Get() +} + +func (b *bandwidthSampler) NumAckAggregationEpochs() uint64 { + return b.maxAckHeightTracker.NumAckAggregationEpochs() +} + +func (b *bandwidthSampler) SetMaxAckHeightTrackerWindowLength(length roundTripCount) { + b.maxAckHeightTracker.SetFilterWindowLength(length) +} + +func (b *bandwidthSampler) ResetMaxAckHeightTracker(newHeight congestion.ByteCount, newTime roundTripCount) { + b.maxAckHeightTracker.Reset(newHeight, newTime) +} + +func (b *bandwidthSampler) SetStartNewAggregationEpochAfterFullRound(value bool) { + b.maxAckHeightTracker.SetStartNewAggregationEpochAfterFullRound(value) +} + +func (b *bandwidthSampler) SetLimitMaxAckHeightTrackerBySendRate(value bool) { + b.limitMaxAckHeightTrackerBySendRate = value +} + +func (b *bandwidthSampler) SetReduceExtraAckedOnBandwidthIncrease(value bool) { + b.maxAckHeightTracker.SetReduceExtraAckedOnBandwidthIncrease(value) +} + +func (b *bandwidthSampler) EnableOverestimateAvoidance() { + if b.overestimateAvoidance { + return + } + + b.overestimateAvoidance = true + b.maxAckHeightTracker.SetAckAggregationBandwidthThreshold(2.0) +} + +func (b *bandwidthSampler) IsOverestimateAvoidanceEnabled() bool { + return b.overestimateAvoidance +} + +func (b *bandwidthSampler) OnPacketSent( + sentTime time.Time, + packetNumber congestion.PacketNumber, + bytes congestion.ByteCount, + bytesInFlight congestion.ByteCount, + isRetransmittable bool, +) { + b.lastSentPacket = packetNumber + + if !isRetransmittable { + return + } + + b.totalBytesSent += bytes + + // If there are no packets in flight, the time at which the new transmission + // opens can be treated as the A_0 point for the purpose of bandwidth + // sampling. This underestimates bandwidth to some extent, and produces some + // artificially low samples for most packets in flight, but it provides with + // samples at important points where we would not have them otherwise, most + // importantly at the beginning of the connection. + if bytesInFlight == 0 { + b.lastAckedPacketAckTime = sentTime + if b.overestimateAvoidance { + b.recentAckPoints.Clear() + b.recentAckPoints.Update(sentTime, b.totalBytesAcked) + b.a0Candidates.Clear() + b.a0Candidates.PushBack(*b.recentAckPoints.MostRecentPoint()) + } + b.totalBytesSentAtLastAckedPacket = b.totalBytesSent + + // In this situation ack compression is not a concern, set send rate to + // effectively infinite. + b.lastAckedPacketSentTime = sentTime + } + + b.connectionStateMap.Emplace(packetNumber, newConnectionStateOnSentPacket( + sentTime, + bytes, + bytesInFlight+bytes, + b, + )) +} + +func (b *bandwidthSampler) OnCongestionEvent( + ackTime time.Time, + ackedPackets []congestion.AckedPacketInfo, + lostPackets []congestion.LostPacketInfo, + maxBandwidth Bandwidth, + estBandwidthUpperBound Bandwidth, + roundTripCount roundTripCount, +) congestionEventSample { + eventSample := newCongestionEventSample() + + var lastLostPacketSendState sendTimeState + + for _, p := range lostPackets { + sendState := b.OnPacketLost(p.PacketNumber, p.BytesLost) + if sendState.isValid { + lastLostPacketSendState = sendState + } + } + + if len(ackedPackets) == 0 { + // Only populate send state for a loss-only event. + eventSample.lastPacketSendState = lastLostPacketSendState + return *eventSample + } + + var lastAckedPacketSendState sendTimeState + var maxSendRate Bandwidth + + for _, p := range ackedPackets { + sample := b.onPacketAcknowledged(ackTime, p.PacketNumber) + if !sample.stateAtSend.isValid { + continue + } + + lastAckedPacketSendState = sample.stateAtSend + + if sample.rtt != 0 { + eventSample.sampleRtt = Min(eventSample.sampleRtt, sample.rtt) + } + if sample.bandwidth > eventSample.sampleMaxBandwidth { + eventSample.sampleMaxBandwidth = sample.bandwidth + eventSample.sampleIsAppLimited = sample.stateAtSend.isAppLimited + } + if sample.sendRate != infBandwidth { + maxSendRate = Max(maxSendRate, sample.sendRate) + } + inflightSample := b.totalBytesAcked - lastAckedPacketSendState.totalBytesAcked + if inflightSample > eventSample.sampleMaxInflight { + eventSample.sampleMaxInflight = inflightSample + } + } + + if !lastLostPacketSendState.isValid { + eventSample.lastPacketSendState = lastAckedPacketSendState + } else if !lastAckedPacketSendState.isValid { + eventSample.lastPacketSendState = lastLostPacketSendState + } else { + // If two packets are inflight and an alarm is armed to lose a packet and it + // wakes up late, then the first of two in flight packets could have been + // acknowledged before the wakeup, which re-evaluates loss detection, and + // could declare the later of the two lost. + if lostPackets[len(lostPackets)-1].PacketNumber > ackedPackets[len(ackedPackets)-1].PacketNumber { + eventSample.lastPacketSendState = lastLostPacketSendState + } else { + eventSample.lastPacketSendState = lastAckedPacketSendState + } + } + + isNewMaxBandwidth := eventSample.sampleMaxBandwidth > maxBandwidth + maxBandwidth = Max(maxBandwidth, eventSample.sampleMaxBandwidth) + if b.limitMaxAckHeightTrackerBySendRate { + maxBandwidth = Max(maxBandwidth, maxSendRate) + } + + eventSample.extraAcked = b.onAckEventEnd(Min(estBandwidthUpperBound, maxBandwidth), isNewMaxBandwidth, roundTripCount) + + return *eventSample +} + +func (b *bandwidthSampler) OnPacketLost(packetNumber congestion.PacketNumber, bytesLost congestion.ByteCount) (s sendTimeState) { + b.totalBytesLost += bytesLost + if sentPacketPointer := b.connectionStateMap.GetEntry(packetNumber); sentPacketPointer != nil { + sentPacketToSendTimeState(sentPacketPointer, &s) + } + return s +} + +func (b *bandwidthSampler) OnPacketNeutered(packetNumber congestion.PacketNumber) { + b.connectionStateMap.Remove(packetNumber, func(sentPacket connectionStateOnSentPacket) { + b.totalBytesNeutered += sentPacket.size + }) +} + +func (b *bandwidthSampler) OnAppLimited() { + b.isAppLimited = true + b.endOfAppLimitedPhase = b.lastSentPacket +} + +func (b *bandwidthSampler) RemoveObsoletePackets(leastUnacked congestion.PacketNumber) { + // A packet can become obsolete when it is removed from QuicUnackedPacketMap's + // view of inflight before it is acked or marked as lost. For example, when + // QuicSentPacketManager::RetransmitCryptoPackets retransmits a crypto packet, + // the packet is removed from QuicUnackedPacketMap's inflight, but is not + // marked as acked or lost in the BandwidthSampler. + b.connectionStateMap.RemoveUpTo(leastUnacked) +} + +func (b *bandwidthSampler) TotalBytesSent() congestion.ByteCount { + return b.totalBytesSent +} + +func (b *bandwidthSampler) TotalBytesLost() congestion.ByteCount { + return b.totalBytesLost +} + +func (b *bandwidthSampler) TotalBytesAcked() congestion.ByteCount { + return b.totalBytesAcked +} + +func (b *bandwidthSampler) TotalBytesNeutered() congestion.ByteCount { + return b.totalBytesNeutered +} + +func (b *bandwidthSampler) IsAppLimited() bool { + return b.isAppLimited +} + +func (b *bandwidthSampler) EndOfAppLimitedPhase() congestion.PacketNumber { + return b.endOfAppLimitedPhase +} + +func (b *bandwidthSampler) max_ack_height() congestion.ByteCount { + return b.maxAckHeightTracker.Get() +} + +func (b *bandwidthSampler) chooseA0Point(totalBytesAcked congestion.ByteCount, a0 *ackPoint) bool { + if b.a0Candidates.Empty() { + return false + } + + if b.a0Candidates.Len() == 1 { + *a0 = *b.a0Candidates.Front() + return true + } + + for i := 1; i < b.a0Candidates.Len(); i++ { + if b.a0Candidates.Offset(i).totalBytesAcked > totalBytesAcked { + *a0 = *b.a0Candidates.Offset(i - 1) + if i > 1 { + for j := 0; j < i-1; j++ { + b.a0Candidates.PopFront() + } + } + return true + } + } + + *a0 = *b.a0Candidates.Back() + for k := 0; k < b.a0Candidates.Len()-1; k++ { + b.a0Candidates.PopFront() + } + return true +} + +func (b *bandwidthSampler) onPacketAcknowledged(ackTime time.Time, packetNumber congestion.PacketNumber) bandwidthSample { + sample := newBandwidthSample() + b.lastAckedPacket = packetNumber + sentPacketPointer := b.connectionStateMap.GetEntry(packetNumber) + if sentPacketPointer == nil { + return *sample + } + + // OnPacketAcknowledgedInner + b.totalBytesAcked += sentPacketPointer.size + b.totalBytesSentAtLastAckedPacket = sentPacketPointer.sendTimeState.totalBytesSent + b.lastAckedPacketSentTime = sentPacketPointer.sentTime + b.lastAckedPacketAckTime = ackTime + if b.overestimateAvoidance { + b.recentAckPoints.Update(ackTime, b.totalBytesAcked) + } + + if b.isAppLimited { + // Exit app-limited phase in two cases: + // (1) end_of_app_limited_phase_ is not initialized, i.e., so far all + // packets are sent while there are buffered packets or pending data. + // (2) The current acked packet is after the sent packet marked as the end + // of the app limit phase. + if b.endOfAppLimitedPhase == invalidPacketNumber || + packetNumber > b.endOfAppLimitedPhase { + b.isAppLimited = false + } + } + + // There might have been no packets acknowledged at the moment when the + // current packet was sent. In that case, there is no bandwidth sample to + // make. + if sentPacketPointer.lastAckedPacketSentTime.IsZero() { + return *sample + } + + // Infinite rate indicates that the sampler is supposed to discard the + // current send rate sample and use only the ack rate. + sendRate := infBandwidth + if sentPacketPointer.sentTime.After(sentPacketPointer.lastAckedPacketSentTime) { + sendRate = BandwidthFromDelta( + sentPacketPointer.sendTimeState.totalBytesSent-sentPacketPointer.totalBytesSentAtLastAckedPacket, + sentPacketPointer.sentTime.Sub(sentPacketPointer.lastAckedPacketSentTime)) + } + + var a0 ackPoint + if b.overestimateAvoidance && b.chooseA0Point(sentPacketPointer.sendTimeState.totalBytesAcked, &a0) { + } else { + a0.ackTime = sentPacketPointer.lastAckedPacketAckTime + a0.totalBytesAcked = sentPacketPointer.sendTimeState.totalBytesAcked + } + + // During the slope calculation, ensure that ack time of the current packet is + // always larger than the time of the previous packet, otherwise division by + // zero or integer underflow can occur. + if ackTime.Sub(a0.ackTime) <= 0 { + return *sample + } + + ackRate := BandwidthFromDelta(b.totalBytesAcked-a0.totalBytesAcked, ackTime.Sub(a0.ackTime)) + + sample.bandwidth = Min(sendRate, ackRate) + // Note: this sample does not account for delayed acknowledgement time. This + // means that the RTT measurements here can be artificially high, especially + // on low bandwidth connections. + sample.rtt = ackTime.Sub(sentPacketPointer.sentTime) + sample.sendRate = sendRate + sentPacketToSendTimeState(sentPacketPointer, &sample.stateAtSend) + + return *sample +} + +func (b *bandwidthSampler) onAckEventEnd( + bandwidthEstimate Bandwidth, + isNewMaxBandwidth bool, + roundTripCount roundTripCount, +) congestion.ByteCount { + newlyAckedBytes := b.totalBytesAcked - b.totalBytesAckedAfterLastAckEvent + if newlyAckedBytes == 0 { + return 0 + } + b.totalBytesAckedAfterLastAckEvent = b.totalBytesAcked + extraAcked := b.maxAckHeightTracker.Update( + bandwidthEstimate, + isNewMaxBandwidth, + roundTripCount, + b.lastSentPacket, + b.lastAckedPacket, + b.lastAckedPacketAckTime, + newlyAckedBytes) + // If |extra_acked| is zero, i.e. this ack event marks the start of a new ack + // aggregation epoch, save LessRecentPoint, which is the last ack point of the + // previous epoch, as a A0 candidate. + if b.overestimateAvoidance && extraAcked == 0 { + b.a0Candidates.PushBack(*b.recentAckPoints.LessRecentPoint()) + } + return extraAcked +} + +func sentPacketToSendTimeState(sentPacket *connectionStateOnSentPacket, sendTimeState *sendTimeState) { + *sendTimeState = sentPacket.sendTimeState + sendTimeState.isValid = true +} + +// BytesFromBandwidthAndTimeDelta calculates the bytes +// from a bandwidth(bits per second) and a time delta +func bytesFromBandwidthAndTimeDelta(bandwidth Bandwidth, delta time.Duration) congestion.ByteCount { + return (congestion.ByteCount(bandwidth) * congestion.ByteCount(delta)) / + (congestion.ByteCount(time.Second) * 8) +} + +func timeDeltaFromBytesAndBandwidth(bytes congestion.ByteCount, bandwidth Bandwidth) time.Duration { + return time.Duration(bytes*8) * time.Second / time.Duration(bandwidth) +} diff --git a/transport/tuic/congestion_v2/bbr_sender.go b/transport/tuic/congestion_v2/bbr_sender.go new file mode 100644 index 00000000..a7700fa1 --- /dev/null +++ b/transport/tuic/congestion_v2/bbr_sender.go @@ -0,0 +1,927 @@ +package congestion + +// src from https://github.com/google/quiche/blob/e7872fc9e12bb1d46a118949c3d4da36de58aa44/quiche/quic/core/congestion_control/bbr_sender.cc + +import ( + "fmt" + "net" + "time" + + "github.com/metacubex/quic-go/congestion" + + "github.com/zhangyunhao116/fastrand" +) + +// BbrSender implements BBR congestion control algorithm. BBR aims to estimate +// the current available Bottleneck Bandwidth and RTT (hence the name), and +// regulates the pacing rate and the size of the congestion window based on +// those signals. +// +// BBR relies on pacing in order to function properly. Do not use BBR when +// pacing is disabled. +// + +const ( + invalidPacketNumber = -1 + initialCongestionWindowPackets = 32 + + // Constants based on TCP defaults. + // The minimum CWND to ensure delayed acks don't reduce bandwidth measurements. + // Does not inflate the pacing rate. + defaultMinimumCongestionWindow = 4 * congestion.ByteCount(congestion.InitialPacketSizeIPv4) + + // The gain used for the STARTUP, equal to 2/ln(2). + defaultHighGain = 2.885 + // The newly derived gain for STARTUP, equal to 4 * ln(2) + derivedHighGain = 2.773 + // The newly derived CWND gain for STARTUP, 2. + derivedHighCWNDGain = 2.0 +) + +// The cycle of gains used during the PROBE_BW stage. +var pacingGain = [...]float64{1.25, 0.75, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0} + +const ( + // The length of the gain cycle. + gainCycleLength = len(pacingGain) + // The size of the bandwidth filter window, in round-trips. + bandwidthWindowSize = gainCycleLength + 2 + + // The time after which the current min_rtt value expires. + minRttExpiry = 10 * time.Second + // The minimum time the connection can spend in PROBE_RTT mode. + probeRttTime = 200 * time.Millisecond + // If the bandwidth does not increase by the factor of |kStartupGrowthTarget| + // within |kRoundTripsWithoutGrowthBeforeExitingStartup| rounds, the connection + // will exit the STARTUP mode. + startupGrowthTarget = 1.25 + roundTripsWithoutGrowthBeforeExitingStartup = int64(3) + + // Flag. + defaultStartupFullLossCount = 8 + quicBbr2DefaultLossThreshold = 0.02 + maxBbrBurstPackets = 3 +) + +type bbrMode int + +const ( + // Startup phase of the connection. + bbrModeStartup = iota + // After achieving the highest possible bandwidth during the startup, lower + // the pacing rate in order to drain the queue. + bbrModeDrain + // Cruising mode. + bbrModeProbeBw + // Temporarily slow down sending in order to empty the buffer and measure + // the real minimum RTT. + bbrModeProbeRtt +) + +// Indicates how the congestion control limits the amount of bytes in flight. +type bbrRecoveryState int + +const ( + // Do not limit. + bbrRecoveryStateNotInRecovery = iota + // Allow an extra outstanding byte for each byte acknowledged. + bbrRecoveryStateConservation + // Allow two extra outstanding bytes for each byte acknowledged (slow + // start). + bbrRecoveryStateGrowth +) + +type bbrSender struct { + rttStats congestion.RTTStatsProvider + clock Clock + pacer *Pacer + + mode bbrMode + + // Bandwidth sampler provides BBR with the bandwidth measurements at + // individual points. + sampler *bandwidthSampler + + // The number of the round trips that have occurred during the connection. + roundTripCount roundTripCount + + // The packet number of the most recently sent packet. + lastSentPacket congestion.PacketNumber + // Acknowledgement of any packet after |current_round_trip_end_| will cause + // the round trip counter to advance. + currentRoundTripEnd congestion.PacketNumber + + // Number of congestion events with some losses, in the current round. + numLossEventsInRound uint64 + + // Number of total bytes lost in the current round. + bytesLostInRound congestion.ByteCount + + // The filter that tracks the maximum bandwidth over the multiple recent + // round-trips. + maxBandwidth *WindowedFilter[Bandwidth, roundTripCount] + + // Minimum RTT estimate. Automatically expires within 10 seconds (and + // triggers PROBE_RTT mode) if no new value is sampled during that period. + minRtt time.Duration + // The time at which the current value of |min_rtt_| was assigned. + minRttTimestamp time.Time + + // The maximum allowed number of bytes in flight. + congestionWindow congestion.ByteCount + + // The initial value of the |congestion_window_|. + initialCongestionWindow congestion.ByteCount + + // The largest value the |congestion_window_| can achieve. + maxCongestionWindow congestion.ByteCount + + // The smallest value the |congestion_window_| can achieve. + minCongestionWindow congestion.ByteCount + + // The pacing gain applied during the STARTUP phase. + highGain float64 + + // The CWND gain applied during the STARTUP phase. + highCwndGain float64 + + // The pacing gain applied during the DRAIN phase. + drainGain float64 + + // The current pacing rate of the connection. + pacingRate Bandwidth + + // The gain currently applied to the pacing rate. + pacingGain float64 + // The gain currently applied to the congestion window. + congestionWindowGain float64 + + // The gain used for the congestion window during PROBE_BW. Latched from + // quic_bbr_cwnd_gain flag. + congestionWindowGainConstant float64 + // The number of RTTs to stay in STARTUP mode. Defaults to 3. + numStartupRtts int64 + + // Number of round-trips in PROBE_BW mode, used for determining the current + // pacing gain cycle. + cycleCurrentOffset int + // The time at which the last pacing gain cycle was started. + lastCycleStart time.Time + + // Indicates whether the connection has reached the full bandwidth mode. + isAtFullBandwidth bool + // Number of rounds during which there was no significant bandwidth increase. + roundsWithoutBandwidthGain int64 + // The bandwidth compared to which the increase is measured. + bandwidthAtLastRound Bandwidth + + // Set to true upon exiting quiescence. + exitingQuiescence bool + + // Time at which PROBE_RTT has to be exited. Setting it to zero indicates + // that the time is yet unknown as the number of packets in flight has not + // reached the required value. + exitProbeRttAt time.Time + // Indicates whether a round-trip has passed since PROBE_RTT became active. + probeRttRoundPassed bool + + // Indicates whether the most recent bandwidth sample was marked as + // app-limited. + lastSampleIsAppLimited bool + // Indicates whether any non app-limited samples have been recorded. + hasNoAppLimitedSample bool + + // Current state of recovery. + recoveryState bbrRecoveryState + // Receiving acknowledgement of a packet after |end_recovery_at_| will cause + // BBR to exit the recovery mode. A value above zero indicates at least one + // loss has been detected, so it must not be set back to zero. + endRecoveryAt congestion.PacketNumber + // A window used to limit the number of bytes in flight during loss recovery. + recoveryWindow congestion.ByteCount + // If true, consider all samples in recovery app-limited. + isAppLimitedRecovery bool // not used + + // When true, pace at 1.5x and disable packet conservation in STARTUP. + slowerStartup bool // not used + // When true, disables packet conservation in STARTUP. + rateBasedStartup bool // not used + + // When true, add the most recent ack aggregation measurement during STARTUP. + enableAckAggregationDuringStartup bool + // When true, expire the windowed ack aggregation values in STARTUP when + // bandwidth increases more than 25%. + expireAckAggregationInStartup bool + + // If true, will not exit low gain mode until bytes_in_flight drops below BDP + // or it's time for high gain mode. + drainToTarget bool + + // If true, slow down pacing rate in STARTUP when overshooting is detected. + detectOvershooting bool + // Bytes lost while detect_overshooting_ is true. + bytesLostWhileDetectingOvershooting congestion.ByteCount + // Slow down pacing rate if + // bytes_lost_while_detecting_overshooting_ * + // bytes_lost_multiplier_while_detecting_overshooting_ > IW. + bytesLostMultiplierWhileDetectingOvershooting uint8 + // When overshooting is detected, do not drop pacing_rate_ below this value / + // min_rtt. + cwndToCalculateMinPacingRate congestion.ByteCount + + // Max congestion window when adjusting network parameters. + maxCongestionWindowWithNetworkParametersAdjusted congestion.ByteCount // not used + + // Params. + maxDatagramSize congestion.ByteCount + // Recorded on packet sent. equivalent |unacked_packets_->bytes_in_flight()| + bytesInFlight congestion.ByteCount +} + +var _ congestion.CongestionControl = &bbrSender{} + +func NewBbrSender( + clock Clock, + initialMaxDatagramSize congestion.ByteCount, + initialCongestionWindowPackets congestion.ByteCount, +) *bbrSender { + return newBbrSender( + clock, + initialMaxDatagramSize, + initialCongestionWindowPackets*initialMaxDatagramSize, + congestion.MaxCongestionWindowPackets*initialMaxDatagramSize, + ) +} + +func newBbrSender( + clock Clock, + initialMaxDatagramSize, + initialCongestionWindow, + initialMaxCongestionWindow congestion.ByteCount, +) *bbrSender { + b := &bbrSender{ + clock: clock, + mode: bbrModeStartup, + sampler: newBandwidthSampler(roundTripCount(bandwidthWindowSize)), + lastSentPacket: invalidPacketNumber, + currentRoundTripEnd: invalidPacketNumber, + maxBandwidth: NewWindowedFilter(roundTripCount(bandwidthWindowSize), MaxFilter[Bandwidth]), + congestionWindow: initialCongestionWindow, + initialCongestionWindow: initialCongestionWindow, + maxCongestionWindow: initialMaxCongestionWindow, + minCongestionWindow: defaultMinimumCongestionWindow, + highGain: defaultHighGain, + highCwndGain: defaultHighGain, + drainGain: 1.0 / defaultHighGain, + pacingGain: 1.0, + congestionWindowGain: 1.0, + congestionWindowGainConstant: 2.0, + numStartupRtts: roundTripsWithoutGrowthBeforeExitingStartup, + recoveryState: bbrRecoveryStateNotInRecovery, + endRecoveryAt: invalidPacketNumber, + recoveryWindow: initialMaxCongestionWindow, + bytesLostMultiplierWhileDetectingOvershooting: 2, + cwndToCalculateMinPacingRate: initialCongestionWindow, + maxCongestionWindowWithNetworkParametersAdjusted: initialMaxCongestionWindow, + maxDatagramSize: initialMaxDatagramSize, + } + b.pacer = NewPacer(func() congestion.ByteCount { + // Pacer wants bytes per second, but Bandwidth is in bits per second. + return congestion.ByteCount(float64(b.bandwidthEstimate()) * b.congestionWindowGain / float64(BytesPerSecond)) + }) + + /* + if b.tracer != nil { + b.lastState = logging.CongestionStateStartup + b.tracer.UpdatedCongestionState(logging.CongestionStateStartup) + } + */ + + b.enterStartupMode(b.clock.Now()) + b.setHighCwndGain(derivedHighCWNDGain) + + return b +} + +func (b *bbrSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { + b.rttStats = provider +} + +// TimeUntilSend implements the SendAlgorithm interface. +func (b *bbrSender) TimeUntilSend(bytesInFlight congestion.ByteCount) time.Time { + return b.pacer.TimeUntilSend() +} + +// HasPacingBudget implements the SendAlgorithm interface. +func (b *bbrSender) HasPacingBudget(now time.Time) bool { + return b.pacer.Budget(now) >= b.maxDatagramSize +} + +// OnPacketSent implements the SendAlgorithm interface. +func (b *bbrSender) OnPacketSent( + sentTime time.Time, + bytesInFlight congestion.ByteCount, + packetNumber congestion.PacketNumber, + bytes congestion.ByteCount, + isRetransmittable bool, +) { + b.pacer.SentPacket(sentTime, bytes) + + b.lastSentPacket = packetNumber + b.bytesInFlight = bytesInFlight + + if bytesInFlight == 0 { + b.exitingQuiescence = true + } + + b.sampler.OnPacketSent(sentTime, packetNumber, bytes, bytesInFlight, isRetransmittable) +} + +// CanSend implements the SendAlgorithm interface. +func (b *bbrSender) CanSend(bytesInFlight congestion.ByteCount) bool { + return bytesInFlight < b.GetCongestionWindow() +} + +// MaybeExitSlowStart implements the SendAlgorithm interface. +func (b *bbrSender) MaybeExitSlowStart() { + // Do nothing +} + +// OnPacketAcked implements the SendAlgorithm interface. +func (b *bbrSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes, priorInFlight congestion.ByteCount, eventTime time.Time) { + // Do nothing. +} + +// OnPacketLost implements the SendAlgorithm interface. +func (b *bbrSender) OnPacketLost(number congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { + // Do nothing. +} + +// OnRetransmissionTimeout implements the SendAlgorithm interface. +func (b *bbrSender) OnRetransmissionTimeout(packetsRetransmitted bool) { + // Do nothing. +} + +// SetMaxDatagramSize implements the SendAlgorithm interface. +func (b *bbrSender) SetMaxDatagramSize(s congestion.ByteCount) { + if s < b.maxDatagramSize { + panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", b.maxDatagramSize, s)) + } + cwndIsMinCwnd := b.congestionWindow == b.minCongestionWindow + b.maxDatagramSize = s + if cwndIsMinCwnd { + b.congestionWindow = b.minCongestionWindow + } + b.pacer.SetMaxDatagramSize(s) +} + +// InSlowStart implements the SendAlgorithmWithDebugInfos interface. +func (b *bbrSender) InSlowStart() bool { + return b.mode == bbrModeStartup +} + +// InRecovery implements the SendAlgorithmWithDebugInfos interface. +func (b *bbrSender) InRecovery() bool { + return b.recoveryState != bbrRecoveryStateNotInRecovery +} + +// GetCongestionWindow implements the SendAlgorithmWithDebugInfos interface. +func (b *bbrSender) GetCongestionWindow() congestion.ByteCount { + if b.mode == bbrModeProbeRtt { + return b.probeRttCongestionWindow() + } + + if b.InRecovery() { + return Min(b.congestionWindow, b.recoveryWindow) + } + + return b.congestionWindow +} + +func (b *bbrSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { + // Do nothing. +} + +func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + totalBytesAckedBefore := b.sampler.TotalBytesAcked() + totalBytesLostBefore := b.sampler.TotalBytesLost() + + var isRoundStart, minRttExpired bool + var excessAcked, bytesLost congestion.ByteCount + + // The send state of the largest packet in acked_packets, unless it is + // empty. If acked_packets is empty, it's the send state of the largest + // packet in lost_packets. + var lastPacketSendState sendTimeState + + b.maybeApplimited(priorInFlight) + + // Update bytesInFlight + b.bytesInFlight = priorInFlight + for _, p := range ackedPackets { + b.bytesInFlight -= p.BytesAcked + } + for _, p := range lostPackets { + b.bytesInFlight -= p.BytesLost + } + + if len(ackedPackets) != 0 { + lastAckedPacket := ackedPackets[len(ackedPackets)-1].PacketNumber + isRoundStart = b.updateRoundTripCounter(lastAckedPacket) + b.updateRecoveryState(lastAckedPacket, len(lostPackets) != 0, isRoundStart) + } + + sample := b.sampler.OnCongestionEvent(eventTime, + ackedPackets, lostPackets, b.maxBandwidth.GetBest(), infBandwidth, b.roundTripCount) + if sample.lastPacketSendState.isValid { + b.lastSampleIsAppLimited = sample.lastPacketSendState.isAppLimited + b.hasNoAppLimitedSample = b.hasNoAppLimitedSample || !b.lastSampleIsAppLimited + } + // Avoid updating |max_bandwidth_| if a) this is a loss-only event, or b) all + // packets in |acked_packets| did not generate valid samples. (e.g. ack of + // ack-only packets). In both cases, sampler_.total_bytes_acked() will not + // change. + if totalBytesAckedBefore != b.sampler.TotalBytesAcked() { + if !sample.sampleIsAppLimited || sample.sampleMaxBandwidth > b.maxBandwidth.GetBest() { + b.maxBandwidth.Update(sample.sampleMaxBandwidth, b.roundTripCount) + } + } + + if sample.sampleRtt != infRTT { + minRttExpired = b.maybeUpdateMinRtt(eventTime, sample.sampleRtt) + } + bytesLost = b.sampler.TotalBytesLost() - totalBytesLostBefore + + excessAcked = sample.extraAcked + lastPacketSendState = sample.lastPacketSendState + + if len(lostPackets) != 0 { + b.numLossEventsInRound++ + b.bytesLostInRound += bytesLost + } + + // Handle logic specific to PROBE_BW mode. + if b.mode == bbrModeProbeBw { + b.updateGainCyclePhase(eventTime, priorInFlight, len(lostPackets) != 0) + } + + // Handle logic specific to STARTUP and DRAIN modes. + if isRoundStart && !b.isAtFullBandwidth { + b.checkIfFullBandwidthReached(&lastPacketSendState) + } + + b.maybeExitStartupOrDrain(eventTime) + + // Handle logic specific to PROBE_RTT. + b.maybeEnterOrExitProbeRtt(eventTime, isRoundStart, minRttExpired) + + // Calculate number of packets acked and lost. + bytesAcked := b.sampler.TotalBytesAcked() - totalBytesAckedBefore + + // After the model is updated, recalculate the pacing rate and congestion + // window. + b.calculatePacingRate(bytesLost) + b.calculateCongestionWindow(bytesAcked, excessAcked) + b.calculateRecoveryWindow(bytesAcked, bytesLost) + + // Cleanup internal state. + if len(lostPackets) != 0 { + lastLostPacket := lostPackets[len(lostPackets)-1].PacketNumber + b.sampler.RemoveObsoletePackets(lastLostPacket) + } + if isRoundStart { + b.numLossEventsInRound = 0 + b.bytesLostInRound = 0 + } +} + +func (b *bbrSender) PacingRate() Bandwidth { + if b.pacingRate == 0 { + return Bandwidth(b.highGain * float64( + BandwidthFromDelta(b.initialCongestionWindow, b.getMinRtt()))) + } + + return b.pacingRate +} + +func (b *bbrSender) hasGoodBandwidthEstimateForResumption() bool { + return b.hasNonAppLimitedSample() +} + +func (b *bbrSender) hasNonAppLimitedSample() bool { + return b.hasNoAppLimitedSample +} + +// Sets the pacing gain used in STARTUP. Must be greater than 1. +func (b *bbrSender) setHighGain(highGain float64) { + b.highGain = highGain + if b.mode == bbrModeStartup { + b.pacingGain = highGain + } +} + +// Sets the CWND gain used in STARTUP. Must be greater than 1. +func (b *bbrSender) setHighCwndGain(highCwndGain float64) { + b.highCwndGain = highCwndGain + if b.mode == bbrModeStartup { + b.congestionWindowGain = highCwndGain + } +} + +// Sets the gain used in DRAIN. Must be less than 1. +func (b *bbrSender) setDrainGain(drainGain float64) { + b.drainGain = drainGain +} + +// What's the current estimated bandwidth in bytes per second. +func (b *bbrSender) bandwidthEstimate() Bandwidth { + return b.maxBandwidth.GetBest() +} + +// Returns the current estimate of the RTT of the connection. Outside of the +// edge cases, this is minimum RTT. +func (b *bbrSender) getMinRtt() time.Duration { + if b.minRtt != 0 { + return b.minRtt + } + // min_rtt could be available if the handshake packet gets neutered then + // gets acknowledged. This could only happen for QUIC crypto where we do not + // drop keys. + minRtt := b.rttStats.MinRTT() + if minRtt == 0 { + return 100 * time.Millisecond + } else { + return minRtt + } +} + +// Computes the target congestion window using the specified gain. +func (b *bbrSender) getTargetCongestionWindow(gain float64) congestion.ByteCount { + bdp := bdpFromRttAndBandwidth(b.getMinRtt(), b.bandwidthEstimate()) + congestionWindow := congestion.ByteCount(gain * float64(bdp)) + + // BDP estimate will be zero if no bandwidth samples are available yet. + if congestionWindow == 0 { + congestionWindow = congestion.ByteCount(gain * float64(b.initialCongestionWindow)) + } + + return Max(congestionWindow, b.minCongestionWindow) +} + +// The target congestion window during PROBE_RTT. +func (b *bbrSender) probeRttCongestionWindow() congestion.ByteCount { + return b.minCongestionWindow +} + +func (b *bbrSender) maybeUpdateMinRtt(now time.Time, sampleMinRtt time.Duration) bool { + // Do not expire min_rtt if none was ever available. + minRttExpired := b.minRtt != 0 && now.After(b.minRttTimestamp.Add(minRttExpiry)) + if minRttExpired || sampleMinRtt < b.minRtt || b.minRtt == 0 { + b.minRtt = sampleMinRtt + b.minRttTimestamp = now + } + + return minRttExpired +} + +// Enters the STARTUP mode. +func (b *bbrSender) enterStartupMode(now time.Time) { + b.mode = bbrModeStartup + // b.maybeTraceStateChange(logging.CongestionStateStartup) + b.pacingGain = b.highGain + b.congestionWindowGain = b.highCwndGain +} + +// Enters the PROBE_BW mode. +func (b *bbrSender) enterProbeBandwidthMode(now time.Time) { + b.mode = bbrModeProbeBw + // b.maybeTraceStateChange(logging.CongestionStateProbeBw) + b.congestionWindowGain = b.congestionWindowGainConstant + + // Pick a random offset for the gain cycle out of {0, 2..7} range. 1 is + // excluded because in that case increased gain and decreased gain would not + // follow each other. + b.cycleCurrentOffset = int(fastrand.Int31n(congestion.PacketsPerConnectionID)) % (gainCycleLength - 1) + if b.cycleCurrentOffset >= 1 { + b.cycleCurrentOffset += 1 + } + + b.lastCycleStart = now + b.pacingGain = pacingGain[b.cycleCurrentOffset] +} + +// Updates the round-trip counter if a round-trip has passed. Returns true if +// the counter has been advanced. +func (b *bbrSender) updateRoundTripCounter(lastAckedPacket congestion.PacketNumber) bool { + if b.currentRoundTripEnd == invalidPacketNumber || lastAckedPacket > b.currentRoundTripEnd { + b.roundTripCount++ + b.currentRoundTripEnd = b.lastSentPacket + return true + } + return false +} + +// Updates the current gain used in PROBE_BW mode. +func (b *bbrSender) updateGainCyclePhase(now time.Time, priorInFlight congestion.ByteCount, hasLosses bool) { + // In most cases, the cycle is advanced after an RTT passes. + shouldAdvanceGainCycling := now.After(b.lastCycleStart.Add(b.getMinRtt())) + // If the pacing gain is above 1.0, the connection is trying to probe the + // bandwidth by increasing the number of bytes in flight to at least + // pacing_gain * BDP. Make sure that it actually reaches the target, as long + // as there are no losses suggesting that the buffers are not able to hold + // that much. + if b.pacingGain > 1.0 && !hasLosses && priorInFlight < b.getTargetCongestionWindow(b.pacingGain) { + shouldAdvanceGainCycling = false + } + + // If pacing gain is below 1.0, the connection is trying to drain the extra + // queue which could have been incurred by probing prior to it. If the number + // of bytes in flight falls down to the estimated BDP value earlier, conclude + // that the queue has been successfully drained and exit this cycle early. + if b.pacingGain < 1.0 && b.bytesInFlight <= b.getTargetCongestionWindow(1) { + shouldAdvanceGainCycling = true + } + + if shouldAdvanceGainCycling { + b.cycleCurrentOffset = (b.cycleCurrentOffset + 1) % gainCycleLength + b.lastCycleStart = now + // Stay in low gain mode until the target BDP is hit. + // Low gain mode will be exited immediately when the target BDP is achieved. + if b.drainToTarget && b.pacingGain < 1 && + pacingGain[b.cycleCurrentOffset] == 1 && + b.bytesInFlight > b.getTargetCongestionWindow(1) { + return + } + b.pacingGain = pacingGain[b.cycleCurrentOffset] + } +} + +// Tracks for how many round-trips the bandwidth has not increased +// significantly. +func (b *bbrSender) checkIfFullBandwidthReached(lastPacketSendState *sendTimeState) { + if b.lastSampleIsAppLimited { + return + } + + target := Bandwidth(float64(b.bandwidthAtLastRound) * startupGrowthTarget) + if b.bandwidthEstimate() >= target { + b.bandwidthAtLastRound = b.bandwidthEstimate() + b.roundsWithoutBandwidthGain = 0 + if b.expireAckAggregationInStartup { + // Expire old excess delivery measurements now that bandwidth increased. + b.sampler.ResetMaxAckHeightTracker(0, b.roundTripCount) + } + return + } + + b.roundsWithoutBandwidthGain++ + if b.roundsWithoutBandwidthGain >= b.numStartupRtts || + b.shouldExitStartupDueToLoss(lastPacketSendState) { + b.isAtFullBandwidth = true + } +} + +func (b *bbrSender) maybeApplimited(bytesInFlight congestion.ByteCount) { + congestionWindow := b.GetCongestionWindow() + if bytesInFlight >= congestionWindow { + return + } + availableBytes := congestionWindow - bytesInFlight + drainLimited := b.mode == bbrModeDrain && bytesInFlight > congestionWindow/2 + if !drainLimited || availableBytes > maxBbrBurstPackets*b.maxDatagramSize { + b.sampler.OnAppLimited() + } +} + +// Transitions from STARTUP to DRAIN and from DRAIN to PROBE_BW if +// appropriate. +func (b *bbrSender) maybeExitStartupOrDrain(now time.Time) { + if b.mode == bbrModeStartup && b.isAtFullBandwidth { + b.mode = bbrModeDrain + // b.maybeTraceStateChange(logging.CongestionStateDrain) + b.pacingGain = b.drainGain + b.congestionWindowGain = b.highCwndGain + } + if b.mode == bbrModeDrain && b.bytesInFlight <= b.getTargetCongestionWindow(1) { + b.enterProbeBandwidthMode(now) + } +} + +// Decides whether to enter or exit PROBE_RTT. +func (b *bbrSender) maybeEnterOrExitProbeRtt(now time.Time, isRoundStart, minRttExpired bool) { + if minRttExpired && !b.exitingQuiescence && b.mode != bbrModeProbeRtt { + b.mode = bbrModeProbeRtt + // b.maybeTraceStateChange(logging.CongestionStateProbRtt) + b.pacingGain = 1.0 + // Do not decide on the time to exit PROBE_RTT until the |bytes_in_flight| + // is at the target small value. + b.exitProbeRttAt = time.Time{} + } + + if b.mode == bbrModeProbeRtt { + b.sampler.OnAppLimited() + // b.maybeTraceStateChange(logging.CongestionStateApplicationLimited) + + if b.exitProbeRttAt.IsZero() { + // If the window has reached the appropriate size, schedule exiting + // PROBE_RTT. The CWND during PROBE_RTT is kMinimumCongestionWindow, but + // we allow an extra packet since QUIC checks CWND before sending a + // packet. + if b.bytesInFlight < b.probeRttCongestionWindow()+congestion.MaxPacketBufferSize { + b.exitProbeRttAt = now.Add(probeRttTime) + b.probeRttRoundPassed = false + } + } else { + if isRoundStart { + b.probeRttRoundPassed = true + } + if now.Sub(b.exitProbeRttAt) >= 0 && b.probeRttRoundPassed { + b.minRttTimestamp = now + if !b.isAtFullBandwidth { + b.enterStartupMode(now) + } else { + b.enterProbeBandwidthMode(now) + } + } + } + } + + b.exitingQuiescence = false +} + +// Determines whether BBR needs to enter, exit or advance state of the +// recovery. +func (b *bbrSender) updateRecoveryState(lastAckedPacket congestion.PacketNumber, hasLosses, isRoundStart bool) { + // Disable recovery in startup, if loss-based exit is enabled. + if !b.isAtFullBandwidth { + return + } + + // Exit recovery when there are no losses for a round. + if hasLosses { + b.endRecoveryAt = b.lastSentPacket + } + + switch b.recoveryState { + case bbrRecoveryStateNotInRecovery: + if hasLosses { + b.recoveryState = bbrRecoveryStateConservation + // This will cause the |recovery_window_| to be set to the correct + // value in CalculateRecoveryWindow(). + b.recoveryWindow = 0 + // Since the conservation phase is meant to be lasting for a whole + // round, extend the current round as if it were started right now. + b.currentRoundTripEnd = b.lastSentPacket + } + case bbrRecoveryStateConservation: + if isRoundStart { + b.recoveryState = bbrRecoveryStateGrowth + } + fallthrough + case bbrRecoveryStateGrowth: + // Exit recovery if appropriate. + if !hasLosses && lastAckedPacket > b.endRecoveryAt { + b.recoveryState = bbrRecoveryStateNotInRecovery + } + } +} + +// Determines the appropriate pacing rate for the connection. +func (b *bbrSender) calculatePacingRate(bytesLost congestion.ByteCount) { + if b.bandwidthEstimate() == 0 { + return + } + + targetRate := Bandwidth(b.pacingGain * float64(b.bandwidthEstimate())) + if b.isAtFullBandwidth { + b.pacingRate = targetRate + return + } + + // Pace at the rate of initial_window / RTT as soon as RTT measurements are + // available. + if b.pacingRate == 0 && b.rttStats.MinRTT() != 0 { + b.pacingRate = BandwidthFromDelta(b.initialCongestionWindow, b.rttStats.MinRTT()) + return + } + + if b.detectOvershooting { + b.bytesLostWhileDetectingOvershooting += bytesLost + // Check for overshooting with network parameters adjusted when pacing rate + // > target_rate and loss has been detected. + if b.pacingRate > targetRate && b.bytesLostWhileDetectingOvershooting > 0 { + if b.hasNoAppLimitedSample || + b.bytesLostWhileDetectingOvershooting*congestion.ByteCount(b.bytesLostMultiplierWhileDetectingOvershooting) > b.initialCongestionWindow { + // We are fairly sure overshoot happens if 1) there is at least one + // non app-limited bw sample or 2) half of IW gets lost. Slow pacing + // rate. + b.pacingRate = Max(targetRate, BandwidthFromDelta(b.cwndToCalculateMinPacingRate, b.rttStats.MinRTT())) + b.bytesLostWhileDetectingOvershooting = 0 + b.detectOvershooting = false + } + } + } + + // Do not decrease the pacing rate during startup. + b.pacingRate = Max(b.pacingRate, targetRate) +} + +// Determines the appropriate congestion window for the connection. +func (b *bbrSender) calculateCongestionWindow(bytesAcked, excessAcked congestion.ByteCount) { + if b.mode == bbrModeProbeRtt { + return + } + + targetWindow := b.getTargetCongestionWindow(b.congestionWindowGain) + if b.isAtFullBandwidth { + // Add the max recently measured ack aggregation to CWND. + targetWindow += b.sampler.MaxAckHeight() + } else if b.enableAckAggregationDuringStartup { + // Add the most recent excess acked. Because CWND never decreases in + // STARTUP, this will automatically create a very localized max filter. + targetWindow += excessAcked + } + + // Instead of immediately setting the target CWND as the new one, BBR grows + // the CWND towards |target_window| by only increasing it |bytes_acked| at a + // time. + if b.isAtFullBandwidth { + b.congestionWindow = Min(targetWindow, b.congestionWindow+bytesAcked) + } else if b.congestionWindow < targetWindow || + b.sampler.TotalBytesAcked() < b.initialCongestionWindow { + // If the connection is not yet out of startup phase, do not decrease the + // window. + b.congestionWindow += bytesAcked + } + + // Enforce the limits on the congestion window. + b.congestionWindow = Max(b.congestionWindow, b.minCongestionWindow) + b.congestionWindow = Min(b.congestionWindow, b.maxCongestionWindow) +} + +// Determines the appropriate window that constrains the in-flight during recovery. +func (b *bbrSender) calculateRecoveryWindow(bytesAcked, bytesLost congestion.ByteCount) { + if b.recoveryState == bbrRecoveryStateNotInRecovery { + return + } + + // Set up the initial recovery window. + if b.recoveryWindow == 0 { + b.recoveryWindow = b.bytesInFlight + bytesAcked + b.recoveryWindow = Max(b.minCongestionWindow, b.recoveryWindow) + return + } + + // Remove losses from the recovery window, while accounting for a potential + // integer underflow. + if b.recoveryWindow >= bytesLost { + b.recoveryWindow = b.recoveryWindow - bytesLost + } else { + b.recoveryWindow = b.maxDatagramSize + } + + // In CONSERVATION mode, just subtracting losses is sufficient. In GROWTH, + // release additional |bytes_acked| to achieve a slow-start-like behavior. + if b.recoveryState == bbrRecoveryStateGrowth { + b.recoveryWindow += bytesAcked + } + + // Always allow sending at least |bytes_acked| in response. + b.recoveryWindow = Max(b.recoveryWindow, b.bytesInFlight+bytesAcked) + b.recoveryWindow = Max(b.minCongestionWindow, b.recoveryWindow) +} + +// Return whether we should exit STARTUP due to excessive loss. +func (b *bbrSender) shouldExitStartupDueToLoss(lastPacketSendState *sendTimeState) bool { + if b.numLossEventsInRound < defaultStartupFullLossCount || !lastPacketSendState.isValid { + return false + } + + inflightAtSend := lastPacketSendState.bytesInFlight + + if inflightAtSend > 0 && b.bytesLostInRound > 0 { + if b.bytesLostInRound > congestion.ByteCount(float64(inflightAtSend)*quicBbr2DefaultLossThreshold) { + return true + } + return false + } + return false +} + +func bdpFromRttAndBandwidth(rtt time.Duration, bandwidth Bandwidth) congestion.ByteCount { + return congestion.ByteCount(rtt) * congestion.ByteCount(bandwidth) / congestion.ByteCount(BytesPerSecond) / congestion.ByteCount(time.Second) +} + +func GetInitialPacketSize(addr net.Addr) congestion.ByteCount { + // If this is not a UDP address, we don't know anything about the MTU. + // Use the minimum size of an Initial packet as the max packet size. + if udpAddr, ok := addr.(*net.UDPAddr); ok { + if udpAddr.IP.To4() != nil { + return congestion.InitialPacketSizeIPv4 + } else { + return congestion.InitialPacketSizeIPv6 + } + } else { + return congestion.MinInitialPacketSize + } +} diff --git a/transport/tuic/congestion_v2/clock.go b/transport/tuic/congestion_v2/clock.go new file mode 100644 index 00000000..405fae70 --- /dev/null +++ b/transport/tuic/congestion_v2/clock.go @@ -0,0 +1,18 @@ +package congestion + +import "time" + +// A Clock returns the current time +type Clock interface { + Now() time.Time +} + +// DefaultClock implements the Clock interface using the Go stdlib clock. +type DefaultClock struct{} + +var _ Clock = DefaultClock{} + +// Now gets the current time +func (DefaultClock) Now() time.Time { + return time.Now() +} diff --git a/transport/tuic/congestion_v2/minmax_go120.go b/transport/tuic/congestion_v2/minmax_go120.go new file mode 100644 index 00000000..1266edbc --- /dev/null +++ b/transport/tuic/congestion_v2/minmax_go120.go @@ -0,0 +1,19 @@ +//go:build !go1.21 + +package congestion + +import "golang.org/x/exp/constraints" + +func Max[T constraints.Ordered](a, b T) T { + if a < b { + return b + } + return a +} + +func Min[T constraints.Ordered](a, b T) T { + if a < b { + return a + } + return b +} diff --git a/transport/tuic/congestion_v2/minmax_go121.go b/transport/tuic/congestion_v2/minmax_go121.go new file mode 100644 index 00000000..65b06726 --- /dev/null +++ b/transport/tuic/congestion_v2/minmax_go121.go @@ -0,0 +1,13 @@ +//go:build go1.21 + +package congestion + +import "cmp" + +func Max[T cmp.Ordered](a, b T) T { + return max(a, b) +} + +func Min[T cmp.Ordered](a, b T) T { + return min(a, b) +} diff --git a/transport/tuic/congestion_v2/pacer.go b/transport/tuic/congestion_v2/pacer.go new file mode 100644 index 00000000..ba4ca138 --- /dev/null +++ b/transport/tuic/congestion_v2/pacer.go @@ -0,0 +1,71 @@ +package congestion + +import ( + "math" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +const ( + maxBurstPackets = 10 +) + +// Pacer implements a token bucket pacing algorithm. +type Pacer struct { + budgetAtLastSent congestion.ByteCount + maxDatagramSize congestion.ByteCount + lastSentTime time.Time + getBandwidth func() congestion.ByteCount // in bytes/s +} + +func NewPacer(getBandwidth func() congestion.ByteCount) *Pacer { + p := &Pacer{ + budgetAtLastSent: maxBurstPackets * congestion.InitialPacketSizeIPv4, + maxDatagramSize: congestion.InitialPacketSizeIPv4, + getBandwidth: getBandwidth, + } + return p +} + +func (p *Pacer) SentPacket(sendTime time.Time, size congestion.ByteCount) { + budget := p.Budget(sendTime) + if size > budget { + p.budgetAtLastSent = 0 + } else { + p.budgetAtLastSent = budget - size + } + p.lastSentTime = sendTime +} + +func (p *Pacer) Budget(now time.Time) congestion.ByteCount { + if p.lastSentTime.IsZero() { + return p.maxBurstSize() + } + budget := p.budgetAtLastSent + (p.getBandwidth()*congestion.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9 + return Min(p.maxBurstSize(), budget) +} + +func (p *Pacer) maxBurstSize() congestion.ByteCount { + return Max( + congestion.ByteCount((congestion.MinPacingDelay+time.Millisecond).Nanoseconds())*p.getBandwidth()/1e9, + maxBurstPackets*p.maxDatagramSize, + ) +} + +// TimeUntilSend returns when the next packet should be sent. +// It returns the zero value of time.Time if a packet can be sent immediately. +func (p *Pacer) TimeUntilSend() time.Time { + if p.budgetAtLastSent >= p.maxDatagramSize { + return time.Time{} + } + return p.lastSentTime.Add(Max( + congestion.MinPacingDelay, + time.Duration(math.Ceil(float64(p.maxDatagramSize-p.budgetAtLastSent)*1e9/ + float64(p.getBandwidth())))*time.Nanosecond, + )) +} + +func (p *Pacer) SetMaxDatagramSize(s congestion.ByteCount) { + p.maxDatagramSize = s +} diff --git a/transport/tuic/congestion_v2/packet_number_indexed_queue.go b/transport/tuic/congestion_v2/packet_number_indexed_queue.go new file mode 100644 index 00000000..119d36f6 --- /dev/null +++ b/transport/tuic/congestion_v2/packet_number_indexed_queue.go @@ -0,0 +1,199 @@ +package congestion + +import ( + "github.com/metacubex/quic-go/congestion" +) + +// packetNumberIndexedQueue is a queue of mostly continuous numbered entries +// which supports the following operations: +// - adding elements to the end of the queue, or at some point past the end +// - removing elements in any order +// - retrieving elements +// If all elements are inserted in order, all of the operations above are +// amortized O(1) time. +// +// Internally, the data structure is a deque where each element is marked as +// present or not. The deque starts at the lowest present index. Whenever an +// element is removed, it's marked as not present, and the front of the deque is +// cleared of elements that are not present. +// +// The tail of the queue is not cleared due to the assumption of entries being +// inserted in order, though removing all elements of the queue will return it +// to its initial state. +// +// Note that this data structure is inherently hazardous, since an addition of +// just two entries will cause it to consume all of the memory available. +// Because of that, it is not a general-purpose container and should not be used +// as one. + +type entryWrapper[T any] struct { + present bool + entry T +} + +type packetNumberIndexedQueue[T any] struct { + entries RingBuffer[entryWrapper[T]] + numberOfPresentEntries int + firstPacket congestion.PacketNumber +} + +func newPacketNumberIndexedQueue[T any](size int) *packetNumberIndexedQueue[T] { + q := &packetNumberIndexedQueue[T]{ + firstPacket: invalidPacketNumber, + } + + q.entries.Init(size) + + return q +} + +// Emplace inserts data associated |packet_number| into (or past) the end of the +// queue, filling up the missing intermediate entries as necessary. Returns +// true if the element has been inserted successfully, false if it was already +// in the queue or inserted out of order. +func (p *packetNumberIndexedQueue[T]) Emplace(packetNumber congestion.PacketNumber, entry *T) bool { + if packetNumber == invalidPacketNumber || entry == nil { + return false + } + + if p.IsEmpty() { + p.entries.PushBack(entryWrapper[T]{ + present: true, + entry: *entry, + }) + p.numberOfPresentEntries = 1 + p.firstPacket = packetNumber + return true + } + + // Do not allow insertion out-of-order. + if packetNumber <= p.LastPacket() { + return false + } + + // Handle potentially missing elements. + offset := int(packetNumber - p.FirstPacket()) + if gap := offset - p.entries.Len(); gap > 0 { + for i := 0; i < gap; i++ { + p.entries.PushBack(entryWrapper[T]{}) + } + } + + p.entries.PushBack(entryWrapper[T]{ + present: true, + entry: *entry, + }) + p.numberOfPresentEntries++ + return true +} + +// GetEntry Retrieve the entry associated with the packet number. Returns the pointer +// to the entry in case of success, or nullptr if the entry does not exist. +func (p *packetNumberIndexedQueue[T]) GetEntry(packetNumber congestion.PacketNumber) *T { + ew := p.getEntryWraper(packetNumber) + if ew == nil { + return nil + } + + return &ew.entry +} + +// Remove, Same as above, but if an entry is present in the queue, also call f(entry) +// before removing it. +func (p *packetNumberIndexedQueue[T]) Remove(packetNumber congestion.PacketNumber, f func(T)) bool { + ew := p.getEntryWraper(packetNumber) + if ew == nil { + return false + } + if f != nil { + f(ew.entry) + } + ew.present = false + p.numberOfPresentEntries-- + + if packetNumber == p.FirstPacket() { + p.clearup() + } + + return true +} + +// RemoveUpTo, but not including |packet_number|. +// Unused slots in the front are also removed, which means when the function +// returns, |first_packet()| can be larger than |packet_number|. +func (p *packetNumberIndexedQueue[T]) RemoveUpTo(packetNumber congestion.PacketNumber) { + for !p.entries.Empty() && + p.firstPacket != invalidPacketNumber && + p.firstPacket < packetNumber { + if p.entries.Front().present { + p.numberOfPresentEntries-- + } + p.entries.PopFront() + p.firstPacket++ + } + p.clearup() + + return +} + +// IsEmpty return if queue is empty. +func (p *packetNumberIndexedQueue[T]) IsEmpty() bool { + return p.numberOfPresentEntries == 0 +} + +// NumberOfPresentEntries returns the number of entries in the queue. +func (p *packetNumberIndexedQueue[T]) NumberOfPresentEntries() int { + return p.numberOfPresentEntries +} + +// EntrySlotsUsed returns the number of entries allocated in the underlying deque. This is +// proportional to the memory usage of the queue. +func (p *packetNumberIndexedQueue[T]) EntrySlotsUsed() int { + return p.entries.Len() +} + +// LastPacket returns packet number of the first entry in the queue. +func (p *packetNumberIndexedQueue[T]) FirstPacket() (packetNumber congestion.PacketNumber) { + return p.firstPacket +} + +// LastPacket returns packet number of the last entry ever inserted in the queue. Note that the +// entry in question may have already been removed. Zero if the queue is +// empty. +func (p *packetNumberIndexedQueue[T]) LastPacket() (packetNumber congestion.PacketNumber) { + if p.IsEmpty() { + return invalidPacketNumber + } + + return p.firstPacket + congestion.PacketNumber(p.entries.Len()-1) +} + +func (p *packetNumberIndexedQueue[T]) clearup() { + for !p.entries.Empty() && !p.entries.Front().present { + p.entries.PopFront() + p.firstPacket++ + } + if p.entries.Empty() { + p.firstPacket = invalidPacketNumber + } +} + +func (p *packetNumberIndexedQueue[T]) getEntryWraper(packetNumber congestion.PacketNumber) *entryWrapper[T] { + if packetNumber == invalidPacketNumber || + p.IsEmpty() || + packetNumber < p.firstPacket { + return nil + } + + offset := int(packetNumber - p.firstPacket) + if offset >= p.entries.Len() { + return nil + } + + ew := p.entries.Offset(offset) + if ew == nil || !ew.present { + return nil + } + + return ew +} diff --git a/transport/tuic/congestion_v2/ringbuffer.go b/transport/tuic/congestion_v2/ringbuffer.go new file mode 100644 index 00000000..e110c00f --- /dev/null +++ b/transport/tuic/congestion_v2/ringbuffer.go @@ -0,0 +1,118 @@ +package congestion + +// A RingBuffer is a ring buffer. +// It acts as a heap that doesn't cause any allocations. +type RingBuffer[T any] struct { + ring []T + headPos, tailPos int + full bool +} + +// Init preallocs a buffer with a certain size. +func (r *RingBuffer[T]) Init(size int) { + r.ring = make([]T, size) +} + +// Len returns the number of elements in the ring buffer. +func (r *RingBuffer[T]) Len() int { + if r.full { + return len(r.ring) + } + if r.tailPos >= r.headPos { + return r.tailPos - r.headPos + } + return r.tailPos - r.headPos + len(r.ring) +} + +// Empty says if the ring buffer is empty. +func (r *RingBuffer[T]) Empty() bool { + return !r.full && r.headPos == r.tailPos +} + +// PushBack adds a new element. +// If the ring buffer is full, its capacity is increased first. +func (r *RingBuffer[T]) PushBack(t T) { + if r.full || len(r.ring) == 0 { + r.grow() + } + r.ring[r.tailPos] = t + r.tailPos++ + if r.tailPos == len(r.ring) { + r.tailPos = 0 + } + if r.tailPos == r.headPos { + r.full = true + } +} + +// PopFront returns the next element. +// It must not be called when the buffer is empty, that means that +// callers might need to check if there are elements in the buffer first. +func (r *RingBuffer[T]) PopFront() T { + if r.Empty() { + panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: pop from an empty queue") + } + r.full = false + t := r.ring[r.headPos] + r.ring[r.headPos] = *new(T) + r.headPos++ + if r.headPos == len(r.ring) { + r.headPos = 0 + } + return t +} + +// Offset returns the offset element. +// It must not be called when the buffer is empty, that means that +// callers might need to check if there are elements in the buffer first +// and check if the index larger than buffer length. +func (r *RingBuffer[T]) Offset(index int) *T { + if r.Empty() || index >= r.Len() { + panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: offset from invalid index") + } + offset := (r.headPos + index) % len(r.ring) + return &r.ring[offset] +} + +// Front returns the front element. +// It must not be called when the buffer is empty, that means that +// callers might need to check if there are elements in the buffer first. +func (r *RingBuffer[T]) Front() *T { + if r.Empty() { + panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: front from an empty queue") + } + return &r.ring[r.headPos] +} + +// Back returns the back element. +// It must not be called when the buffer is empty, that means that +// callers might need to check if there are elements in the buffer first. +func (r *RingBuffer[T]) Back() *T { + if r.Empty() { + panic("github.com/quic-go/quic-go/internal/utils/ringbuffer: back from an empty queue") + } + return r.Offset(r.Len() - 1) +} + +// Grow the maximum size of the queue. +// This method assume the queue is full. +func (r *RingBuffer[T]) grow() { + oldRing := r.ring + newSize := len(oldRing) * 2 + if newSize == 0 { + newSize = 1 + } + r.ring = make([]T, newSize) + headLen := copy(r.ring, oldRing[r.headPos:]) + copy(r.ring[headLen:], oldRing[:r.headPos]) + r.headPos, r.tailPos, r.full = 0, len(oldRing), false +} + +// Clear removes all elements. +func (r *RingBuffer[T]) Clear() { + var zeroValue T + for i := range r.ring { + r.ring[i] = zeroValue + } + r.headPos, r.tailPos, r.full = 0, 0, false +} diff --git a/transport/tuic/congestion_v2/windowed_filter.go b/transport/tuic/congestion_v2/windowed_filter.go new file mode 100644 index 00000000..2421b48b --- /dev/null +++ b/transport/tuic/congestion_v2/windowed_filter.go @@ -0,0 +1,162 @@ +package congestion + +import ( + "golang.org/x/exp/constraints" +) + +// Implements Kathleen Nichols' algorithm for tracking the minimum (or maximum) +// estimate of a stream of samples over some fixed time interval. (E.g., +// the minimum RTT over the past five minutes.) The algorithm keeps track of +// the best, second best, and third best min (or max) estimates, maintaining an +// invariant that the measurement time of the n'th best >= n-1'th best. + +// The algorithm works as follows. On a reset, all three estimates are set to +// the same sample. The second best estimate is then recorded in the second +// quarter of the window, and a third best estimate is recorded in the second +// half of the window, bounding the worst case error when the true min is +// monotonically increasing (or true max is monotonically decreasing) over the +// window. +// +// A new best sample replaces all three estimates, since the new best is lower +// (or higher) than everything else in the window and it is the most recent. +// The window thus effectively gets reset on every new min. The same property +// holds true for second best and third best estimates. Specifically, when a +// sample arrives that is better than the second best but not better than the +// best, it replaces the second and third best estimates but not the best +// estimate. Similarly, a sample that is better than the third best estimate +// but not the other estimates replaces only the third best estimate. +// +// Finally, when the best expires, it is replaced by the second best, which in +// turn is replaced by the third best. The newest sample replaces the third +// best. + +type WindowedFilterValue interface { + any +} + +type WindowedFilterTime interface { + constraints.Integer | constraints.Float +} + +type WindowedFilter[V WindowedFilterValue, T WindowedFilterTime] struct { + // Time length of window. + windowLength T + estimates []entry[V, T] + comparator func(V, V) int +} + +type entry[V WindowedFilterValue, T WindowedFilterTime] struct { + sample V + time T +} + +// Compares two values and returns true if the first is greater than or equal +// to the second. +func MaxFilter[O constraints.Ordered](a, b O) int { + if a > b { + return 1 + } else if a < b { + return -1 + } + return 0 +} + +// Compares two values and returns true if the first is less than or equal +// to the second. +func MinFilter[O constraints.Ordered](a, b O) int { + if a < b { + return 1 + } else if a > b { + return -1 + } + return 0 +} + +func NewWindowedFilter[V WindowedFilterValue, T WindowedFilterTime](windowLength T, comparator func(V, V) int) *WindowedFilter[V, T] { + return &WindowedFilter[V, T]{ + windowLength: windowLength, + estimates: make([]entry[V, T], 3, 3), + comparator: comparator, + } +} + +// Changes the window length. Does not update any current samples. +func (f *WindowedFilter[V, T]) SetWindowLength(windowLength T) { + f.windowLength = windowLength +} + +func (f *WindowedFilter[V, T]) GetBest() V { + return f.estimates[0].sample +} + +func (f *WindowedFilter[V, T]) GetSecondBest() V { + return f.estimates[1].sample +} + +func (f *WindowedFilter[V, T]) GetThirdBest() V { + return f.estimates[2].sample +} + +// Updates best estimates with |sample|, and expires and updates best +// estimates as necessary. +func (f *WindowedFilter[V, T]) Update(newSample V, newTime T) { + // Reset all estimates if they have not yet been initialized, if new sample + // is a new best, or if the newest recorded estimate is too old. + if f.comparator(f.estimates[0].sample, *new(V)) == 0 || + f.comparator(newSample, f.estimates[0].sample) >= 0 || + newTime-f.estimates[2].time > f.windowLength { + f.Reset(newSample, newTime) + return + } + + if f.comparator(newSample, f.estimates[1].sample) >= 0 { + f.estimates[1] = entry[V, T]{newSample, newTime} + f.estimates[2] = f.estimates[1] + } else if f.comparator(newSample, f.estimates[2].sample) >= 0 { + f.estimates[2] = entry[V, T]{newSample, newTime} + } + + // Expire and update estimates as necessary. + if newTime-f.estimates[0].time > f.windowLength { + // The best estimate hasn't been updated for an entire window, so promote + // second and third best estimates. + f.estimates[0] = f.estimates[1] + f.estimates[1] = f.estimates[2] + f.estimates[2] = entry[V, T]{newSample, newTime} + // Need to iterate one more time. Check if the new best estimate is + // outside the window as well, since it may also have been recorded a + // long time ago. Don't need to iterate once more since we cover that + // case at the beginning of the method. + if newTime-f.estimates[0].time > f.windowLength { + f.estimates[0] = f.estimates[1] + f.estimates[1] = f.estimates[2] + } + return + } + if f.comparator(f.estimates[1].sample, f.estimates[0].sample) == 0 && + newTime-f.estimates[1].time > f.windowLength/4 { + // A quarter of the window has passed without a better sample, so the + // second-best estimate is taken from the second quarter of the window. + f.estimates[1] = entry[V, T]{newSample, newTime} + f.estimates[2] = f.estimates[1] + return + } + + if f.comparator(f.estimates[2].sample, f.estimates[1].sample) == 0 && + newTime-f.estimates[2].time > f.windowLength/2 { + // We've passed a half of the window without a better estimate, so take + // a third-best estimate from the second half of the window. + f.estimates[2] = entry[V, T]{newSample, newTime} + } +} + +// Resets all estimates to new sample. +func (f *WindowedFilter[V, T]) Reset(newSample V, newTime T) { + f.estimates[2] = entry[V, T]{newSample, newTime} + f.estimates[1] = f.estimates[2] + f.estimates[0] = f.estimates[1] +} + +func (f *WindowedFilter[V, T]) Clear() { + f.estimates = make([]entry[V, T], 3, 3) +} From 8253bfe2e00c22a5b81de866b0ae757e18efe15b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 1 Oct 2023 09:10:11 +0800 Subject: [PATCH 462/530] add `quic-go-disable-ecn` to experimental --- config/config.go | 1 + hub/executor/executor.go | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/config/config.go b/config/config.go index e240f9b9..5ea45a39 100644 --- a/config/config.go +++ b/config/config.go @@ -159,6 +159,7 @@ type Sniffer struct { type Experimental struct { Fingerprints []string `yaml:"fingerprints"` QUICGoDisableGSO bool `yaml:"quic-go-disable-gso"` + QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"` } // Config is clash config manager diff --git a/hub/executor/executor.go b/hub/executor/executor.go index a50d3539..ebcbac91 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -180,7 +180,10 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList func updateExperimental(c *config.Config) { if c.Experimental.QUICGoDisableGSO { - _ = os.Setenv("QUIC_GO_DISABLE_GSO", "1") + _ = os.Setenv("QUIC_GO_DISABLE_GSO", strconv.FormatBool(true)) + } + if c.Experimental.QUICGoDisableECN { + _ = os.Setenv("QUIC_GO_DISABLE_ECN", strconv.FormatBool(true)) } } From dbaee284e4310aea71344f5154b174bd0333b657 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 1 Oct 2023 12:04:34 +0800 Subject: [PATCH 463/530] fix: hy2/tuic inbound cert isn't path Co-authored-by: wwqgtxx --- common/net/tls.go | 8 +++++++- hub/route/server.go | 2 +- listener/sing_hysteria2/server.go | 5 +---- listener/tuic/server.go | 5 +---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/common/net/tls.go b/common/net/tls.go index e51324f7..b2865503 100644 --- a/common/net/tls.go +++ b/common/net/tls.go @@ -10,7 +10,11 @@ import ( "math/big" ) -func ParseCert(certificate, privateKey string) (tls.Certificate, error) { +type Path interface { + Resolve(path string) string +} + +func ParseCert(certificate, privateKey string, path Path) (tls.Certificate, error) { if certificate == "" && privateKey == "" { return newRandomTLSKeyPair() } @@ -19,6 +23,8 @@ func ParseCert(certificate, privateKey string) (tls.Certificate, error) { return cert, nil } + certificate = path.Resolve(certificate) + privateKey = path.Resolve(privateKey) cert, loadErr := tls.LoadX509KeyPair(certificate, privateKey) if loadErr != nil { return tls.Certificate{}, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error()) diff --git a/hub/route/server.go b/hub/route/server.go index 3d0df95e..aa2d03b8 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -112,7 +112,7 @@ func Start(addr string, tlsAddr string, secret string, if len(tlsAddr) > 0 { go func() { - c, err := CN.ParseCert(certificat, privateKey) + c, err := CN.ParseCert(certificat, privateKey, C.Path) if err != nil { log.Errorln("External controller tls listen error: %s", err) return diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index 7897bd84..bc25ec2a 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -50,10 +50,7 @@ func New(config LC.Hysteria2Server, tunnel C.Tunnel, additions ...inbound.Additi sl = &Listener{false, config, nil, nil} - config.Certificate = C.Path.Resolve(config.Certificate) - config.PrivateKey = C.Path.Resolve(config.PrivateKey) - - cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) + cert, err := CN.ParseCert(config.Certificate, config.PrivateKey, C.Path) if err != nil { return nil, err } diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 12a6ac6d..70cf4a01 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -44,10 +44,7 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( Additions: additions, } - config.Certificate = C.Path.Resolve(config.Certificate) - config.PrivateKey = C.Path.Resolve(config.PrivateKey) - - cert, err := CN.ParseCert(config.Certificate, config.PrivateKey) + cert, err := CN.ParseCert(config.Certificate, config.PrivateKey, C.Path) if err != nil { return nil, err } From 4e3cd01aadff90adcd2ee5f68c007d53b3bcc31d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 1 Oct 2023 13:44:56 +0800 Subject: [PATCH 464/530] chore: merge some quic-go fix --- go.mod | 8 +- go.sum | 12 +- transport/hysteria/congestion/brutal.go | 4 - transport/tuic/common/congestion.go | 16 + transport/tuic/congestion/cubic.go | 213 +++++++++++++ transport/tuic/congestion/cubic_sender.go | 297 ++++++++++++++++++ .../tuic/congestion/hybrid_slow_start.go | 112 +++++++ transport/tuic/congestion/minmax.go | 56 ++++ 8 files changed, 704 insertions(+), 14 deletions(-) create mode 100644 transport/tuic/congestion/cubic.go create mode 100644 transport/tuic/congestion/cubic_sender.go create mode 100644 transport/tuic/congestion/hybrid_slow_start.go create mode 100644 transport/tuic/congestion/minmax.go diff --git a/go.mod b/go.mod index 826eb0ba..d1503b48 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ 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.39.1-0.20230930051114-b486c7799a55 - github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c + github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623 + github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee @@ -32,7 +32,7 @@ require ( github.com/oschwald/maxminddb-golang v1.12.0 github.com/puzpuzpuz/xsync/v2 v2.5.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.11 + github.com/sagernet/sing v0.2.12 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 @@ -105,4 +105,4 @@ require ( golang.org/x/tools v0.13.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 diff --git a/go.sum b/go.sum index d6c96aaa..3aa28a7f 100644 --- a/go.sum +++ b/go.sum @@ -93,12 +93,12 @@ 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.39.1-0.20230930051114-b486c7799a55 h1:cAqp0BFOTr/1TpFicH1dA1q/6fp7E/JkqHBORfohqr4= -github.com/metacubex/quic-go v0.39.1-0.20230930051114-b486c7799a55/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= -github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1 h1:MkYAvDyhb7cwuqL4ZLKU3Oi6tYjFnz1sz5LS82JmtDo= -github.com/metacubex/sing v0.0.0-20230926010351-b23b466642d1/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c h1:j7PKIUUhOAxJaLf/NmUKuIs9R06xNoYizwYgqf5HSrA= -github.com/metacubex/sing-quic v0.0.0-20230930052455-ae588c275b9c/go.mod h1:TPAXFCHCtzW9Dm+wq1l1R/p0v/S/xmuRU0qfPR7WlOA= +github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623 h1:lxXUXdS2GB4Ktn3ocnzQ53v1lqd6LYYfYIKICugTaJM= +github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= +github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= +github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= +github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= diff --git a/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 67067917..88bf6f34 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -100,10 +100,6 @@ func (b *BrutalSender) OnCongestionEvent(number congestion.PacketNumber, lostByt b.updateAckRate(currentTimestamp) } -func (b *BrutalSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { - // Stub -} - func (b *BrutalSender) SetMaxDatagramSize(size congestion.ByteCount) { b.maxDatagramSize = size b.pacer.SetMaxDatagramSize(size) diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index 1176ebd6..13c1300f 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -18,6 +18,22 @@ func SetCongestionController(quicConn quic.Connection, cc string, cwnd int) { cwnd = 32 } switch cc { + case "cubic": + quicConn.SetCongestionControl( + congestion.NewCubicSender( + congestion.DefaultClock{}, + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), + false, + ), + ) + case "new_reno": + quicConn.SetCongestionControl( + congestion.NewCubicSender( + congestion.DefaultClock{}, + congestion.GetInitialPacketSize(quicConn.RemoteAddr()), + true, + ), + ) case "bbr_meta_v1": quicConn.SetCongestionControl( congestion.NewBBRSender( diff --git a/transport/tuic/congestion/cubic.go b/transport/tuic/congestion/cubic.go new file mode 100644 index 00000000..dd491a32 --- /dev/null +++ b/transport/tuic/congestion/cubic.go @@ -0,0 +1,213 @@ +package congestion + +import ( + "math" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +// This cubic implementation is based on the one found in Chromiums's QUIC +// implementation, in the files net/quic/congestion_control/cubic.{hh,cc}. + +// Constants based on TCP defaults. +// The following constants are in 2^10 fractions of a second instead of ms to +// allow a 10 shift right to divide. + +// 1024*1024^3 (first 1024 is from 0.100^3) +// where 0.100 is 100 ms which is the scaling round trip time. +const ( + cubeScale = 40 + cubeCongestionWindowScale = 410 + cubeFactor congestion.ByteCount = 1 << cubeScale / cubeCongestionWindowScale / maxDatagramSize + // TODO: when re-enabling cubic, make sure to use the actual packet size here + maxDatagramSize = congestion.ByteCount(InitialPacketSizeIPv4) +) + +const defaultNumConnections = 1 + +// Default Cubic backoff factor +const beta float32 = 0.7 + +// Additional backoff factor when loss occurs in the concave part of the Cubic +// curve. This additional backoff factor is expected to give up bandwidth to +// new concurrent flows and speed up convergence. +const betaLastMax float32 = 0.85 + +// Cubic implements the cubic algorithm from TCP +type Cubic struct { + clock Clock + + // Number of connections to simulate. + numConnections int + + // Time when this cycle started, after last loss event. + epoch time.Time + + // Max congestion window used just before last loss event. + // Note: to improve fairness to other streams an additional back off is + // applied to this value if the new value is below our latest value. + lastMaxCongestionWindow congestion.ByteCount + + // Number of acked bytes since the cycle started (epoch). + ackedBytesCount congestion.ByteCount + + // TCP Reno equivalent congestion window in packets. + estimatedTCPcongestionWindow congestion.ByteCount + + // Origin point of cubic function. + originPointCongestionWindow congestion.ByteCount + + // Time to origin point of cubic function in 2^10 fractions of a second. + timeToOriginPoint uint32 + + // Last congestion window in packets computed by cubic function. + lastTargetCongestionWindow congestion.ByteCount +} + +// NewCubic returns a new Cubic instance +func NewCubic(clock Clock) *Cubic { + c := &Cubic{ + clock: clock, + numConnections: defaultNumConnections, + } + c.Reset() + return c +} + +// Reset is called after a timeout to reset the cubic state +func (c *Cubic) Reset() { + c.epoch = time.Time{} + c.lastMaxCongestionWindow = 0 + c.ackedBytesCount = 0 + c.estimatedTCPcongestionWindow = 0 + c.originPointCongestionWindow = 0 + c.timeToOriginPoint = 0 + c.lastTargetCongestionWindow = 0 +} + +func (c *Cubic) alpha() float32 { + // TCPFriendly alpha is described in Section 3.3 of the CUBIC paper. Note that + // beta here is a cwnd multiplier, and is equal to 1-beta from the paper. + // We derive the equivalent alpha for an N-connection emulation as: + b := c.beta() + return 3 * float32(c.numConnections) * float32(c.numConnections) * (1 - b) / (1 + b) +} + +func (c *Cubic) beta() float32 { + // kNConnectionBeta is the backoff factor after loss for our N-connection + // emulation, which emulates the effective backoff of an ensemble of N + // TCP-Reno connections on a single loss event. The effective multiplier is + // computed as: + return (float32(c.numConnections) - 1 + beta) / float32(c.numConnections) +} + +func (c *Cubic) betaLastMax() float32 { + // betaLastMax is the additional backoff factor after loss for our + // N-connection emulation, which emulates the additional backoff of + // an ensemble of N TCP-Reno connections on a single loss event. The + // effective multiplier is computed as: + return (float32(c.numConnections) - 1 + betaLastMax) / float32(c.numConnections) +} + +// OnApplicationLimited is called on ack arrival when sender is unable to use +// the available congestion window. Resets Cubic state during quiescence. +func (c *Cubic) OnApplicationLimited() { + // When sender is not using the available congestion window, the window does + // not grow. But to be RTT-independent, Cubic assumes that the sender has been + // using the entire window during the time since the beginning of the current + // "epoch" (the end of the last loss recovery period). Since + // application-limited periods break this assumption, we reset the epoch when + // in such a period. This reset effectively freezes congestion window growth + // through application-limited periods and allows Cubic growth to continue + // when the entire window is being used. + c.epoch = time.Time{} +} + +// CongestionWindowAfterPacketLoss computes a new congestion window to use after +// a loss event. Returns the new congestion window in packets. The new +// congestion window is a multiplicative decrease of our current window. +func (c *Cubic) CongestionWindowAfterPacketLoss(currentCongestionWindow congestion.ByteCount) congestion.ByteCount { + if currentCongestionWindow+maxDatagramSize < c.lastMaxCongestionWindow { + // We never reached the old max, so assume we are competing with another + // flow. Use our extra back off factor to allow the other flow to go up. + c.lastMaxCongestionWindow = congestion.ByteCount(c.betaLastMax() * float32(currentCongestionWindow)) + } else { + c.lastMaxCongestionWindow = currentCongestionWindow + } + c.epoch = time.Time{} // Reset time. + return congestion.ByteCount(float32(currentCongestionWindow) * c.beta()) +} + +// CongestionWindowAfterAck computes a new congestion window to use after a received ACK. +// Returns the new congestion window in packets. The new congestion window +// follows a cubic function that depends on the time passed since last +// packet loss. +func (c *Cubic) CongestionWindowAfterAck( + ackedBytes congestion.ByteCount, + currentCongestionWindow congestion.ByteCount, + delayMin time.Duration, + eventTime time.Time, +) congestion.ByteCount { + c.ackedBytesCount += ackedBytes + + if c.epoch.IsZero() { + // First ACK after a loss event. + c.epoch = eventTime // Start of epoch. + c.ackedBytesCount = ackedBytes // Reset count. + // Reset estimated_tcp_congestion_window_ to be in sync with cubic. + c.estimatedTCPcongestionWindow = currentCongestionWindow + if c.lastMaxCongestionWindow <= currentCongestionWindow { + c.timeToOriginPoint = 0 + c.originPointCongestionWindow = currentCongestionWindow + } else { + c.timeToOriginPoint = uint32(math.Cbrt(float64(cubeFactor * (c.lastMaxCongestionWindow - currentCongestionWindow)))) + c.originPointCongestionWindow = c.lastMaxCongestionWindow + } + } + + // Change the time unit from microseconds to 2^10 fractions per second. Take + // the round trip time in account. This is done to allow us to use shift as a + // divide operator. + elapsedTime := int64(eventTime.Add(delayMin).Sub(c.epoch)/time.Microsecond) << 10 / (1000 * 1000) + + // Right-shifts of negative, signed numbers have implementation-dependent + // behavior, so force the offset to be positive, as is done in the kernel. + offset := int64(c.timeToOriginPoint) - elapsedTime + if offset < 0 { + offset = -offset + } + + deltaCongestionWindow := congestion.ByteCount(cubeCongestionWindowScale*offset*offset*offset) * maxDatagramSize >> cubeScale + var targetCongestionWindow congestion.ByteCount + if elapsedTime > int64(c.timeToOriginPoint) { + targetCongestionWindow = c.originPointCongestionWindow + deltaCongestionWindow + } else { + targetCongestionWindow = c.originPointCongestionWindow - deltaCongestionWindow + } + // Limit the CWND increase to half the acked bytes. + targetCongestionWindow = Min(targetCongestionWindow, currentCongestionWindow+c.ackedBytesCount/2) + + // Increase the window by approximately Alpha * 1 MSS of bytes every + // time we ack an estimated tcp window of bytes. For small + // congestion windows (less than 25), the formula below will + // increase slightly slower than linearly per estimated tcp window + // of bytes. + c.estimatedTCPcongestionWindow += congestion.ByteCount(float32(c.ackedBytesCount) * c.alpha() * float32(maxDatagramSize) / float32(c.estimatedTCPcongestionWindow)) + c.ackedBytesCount = 0 + + // We have a new cubic congestion window. + c.lastTargetCongestionWindow = targetCongestionWindow + + // Compute target congestion_window based on cubic target and estimated TCP + // congestion_window, use highest (fastest). + if targetCongestionWindow < c.estimatedTCPcongestionWindow { + targetCongestionWindow = c.estimatedTCPcongestionWindow + } + return targetCongestionWindow +} + +// SetNumConnections sets the number of emulated connections +func (c *Cubic) SetNumConnections(n int) { + c.numConnections = n +} diff --git a/transport/tuic/congestion/cubic_sender.go b/transport/tuic/congestion/cubic_sender.go new file mode 100644 index 00000000..f544cd74 --- /dev/null +++ b/transport/tuic/congestion/cubic_sender.go @@ -0,0 +1,297 @@ +package congestion + +import ( + "fmt" + "time" + + "github.com/metacubex/quic-go/congestion" +) + +const ( + maxBurstPackets = 3 + renoBeta = 0.7 // Reno backoff factor. + minCongestionWindowPackets = 2 + initialCongestionWindow = 32 +) + +const InvalidPacketNumber congestion.PacketNumber = -1 +const MaxCongestionWindowPackets = 20000 +const MaxByteCount = congestion.ByteCount(1<<62 - 1) + +type cubicSender struct { + hybridSlowStart HybridSlowStart + rttStats congestion.RTTStatsProvider + cubic *Cubic + pacer *pacer + clock Clock + + reno bool + + // Track the largest packet that has been sent. + largestSentPacketNumber congestion.PacketNumber + + // Track the largest packet that has been acked. + largestAckedPacketNumber congestion.PacketNumber + + // Track the largest packet number outstanding when a CWND cutback occurs. + largestSentAtLastCutback congestion.PacketNumber + + // Whether the last loss event caused us to exit slowstart. + // Used for stats collection of slowstartPacketsLost + lastCutbackExitedSlowstart bool + + // Congestion window in bytes. + congestionWindow congestion.ByteCount + + // Slow start congestion window in bytes, aka ssthresh. + slowStartThreshold congestion.ByteCount + + // ACK counter for the Reno implementation. + numAckedPackets uint64 + + initialCongestionWindow congestion.ByteCount + initialMaxCongestionWindow congestion.ByteCount + + maxDatagramSize congestion.ByteCount +} + +var ( + _ congestion.CongestionControl = &cubicSender{} +) + +// NewCubicSender makes a new cubic sender +func NewCubicSender( + clock Clock, + initialMaxDatagramSize congestion.ByteCount, + reno bool, +) *cubicSender { + return newCubicSender( + clock, + reno, + initialMaxDatagramSize, + initialCongestionWindow*initialMaxDatagramSize, + MaxCongestionWindowPackets*initialMaxDatagramSize, + ) +} + +func newCubicSender( + clock Clock, + reno bool, + initialMaxDatagramSize, + initialCongestionWindow, + initialMaxCongestionWindow congestion.ByteCount, +) *cubicSender { + c := &cubicSender{ + largestSentPacketNumber: InvalidPacketNumber, + largestAckedPacketNumber: InvalidPacketNumber, + largestSentAtLastCutback: InvalidPacketNumber, + initialCongestionWindow: initialCongestionWindow, + initialMaxCongestionWindow: initialMaxCongestionWindow, + congestionWindow: initialCongestionWindow, + slowStartThreshold: MaxByteCount, + cubic: NewCubic(clock), + clock: clock, + reno: reno, + maxDatagramSize: initialMaxDatagramSize, + } + c.pacer = newPacer(c.BandwidthEstimate) + return c +} + +func (c *cubicSender) SetRTTStatsProvider(provider congestion.RTTStatsProvider) { + c.rttStats = provider +} + +// TimeUntilSend returns when the next packet should be sent. +func (c *cubicSender) TimeUntilSend(_ congestion.ByteCount) time.Time { + return c.pacer.TimeUntilSend() +} + +func (c *cubicSender) HasPacingBudget(now time.Time) bool { + return c.pacer.Budget(now) >= c.maxDatagramSize +} + +func (c *cubicSender) maxCongestionWindow() congestion.ByteCount { + return c.maxDatagramSize * MaxCongestionWindowPackets +} + +func (c *cubicSender) minCongestionWindow() congestion.ByteCount { + return c.maxDatagramSize * minCongestionWindowPackets +} + +func (c *cubicSender) OnPacketSent( + sentTime time.Time, + _ congestion.ByteCount, + packetNumber congestion.PacketNumber, + bytes congestion.ByteCount, + isRetransmittable bool, +) { + c.pacer.SentPacket(sentTime, bytes) + if !isRetransmittable { + return + } + c.largestSentPacketNumber = packetNumber + c.hybridSlowStart.OnPacketSent(packetNumber) +} + +func (c *cubicSender) CanSend(bytesInFlight congestion.ByteCount) bool { + return bytesInFlight < c.GetCongestionWindow() +} + +func (c *cubicSender) InRecovery() bool { + return c.largestAckedPacketNumber != InvalidPacketNumber && c.largestAckedPacketNumber <= c.largestSentAtLastCutback +} + +func (c *cubicSender) InSlowStart() bool { + return c.GetCongestionWindow() < c.slowStartThreshold +} + +func (c *cubicSender) GetCongestionWindow() congestion.ByteCount { + return c.congestionWindow +} + +func (c *cubicSender) MaybeExitSlowStart() { + if c.InSlowStart() && + c.hybridSlowStart.ShouldExitSlowStart(c.rttStats.LatestRTT(), c.rttStats.MinRTT(), c.GetCongestionWindow()/c.maxDatagramSize) { + // exit slow start + c.slowStartThreshold = c.congestionWindow + } +} + +func (c *cubicSender) OnPacketAcked( + ackedPacketNumber congestion.PacketNumber, + ackedBytes congestion.ByteCount, + priorInFlight congestion.ByteCount, + eventTime time.Time, +) { + c.largestAckedPacketNumber = Max(ackedPacketNumber, c.largestAckedPacketNumber) + if c.InRecovery() { + return + } + c.maybeIncreaseCwnd(ackedPacketNumber, ackedBytes, priorInFlight, eventTime) + if c.InSlowStart() { + c.hybridSlowStart.OnPacketAcked(ackedPacketNumber) + } +} + +func (c *cubicSender) OnCongestionEvent(packetNumber congestion.PacketNumber, lostBytes, priorInFlight congestion.ByteCount) { + // TCP NewReno (RFC6582) says that once a loss occurs, any losses in packets + // already sent should be treated as a single loss event, since it's expected. + if packetNumber <= c.largestSentAtLastCutback { + return + } + c.lastCutbackExitedSlowstart = c.InSlowStart() + + if c.reno { + c.congestionWindow = congestion.ByteCount(float64(c.congestionWindow) * renoBeta) + } else { + c.congestionWindow = c.cubic.CongestionWindowAfterPacketLoss(c.congestionWindow) + } + if minCwnd := c.minCongestionWindow(); c.congestionWindow < minCwnd { + c.congestionWindow = minCwnd + } + c.slowStartThreshold = c.congestionWindow + c.largestSentAtLastCutback = c.largestSentPacketNumber + // reset packet count from congestion avoidance mode. We start + // counting again when we're out of recovery. + c.numAckedPackets = 0 +} + +func (b *cubicSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + // Stub +} + +// Called when we receive an ack. Normal TCP tracks how many packets one ack +// represents, but quic has a separate ack for each packet. +func (c *cubicSender) maybeIncreaseCwnd( + _ congestion.PacketNumber, + ackedBytes congestion.ByteCount, + priorInFlight congestion.ByteCount, + eventTime time.Time, +) { + // Do not increase the congestion window unless the sender is close to using + // the current window. + if !c.isCwndLimited(priorInFlight) { + c.cubic.OnApplicationLimited() + return + } + if c.congestionWindow >= c.maxCongestionWindow() { + return + } + if c.InSlowStart() { + // TCP slow start, exponential growth, increase by one for each ACK. + c.congestionWindow += c.maxDatagramSize + return + } + // Congestion avoidance + if c.reno { + // Classic Reno congestion avoidance. + c.numAckedPackets++ + if c.numAckedPackets >= uint64(c.congestionWindow/c.maxDatagramSize) { + c.congestionWindow += c.maxDatagramSize + c.numAckedPackets = 0 + } + } else { + c.congestionWindow = Min(c.maxCongestionWindow(), c.cubic.CongestionWindowAfterAck(ackedBytes, c.congestionWindow, c.rttStats.MinRTT(), eventTime)) + } +} + +func (c *cubicSender) isCwndLimited(bytesInFlight congestion.ByteCount) bool { + congestionWindow := c.GetCongestionWindow() + if bytesInFlight >= congestionWindow { + return true + } + availableBytes := congestionWindow - bytesInFlight + slowStartLimited := c.InSlowStart() && bytesInFlight > congestionWindow/2 + return slowStartLimited || availableBytes <= maxBurstPackets*c.maxDatagramSize +} + +// BandwidthEstimate returns the current bandwidth estimate +func (c *cubicSender) BandwidthEstimate() Bandwidth { + if c.rttStats == nil { + return infBandwidth + } + srtt := c.rttStats.SmoothedRTT() + if srtt == 0 { + // If we haven't measured an rtt, the bandwidth estimate is unknown. + return infBandwidth + } + return BandwidthFromDelta(c.GetCongestionWindow(), srtt) +} + +// OnRetransmissionTimeout is called on an retransmission timeout +func (c *cubicSender) OnRetransmissionTimeout(packetsRetransmitted bool) { + c.largestSentAtLastCutback = InvalidPacketNumber + if !packetsRetransmitted { + return + } + c.hybridSlowStart.Restart() + c.cubic.Reset() + c.slowStartThreshold = c.congestionWindow / 2 + c.congestionWindow = c.minCongestionWindow() +} + +// OnConnectionMigration is called when the connection is migrated (?) +func (c *cubicSender) OnConnectionMigration() { + c.hybridSlowStart.Restart() + c.largestSentPacketNumber = InvalidPacketNumber + c.largestAckedPacketNumber = InvalidPacketNumber + c.largestSentAtLastCutback = InvalidPacketNumber + c.lastCutbackExitedSlowstart = false + c.cubic.Reset() + c.numAckedPackets = 0 + c.congestionWindow = c.initialCongestionWindow + c.slowStartThreshold = c.initialMaxCongestionWindow +} + +func (c *cubicSender) SetMaxDatagramSize(s congestion.ByteCount) { + if s < c.maxDatagramSize { + panic(fmt.Sprintf("congestion BUG: decreased max datagram size from %d to %d", c.maxDatagramSize, s)) + } + cwndIsMinCwnd := c.congestionWindow == c.minCongestionWindow() + c.maxDatagramSize = s + if cwndIsMinCwnd { + c.congestionWindow = c.minCongestionWindow() + } + c.pacer.SetMaxDatagramSize(s) +} diff --git a/transport/tuic/congestion/hybrid_slow_start.go b/transport/tuic/congestion/hybrid_slow_start.go new file mode 100644 index 00000000..7586774e --- /dev/null +++ b/transport/tuic/congestion/hybrid_slow_start.go @@ -0,0 +1,112 @@ +package congestion + +import ( + "time" + + "github.com/metacubex/quic-go/congestion" +) + +// Note(pwestin): the magic clamping numbers come from the original code in +// tcp_cubic.c. +const hybridStartLowWindow = congestion.ByteCount(16) + +// Number of delay samples for detecting the increase of delay. +const hybridStartMinSamples = uint32(8) + +// Exit slow start if the min rtt has increased by more than 1/8th. +const hybridStartDelayFactorExp = 3 // 2^3 = 8 +// The original paper specifies 2 and 8ms, but those have changed over time. +const ( + hybridStartDelayMinThresholdUs = int64(4000) + hybridStartDelayMaxThresholdUs = int64(16000) +) + +// HybridSlowStart implements the TCP hybrid slow start algorithm +type HybridSlowStart struct { + endPacketNumber congestion.PacketNumber + lastSentPacketNumber congestion.PacketNumber + started bool + currentMinRTT time.Duration + rttSampleCount uint32 + hystartFound bool +} + +// StartReceiveRound is called for the start of each receive round (burst) in the slow start phase. +func (s *HybridSlowStart) StartReceiveRound(lastSent congestion.PacketNumber) { + s.endPacketNumber = lastSent + s.currentMinRTT = 0 + s.rttSampleCount = 0 + s.started = true +} + +// IsEndOfRound returns true if this ack is the last packet number of our current slow start round. +func (s *HybridSlowStart) IsEndOfRound(ack congestion.PacketNumber) bool { + return s.endPacketNumber < ack +} + +// ShouldExitSlowStart should be called on every new ack frame, since a new +// RTT measurement can be made then. +// rtt: the RTT for this ack packet. +// minRTT: is the lowest delay (RTT) we have seen during the session. +// congestionWindow: the congestion window in packets. +func (s *HybridSlowStart) ShouldExitSlowStart(latestRTT time.Duration, minRTT time.Duration, congestionWindow congestion.ByteCount) bool { + if !s.started { + // Time to start the hybrid slow start. + s.StartReceiveRound(s.lastSentPacketNumber) + } + if s.hystartFound { + return true + } + // Second detection parameter - delay increase detection. + // Compare the minimum delay (s.currentMinRTT) of the current + // burst of packets relative to the minimum delay during the session. + // Note: we only look at the first few(8) packets in each burst, since we + // only want to compare the lowest RTT of the burst relative to previous + // bursts. + s.rttSampleCount++ + if s.rttSampleCount <= hybridStartMinSamples { + if s.currentMinRTT == 0 || s.currentMinRTT > latestRTT { + s.currentMinRTT = latestRTT + } + } + // We only need to check this once per round. + if s.rttSampleCount == hybridStartMinSamples { + // Divide minRTT by 8 to get a rtt increase threshold for exiting. + minRTTincreaseThresholdUs := int64(minRTT / time.Microsecond >> hybridStartDelayFactorExp) + // Ensure the rtt threshold is never less than 2ms or more than 16ms. + minRTTincreaseThresholdUs = Min(minRTTincreaseThresholdUs, hybridStartDelayMaxThresholdUs) + minRTTincreaseThreshold := time.Duration(Max(minRTTincreaseThresholdUs, hybridStartDelayMinThresholdUs)) * time.Microsecond + + if s.currentMinRTT > (minRTT + minRTTincreaseThreshold) { + s.hystartFound = true + } + } + // Exit from slow start if the cwnd is greater than 16 and + // increasing delay is found. + return congestionWindow >= hybridStartLowWindow && s.hystartFound +} + +// OnPacketSent is called when a packet was sent +func (s *HybridSlowStart) OnPacketSent(packetNumber congestion.PacketNumber) { + s.lastSentPacketNumber = packetNumber +} + +// OnPacketAcked gets invoked after ShouldExitSlowStart, so it's best to end +// the round when the final packet of the burst is received and start it on +// the next incoming ack. +func (s *HybridSlowStart) OnPacketAcked(ackedPacketNumber congestion.PacketNumber) { + if s.IsEndOfRound(ackedPacketNumber) { + s.started = false + } +} + +// Started returns true if started +func (s *HybridSlowStart) Started() bool { + return s.started +} + +// Restart the slow start phase +func (s *HybridSlowStart) Restart() { + s.started = false + s.hystartFound = false +} diff --git a/transport/tuic/congestion/minmax.go b/transport/tuic/congestion/minmax.go new file mode 100644 index 00000000..0a8f4ad4 --- /dev/null +++ b/transport/tuic/congestion/minmax.go @@ -0,0 +1,56 @@ +package congestion + +import ( + "math" + "time" +) + +// InfDuration is a duration of infinite length +const InfDuration = time.Duration(math.MaxInt64) + +// MinNonZeroDuration return the minimum duration that's not zero. +func MinNonZeroDuration(a, b time.Duration) time.Duration { + if a == 0 { + return b + } + if b == 0 { + return a + } + return Min(a, b) +} + +// AbsDuration returns the absolute value of a time duration +func AbsDuration(d time.Duration) time.Duration { + if d >= 0 { + return d + } + return -d +} + +// MinTime returns the earlier time +func MinTime(a, b time.Time) time.Time { + if a.After(b) { + return b + } + return a +} + +// MinNonZeroTime returns the earlist time that is not time.Time{} +// If both a and b are time.Time{}, it returns time.Time{} +func MinNonZeroTime(a, b time.Time) time.Time { + if a.IsZero() { + return b + } + if b.IsZero() { + return a + } + return MinTime(a, b) +} + +// MaxTime returns the later time +func MaxTime(a, b time.Time) time.Time { + if a.After(b) { + return a + } + return b +} From 7eae7756f56034913c36add8e316a629bd31eee5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 1 Oct 2023 19:15:26 +0800 Subject: [PATCH 465/530] chore: update gvisor --- go.mod | 6 +++--- go.sum | 12 ++++++------ 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/go.mod b/go.mod index d1503b48..26075f32 100644 --- a/go.mod +++ b/go.mod @@ -23,9 +23,9 @@ require ( github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee + github.com/metacubex/sing-tun v0.1.14 github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 - github.com/metacubex/sing-wireguard v0.0.0-20230611155257-1498ae315a28 + github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 @@ -77,7 +77,7 @@ require ( github.com/klauspost/compress v1.16.7 // 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-20230611153922-78842f086475 // indirect + github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 // indirect github.com/oasisprotocol/deoxysii v0.0.0-20220228165953-2091330c22b7 // indirect github.com/onsi/ginkgo/v2 v2.9.5 // indirect github.com/pierrec/lz4/v4 v4.1.14 // indirect diff --git a/go.sum b/go.sum index 3aa28a7f..a8de3428 100644 --- a/go.sum +++ b/go.sum @@ -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-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= -github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= +github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= +github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623 h1:lxXUXdS2GB4Ktn3ocnzQ53v1lqd6LYYfYIKICugTaJM= github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= @@ -103,12 +103,12 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee h1:hbbq181N4ZaDbhk/iJ0iA+3xfI/6v+j3nWeN5Who1xQ= -github.com/metacubex/sing-tun v0.1.13-0.20230926010214-4e9d1add2aee/go.mod h1:X2P/H1HqXwqGcguGXWDVDhSS1GmDxVi13OmbtDedZ2M= +github.com/metacubex/sing-tun v0.1.14 h1:35ermQwWZkHDai9Eg7EXoCjBFaU7IxcgzFOSMIcTR24= +github.com/metacubex/sing-tun v0.1.14/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= -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/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= +github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= From d1e88a30cb1fe7be8ea938039c22e8f9ab44e50d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 3 Oct 2023 16:00:03 +0800 Subject: [PATCH 466/530] fix: gVisor UDP 6to4 check --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 26075f32..abcf0a2c 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.14 + github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 diff --git a/go.sum b/go.sum index a8de3428..cd1a44a2 100644 --- a/go.sum +++ b/go.sum @@ -103,8 +103,8 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.14 h1:35ermQwWZkHDai9Eg7EXoCjBFaU7IxcgzFOSMIcTR24= -github.com/metacubex/sing-tun v0.1.14/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= +github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c h1:vzueqPO6LCdgE+KpGdZ89PwxcDGQW+lCnc7Leq2s1yY= +github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= From 5ff4473083e95c62614ca1e735fd33e57c917ec4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 6 Oct 2023 17:44:36 +0800 Subject: [PATCH 467/530] chore: migrate from gorilla/websocket to gobwas/ws --- component/tls/utls.go | 9 +- go.mod | 4 +- go.sum | 9 +- hub/route/connections.go | 9 +- hub/route/server.go | 36 +++-- transport/vmess/websocket.go | 263 ++++++++++++++++++++--------------- 6 files changed, 187 insertions(+), 143 deletions(-) diff --git a/component/tls/utls.go b/component/tls/utls.go index 7ea2ad06..e3d101dc 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -99,10 +99,9 @@ func copyConfig(c *tls.Config) *utls.Config { } } -// WebsocketHandshake basically calls UConn.Handshake inside it but it will only send -// http/1.1 in its ALPN. +// BuildWebsocketHandshakeState it will only send http/1.1 in its ALPN. // Copy from https://github.com/XTLS/Xray-core/blob/main/transport/internet/tls/tls.go -func (c *UConn) WebsocketHandshake() error { +func (c *UConn) BuildWebsocketHandshakeState() error { // Build the handshake state. This will apply every variable of the TLS of the // fingerprint in the UConn if err := c.BuildHandshakeState(); err != nil { @@ -120,11 +119,11 @@ func (c *UConn) WebsocketHandshake() error { if !hasALPNExtension { // Append extension if doesn't exists c.Extensions = append(c.Extensions, &utls.ALPNExtension{AlpnProtocols: []string{"http/1.1"}}) } - // Rebuild the client hello and do the handshake + // Rebuild the client hello if err := c.BuildHandshakeState(); err != nil { return err } - return c.Handshake() + return nil } func SetGlobalUtlsClient(Client string) { diff --git a/go.mod b/go.mod index abcf0a2c..e14ccda1 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,8 @@ require ( github.com/go-chi/chi/v5 v5.0.10 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.3 + github.com/gobwas/ws v1.3.0 github.com/gofrs/uuid/v5 v5.0.0 - github.com/gorilla/websocket v1.5.0 github.com/insomniacslk/dhcp v0.0.0-20230908212754-65c27093e38a github.com/jpillora/backoff v1.0.0 github.com/klauspost/cpuid/v2 v2.2.5 @@ -69,6 +69,8 @@ require ( github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.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 diff --git a/go.sum b/go.sum index cd1a44a2..0c6b9e50 100644 --- a/go.sum +++ b/go.sum @@ -49,6 +49,12 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 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/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0= +github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= 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/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -63,8 +69,6 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN 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= -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/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= @@ -237,6 +241,7 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= diff --git a/hub/route/connections.go b/hub/route/connections.go index b123ecae..67d5afa3 100644 --- a/hub/route/connections.go +++ b/hub/route/connections.go @@ -11,7 +11,8 @@ import ( "github.com/go-chi/chi/v5" "github.com/go-chi/render" - "github.com/gorilla/websocket" + "github.com/gobwas/ws" + "github.com/gobwas/ws/wsutil" ) func connectionRouter() http.Handler { @@ -23,13 +24,13 @@ func connectionRouter() http.Handler { } func getConnections(w http.ResponseWriter, r *http.Request) { - if !websocket.IsWebSocketUpgrade(r) { + if !(r.Header.Get("Upgrade") == "websocket") { snapshot := statistic.DefaultManager.Snapshot() render.JSON(w, r, snapshot) return } - conn, err := upgrader.Upgrade(w, r, nil) + conn, _, _, err := ws.UpgradeHTTP(r, w) if err != nil { return } @@ -55,7 +56,7 @@ func getConnections(w http.ResponseWriter, r *http.Request) { return err } - return conn.WriteMessage(websocket.TextMessage, buf.Bytes()) + return wsutil.WriteMessage(conn, ws.StateServerSide, ws.OpText, buf.Bytes()) } if err := sendSnapshot(); err != nil { diff --git a/hub/route/server.go b/hub/route/server.go index aa2d03b8..93afd989 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -5,6 +5,7 @@ import ( "crypto/subtle" "crypto/tls" "encoding/json" + "net" "net/http" "runtime/debug" "strings" @@ -21,7 +22,8 @@ import ( "github.com/go-chi/chi/v5/middleware" "github.com/go-chi/cors" "github.com/go-chi/render" - "github.com/gorilla/websocket" + "github.com/gobwas/ws" + "github.com/gobwas/ws/wsutil" ) var ( @@ -29,12 +31,6 @@ var ( serverAddr = "" uiPath = "" - - upgrader = websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { - return true - }, - } ) type Traffic struct { @@ -166,7 +162,7 @@ func authentication(next http.Handler) http.Handler { } // Browser websocket not support custom header - if websocket.IsWebSocketUpgrade(r) && r.URL.Query().Get("token") != "" { + if r.Header.Get("Upgrade") == "websocket" && r.URL.Query().Get("token") != "" { token := r.URL.Query().Get("token") if !safeEuqal(token, serverSecret) { render.Status(r, http.StatusUnauthorized) @@ -197,10 +193,10 @@ func hello(w http.ResponseWriter, r *http.Request) { } func traffic(w http.ResponseWriter, r *http.Request) { - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { + var wsConn net.Conn + if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, err = upgrader.Upgrade(w, r, nil) + wsConn, _, _, err = ws.UpgradeHTTP(r, w) if err != nil { return } @@ -230,7 +226,7 @@ func traffic(w http.ResponseWriter, r *http.Request) { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + err = wsutil.WriteMessage(wsConn, ws.StateServerSide, ws.OpText, buf.Bytes()) } if err != nil { @@ -240,10 +236,10 @@ func traffic(w http.ResponseWriter, r *http.Request) { } func memory(w http.ResponseWriter, r *http.Request) { - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { + var wsConn net.Conn + if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, err = upgrader.Upgrade(w, r, nil) + wsConn, _, _, err = ws.UpgradeHTTP(r, w) if err != nil { return } @@ -280,7 +276,7 @@ func memory(w http.ResponseWriter, r *http.Request) { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + err = wsutil.WriteMessage(wsConn, ws.StateServerSide, ws.OpText, buf.Bytes()) } if err != nil { @@ -323,10 +319,10 @@ func getLogs(w http.ResponseWriter, r *http.Request) { return } - var wsConn *websocket.Conn - if websocket.IsWebSocketUpgrade(r) { + var wsConn net.Conn + if r.Header.Get("Upgrade") == "websocket" { var err error - wsConn, err = upgrader.Upgrade(w, r, nil) + wsConn, _, _, err = ws.UpgradeHTTP(r, w) if err != nil { return } @@ -385,7 +381,7 @@ func getLogs(w http.ResponseWriter, r *http.Request) { _, err = w.Write(buf.Bytes()) w.(http.Flusher).Flush() } else { - err = wsConn.WriteMessage(websocket.TextMessage, buf.Bytes()) + err = wsutil.WriteMessage(wsConn, ws.StateServerSide, ws.OpText, buf.Bytes()) } if err != nil { diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index a4ce99a9..2b26eb1a 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -1,6 +1,7 @@ package vmess import ( + "bufio" "bytes" "context" "crypto/tls" @@ -14,27 +15,24 @@ import ( "net/url" "strconv" "strings" - "sync" "time" "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/gorilla/websocket" + "github.com/gobwas/ws" + "github.com/gobwas/ws/wsutil" "github.com/zhangyunhao116/fastrand" ) type websocketConn struct { - conn *websocket.Conn - reader io.Reader - remoteAddr net.Addr + net.Conn + state ws.State + reader *wsutil.Reader + controlHandler wsutil.FrameHandlerFunc rawWriter N.ExtendedWriter - - // https://godoc.org/github.com/gorilla/websocket#hdr-Concurrency - rMux sync.Mutex - wMux sync.Mutex } type websocketWithEarlyDataConn struct { @@ -61,32 +59,48 @@ type WebsocketConfig struct { } // Read implements net.Conn.Read() -func (wsc *websocketConn) Read(b []byte) (int, error) { - wsc.rMux.Lock() - defer wsc.rMux.Unlock() +// modify from gobwas/ws/wsutil.readData +func (wsc *websocketConn) Read(b []byte) (n int, err error) { + var header ws.Header for { - reader, err := wsc.getReader() - if err != nil { - return 0, err + n, err = wsc.reader.Read(b) + // in gobwas/ws: "The error is io.EOF only if all of message bytes were read." + // but maybe next frame still have data, so drop it + if errors.Is(err, io.EOF) { + err = nil } - - nBytes, err := reader.Read(b) - if err == io.EOF { - wsc.reader = nil + if !errors.Is(err, wsutil.ErrNoFrameAdvance) { + return + } + header, err = wsc.reader.NextFrame() + if err != nil { + return + } + if header.OpCode.IsControl() { + err = wsc.controlHandler(header, wsc.reader) + if err != nil { + return + } + continue + } + if header.OpCode&(ws.OpBinary|ws.OpText) == 0 { + err = wsc.reader.Discard() + if err != nil { + return + } continue } - return nBytes, err } } // Write implements io.Writer. -func (wsc *websocketConn) Write(b []byte) (int, error) { - wsc.wMux.Lock() - defer wsc.wMux.Unlock() - if err := wsc.conn.WriteMessage(websocket.BinaryMessage, b); err != nil { - return 0, err +func (wsc *websocketConn) Write(b []byte) (n int, err error) { + err = wsutil.WriteMessage(wsc.Conn, wsc.state, ws.OpBinary, b) + if err != nil { + return } - return len(b), nil + n = len(b) + return } func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { @@ -108,7 +122,7 @@ func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { header := buffer.ExtendHeader(headerLen) _ = header[2] // bounds check hint to compiler - header[0] = websocket.BinaryMessage | 1<<7 + header[0] = byte(ws.OpBinary) | 0x80 header[1] = 1 << 7 if dataLen < 126 { @@ -121,12 +135,12 @@ func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { binary.BigEndian.PutUint64(header[2:], uint64(dataLen)) } - maskKey := fastrand.Uint32() - binary.LittleEndian.PutUint32(header[1+payloadBitLength:], maskKey) - N.MaskWebSocket(maskKey, data) + if wsc.state.ClientSide() { + maskKey := fastrand.Uint32() + binary.LittleEndian.PutUint32(header[1+payloadBitLength:], maskKey) + N.MaskWebSocket(maskKey, data) + } - wsc.wMux.Lock() - defer wsc.wMux.Unlock() return wsc.rawWriter.WriteBuffer(buffer) } @@ -135,59 +149,16 @@ func (wsc *websocketConn) FrontHeadroom() int { } func (wsc *websocketConn) Upstream() any { - return wsc.conn.UnderlyingConn() + return wsc.Conn } func (wsc *websocketConn) Close() error { - var e []string - if err := wsc.conn.WriteControl(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""), time.Now().Add(time.Second*5)); err != nil { - e = append(e, err.Error()) - } - if err := wsc.conn.Close(); err != nil { - e = append(e, err.Error()) - } - if len(e) > 0 { - return fmt.Errorf("failed to close connection: %s", strings.Join(e, ",")) - } + _ = wsc.Conn.SetWriteDeadline(time.Now().Add(time.Second * 5)) + _ = wsutil.WriteMessage(wsc.Conn, wsc.state, ws.OpClose, ws.NewCloseFrameBody(ws.StatusNormalClosure, "")) + _ = wsc.Conn.Close() return nil } -func (wsc *websocketConn) getReader() (io.Reader, error) { - if wsc.reader != nil { - return wsc.reader, nil - } - - _, reader, err := wsc.conn.NextReader() - if err != nil { - return nil, err - } - wsc.reader = reader - return reader, nil -} - -func (wsc *websocketConn) LocalAddr() net.Addr { - return wsc.conn.LocalAddr() -} - -func (wsc *websocketConn) RemoteAddr() net.Addr { - return wsc.remoteAddr -} - -func (wsc *websocketConn) SetDeadline(t time.Time) error { - if err := wsc.SetReadDeadline(t); err != nil { - return err - } - return wsc.SetWriteDeadline(t) -} - -func (wsc *websocketConn) SetReadDeadline(t time.Time) error { - return wsc.conn.SetReadDeadline(t) -} - -func (wsc *websocketConn) SetWriteDeadline(t time.Time) error { - return wsc.conn.SetWriteDeadline(t) -} - func (wsedc *websocketWithEarlyDataConn) Dial(earlyData []byte) error { base64DataBuf := &bytes.Buffer{} base64EarlyDataEncoder := base64.NewEncoder(base64.RawURLEncoding, base64DataBuf) @@ -341,29 +312,25 @@ func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Co } func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { - - dialer := &websocket.Dialer{ - NetDial: func(network, addr string) (net.Conn, error) { + dialer := ws.Dialer{ + NetDial: func(ctx context.Context, network, addr string) (net.Conn, error) { return conn, nil }, - ReadBufferSize: 4 * 1024, - WriteBufferSize: 4 * 1024, - HandshakeTimeout: time.Second * 8, + TLSConfig: c.TLSConfig, } - scheme := "ws" if c.TLS { scheme = "wss" - dialer.TLSClientConfig = c.TLSConfig if len(c.ClientFingerprint) != 0 { if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { - dialer.NetDialTLSContext = func(_ context.Context, _, addr string) (net.Conn, error) { - utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) + utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) - if err := utlsConn.(*tlsC.UConn).WebsocketHandshake(); err != nil { - return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) - } - return utlsConn, nil + if err := utlsConn.(*tlsC.UConn).BuildWebsocketHandshakeState(); err != nil { + return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) + } + + dialer.TLSClient = func(conn net.Conn, hostname string) net.Conn { + return utlsConn } } } @@ -381,38 +348,47 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, RawQuery: u.RawQuery, } - headers := http.Header{} + headers := http.Header{"User-Agent": []string{"Go-http-client/1.1"}} // match golang's net/http if c.Headers != nil { - for k := range c.Headers { - headers.Add(k, c.Headers.Get(k)) + cHeaders := c.Headers + // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` + // if headers has "Host" will send repeatedly + if host := cHeaders.Get("Host"); host != "" { + cHeaders.Del("Host") + uri.Host = host + } + for k := range cHeaders { + headers.Add(k, cHeaders.Get(k)) } } if earlyData != nil { + earlyDataString := earlyData.String() if c.EarlyDataHeaderName == "" { - uri.Path += earlyData.String() + uri.Path += earlyDataString } else { - headers.Set(c.EarlyDataHeaderName, earlyData.String()) + // gobwas/ws will check server's response "Sec-Websocket-Protocol" so must add Protocols to ws.Dialer + // if not will cause ws.ErrHandshakeBadSubProtocol + if c.EarlyDataHeaderName == "Sec-WebSocket-Protocol" { + // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols + // to avoid send repeatedly don't set it to headers + dialer.Protocols = []string{earlyDataString} + } else { + headers.Set(c.EarlyDataHeaderName, earlyDataString) + } + } } - wsConn, resp, err := dialer.DialContext(ctx, uri.String(), headers) + dialer.Header = ws.HandshakeHeaderHTTP(headers) + + conn, reader, _, err := dialer.Dial(ctx, uri.String()) if err != nil { - reason := err - if resp != nil { - reason = errors.New(resp.Status) - } - return nil, fmt.Errorf("dial %s error: %w", uri.Host, reason) + return nil, fmt.Errorf("dial %s error: %w", uri.Host, err) } - conn = &websocketConn{ - conn: wsConn, - rawWriter: N.NewExtendedWriter(wsConn.UnderlyingConn()), - remoteAddr: conn.RemoteAddr(), - } + conn = newWebsocketConn(conn, reader, ws.StateClientSide) // websocketConn can't correct handle ReadDeadline - // gorilla/websocket will cache the os.ErrDeadlineExceeded from conn.Read() - // it will cause read fail and event panic in *websocket.Conn.NextReader() // so call N.NewDeadlineConn to add a safe wrapper return N.NewDeadlineConn(conn), nil } @@ -436,3 +412,68 @@ func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig) return streamWebsocketConn(ctx, conn, c, nil) } + +func newWebsocketConn(conn net.Conn, br *bufio.Reader, state ws.State) *websocketConn { + controlHandler := wsutil.ControlFrameHandler(conn, state) + var reader io.Reader + if br != nil && br.Buffered() > 0 { + reader = br + } else { + reader = conn + } + return &websocketConn{ + Conn: conn, + state: state, + reader: &wsutil.Reader{ + Source: reader, + State: state, + SkipHeaderCheck: true, + CheckUTF8: false, + OnIntermediate: controlHandler, + }, + controlHandler: controlHandler, + rawWriter: N.NewExtendedWriter(conn), + } +} + +var replacer = strings.NewReplacer("+", "-", "/", "_", "=", "") + +func decodeEd(s string) ([]byte, error) { + return base64.RawURLEncoding.DecodeString(replacer.Replace(s)) +} + +func decodeXray0rtt(requestHeader http.Header) ([]byte, http.Header) { + var edBuf []byte + responseHeader := http.Header{} + // read inHeader's `Sec-WebSocket-Protocol` for Xray's 0rtt ws + if secProtocol := requestHeader.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { + if buf, err := decodeEd(secProtocol); err == nil { // sure could base64 decode + edBuf = buf + } + } + return edBuf, responseHeader +} + +func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Conn, error) { + edBuf, responseHeader := decodeXray0rtt(r.Header) + wsConn, rw, _, err := ws.HTTPUpgrader{ + Header: responseHeader, + }.Upgrade(r, w) + if err != nil { + return nil, err + } + conn := newWebsocketConn(wsConn, rw.Reader, ws.StateServerSide) + if len(edBuf) > 0 { + return &websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}, nil + } + return conn, nil +} + +type websocketWithReaderConn struct { + *websocketConn + reader io.Reader +} + +func (ws *websocketWithReaderConn) Read(b []byte) (n int, err error) { + return ws.reader.Read(b) +} From 791ecfbb32219b7b5cf625c3aa74a9f9003eef89 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 7 Oct 2023 16:45:15 +0800 Subject: [PATCH 468/530] feat: add `ws-path` to vmess listener --- docs/config.yaml | 1 + listener/config/vmess.go | 1 + listener/inbound/vmess.go | 4 +++- listener/sing_vmess/server.go | 20 ++++++++++++++++++++ transport/vmess/websocket.go | 19 +++++++++++-------- 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index c2bdc263..030328b6 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -936,6 +936,7 @@ listeners: - username: 1 uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 alterId: 1 + # ws-path: "/" # 如果不为空则开启websocket传输层 - name: tuic-in-1 type: tuic diff --git a/listener/config/vmess.go b/listener/config/vmess.go index cc49433e..88bde9a4 100644 --- a/listener/config/vmess.go +++ b/listener/config/vmess.go @@ -14,6 +14,7 @@ type VmessServer struct { Enable bool Listen string Users []VmessUser + WsPath string } func (t VmessServer) String() string { diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index fa2c30f1..36bb208b 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -9,7 +9,8 @@ import ( type VmessOption struct { BaseOption - Users []VmessUser `inbound:"users"` + Users []VmessUser `inbound:"users"` + WsPath string `inbound:"ws-path,omitempty"` } type VmessUser struct { @@ -49,6 +50,7 @@ func NewVmess(options *VmessOption) (*Vmess, error) { Enable: true, Listen: base.RawAddress(), Users: users, + WsPath: options.WsPath, }, }, nil } diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index d28213c8..96d713c9 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -3,6 +3,7 @@ package sing_vmess import ( "context" "net" + "net/http" "net/url" "strings" @@ -12,6 +13,7 @@ import ( LC "github.com/Dreamacro/clash/listener/config" "github.com/Dreamacro/clash/listener/sing" "github.com/Dreamacro/clash/ntp" + clashVMess "github.com/Dreamacro/clash/transport/vmess" vmess "github.com/metacubex/sing-vmess" "github.com/sagernet/sing/common" @@ -65,6 +67,20 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) sl = &Listener{false, config, nil, service} + var httpMux *http.ServeMux + + if config.WsPath != "" { + httpMux = http.NewServeMux() + httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) { + conn, err := clashVMess.StreamUpgradedWebsocketConn(w, r) + if err != nil { + http.Error(w, err.Error(), 500) + return + } + sl.HandleConn(conn, tunnel) + }) + } + for _, addr := range strings.Split(config.Listen, ",") { addr := addr @@ -76,6 +92,10 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) sl.listeners = append(sl.listeners, l) go func() { + if httpMux != nil { + _ = http.Serve(l, httpMux) + return + } for { c, err := l.Accept() if err != nil { diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 2b26eb1a..6d679e29 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -118,12 +118,17 @@ func (wsc *websocketConn) WriteBuffer(buffer *buf.Buffer) error { var headerLen int headerLen += 1 // FIN / RSV / OPCODE headerLen += payloadBitLength - headerLen += 4 // MASK KEY + if wsc.state.ClientSide() { + headerLen += 4 // MASK KEY + } header := buffer.ExtendHeader(headerLen) - _ = header[2] // bounds check hint to compiler header[0] = byte(ws.OpBinary) | 0x80 - header[1] = 1 << 7 + if wsc.state.ClientSide() { + header[1] = 1 << 7 + } else { + header[1] = 0 + } if dataLen < 126 { header[1] |= byte(dataLen) @@ -456,17 +461,15 @@ func decodeXray0rtt(requestHeader http.Header) ([]byte, http.Header) { func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Conn, error) { edBuf, responseHeader := decodeXray0rtt(r.Header) - wsConn, rw, _, err := ws.HTTPUpgrader{ - Header: responseHeader, - }.Upgrade(r, w) + wsConn, rw, _, err := ws.HTTPUpgrader{Header: responseHeader}.Upgrade(r, w) if err != nil { return nil, err } conn := newWebsocketConn(wsConn, rw.Reader, ws.StateServerSide) if len(edBuf) > 0 { - return &websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}, nil + return N.NewDeadlineConn(&websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}), nil } - return conn, nil + return N.NewDeadlineConn(conn), nil } type websocketWithReaderConn struct { From d8fe7a52d685b1edf63395ca7de73a16f8307149 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 7 Oct 2023 17:08:54 +0800 Subject: [PATCH 469/530] feat: add `certificate` and `private-key` to vmess listener --- docs/config.yaml | 3 +++ listener/config/vmess.go | 10 ++++++---- listener/inbound/vmess.go | 16 ++++++++++------ listener/sing_vmess/server.go | 13 +++++++++++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/docs/config.yaml b/docs/config.yaml index 030328b6..bfcdc0cd 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -937,6 +937,9 @@ listeners: uuid: 9d0cb9d0-964f-4ef6-897d-6c6b3ccf9e68 alterId: 1 # ws-path: "/" # 如果不为空则开启websocket传输层 + # 下面两项如果填写则开启tls(需要同时填写) + # certificate: ./server.crt + # private-key: ./server.key - name: tuic-in-1 type: tuic diff --git a/listener/config/vmess.go b/listener/config/vmess.go index 88bde9a4..1cf2d46c 100644 --- a/listener/config/vmess.go +++ b/listener/config/vmess.go @@ -11,10 +11,12 @@ type VmessUser struct { } type VmessServer struct { - Enable bool - Listen string - Users []VmessUser - WsPath string + Enable bool + Listen string + Users []VmessUser + WsPath string + Certificate string + PrivateKey string } func (t VmessServer) String() string { diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 36bb208b..3f516198 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -9,8 +9,10 @@ import ( type VmessOption struct { BaseOption - Users []VmessUser `inbound:"users"` - WsPath string `inbound:"ws-path,omitempty"` + Users []VmessUser `inbound:"users"` + WsPath string `inbound:"ws-path,omitempty"` + Certificate string `inbound:"certificate,omitempty"` + PrivateKey string `inbound:"private-key,omitempty"` } type VmessUser struct { @@ -47,10 +49,12 @@ func NewVmess(options *VmessOption) (*Vmess, error) { Base: base, config: options, vs: LC.VmessServer{ - Enable: true, - Listen: base.RawAddress(), - Users: users, - WsPath: options.WsPath, + Enable: true, + Listen: base.RawAddress(), + Users: users, + WsPath: options.WsPath, + Certificate: options.Certificate, + PrivateKey: options.PrivateKey, }, }, nil } diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index 96d713c9..014e86f9 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -2,6 +2,7 @@ package sing_vmess import ( "context" + "crypto/tls" "net" "net/http" "net/url" @@ -67,8 +68,16 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) sl = &Listener{false, config, nil, service} + tlsConfig := &tls.Config{} var httpMux *http.ServeMux + if config.Certificate != "" && config.PrivateKey != "" { + cert, err := N.ParseCert(config.Certificate, config.PrivateKey, C.Path) + if err != nil { + return nil, err + } + tlsConfig.Certificates = []tls.Certificate{cert} + } if config.WsPath != "" { httpMux = http.NewServeMux() httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) { @@ -79,6 +88,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) } sl.HandleConn(conn, tunnel) }) + tlsConfig.NextProtos = append(tlsConfig.NextProtos, "http/1.1") } for _, addr := range strings.Split(config.Listen, ",") { @@ -89,6 +99,9 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) if err != nil { return nil, err } + if len(tlsConfig.Certificates) > 0 { + l = tls.NewListener(l, tlsConfig) + } sl.listeners = append(sl.listeners, l) go func() { From 5a1800d642a6d928637f55bff2382a81ef1c96ab Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 7 Oct 2023 17:30:03 +0800 Subject: [PATCH 470/530] fix: BBR bandwidth estimation edge case from https://github.com/apernet/hysteria/commit/89429598bf897a34d61027cf7f68f5e35fcfff4b --- go.mod | 2 +- go.sum | 4 ++-- transport/tuic/congestion_v2/bbr_sender.go | 18 ++++++++++++++---- transport/tuic/congestion_v2/pacer.go | 3 +++ 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index e14ccda1..171fec55 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.39.1-0.20231001052253-5776efe31623 + github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838 github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 diff --git a/go.sum b/go.sum index 0c6b9e50..aa6ff01b 100644 --- a/go.sum +++ b/go.sum @@ -97,8 +97,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-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623 h1:lxXUXdS2GB4Ktn3ocnzQ53v1lqd6LYYfYIKICugTaJM= -github.com/metacubex/quic-go v0.39.1-0.20231001052253-5776efe31623/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838 h1:VqiDBQY+MB7vmUF2AHhbExMoLXu+1zoPgMUsDy43wvs= +github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= diff --git a/transport/tuic/congestion_v2/bbr_sender.go b/transport/tuic/congestion_v2/bbr_sender.go index a7700fa1..68c10d20 100644 --- a/transport/tuic/congestion_v2/bbr_sender.go +++ b/transport/tuic/congestion_v2/bbr_sender.go @@ -22,6 +22,8 @@ import ( // const ( + minBps = 65536 // 64 kbps + invalidPacketNumber = -1 initialCongestionWindowPackets = 32 @@ -285,10 +287,7 @@ func newBbrSender( maxCongestionWindowWithNetworkParametersAdjusted: initialMaxCongestionWindow, maxDatagramSize: initialMaxDatagramSize, } - b.pacer = NewPacer(func() congestion.ByteCount { - // Pacer wants bytes per second, but Bandwidth is in bits per second. - return congestion.ByteCount(float64(b.bandwidthEstimate()) * b.congestionWindowGain / float64(BytesPerSecond)) - }) + b.pacer = NewPacer(b.bandwidthForPacer) /* if b.tracer != nil { @@ -538,6 +537,17 @@ func (b *bbrSender) bandwidthEstimate() Bandwidth { return b.maxBandwidth.GetBest() } +func (b *bbrSender) bandwidthForPacer() congestion.ByteCount { + bps := congestion.ByteCount(float64(b.bandwidthEstimate()) * b.congestionWindowGain / float64(BytesPerSecond)) + if bps < minBps { + // We need to make sure that the bandwidth value for pacer is never zero, + // otherwise it will go into an edge case where HasPacingBudget = false + // but TimeUntilSend is before, causing the quic-go send loop to go crazy and get stuck. + return minBps + } + return bps +} + // Returns the current estimate of the RTT of the connection. Outside of the // edge cases, this is minimum RTT. func (b *bbrSender) getMinRtt() time.Duration { diff --git a/transport/tuic/congestion_v2/pacer.go b/transport/tuic/congestion_v2/pacer.go index ba4ca138..ecaf3d11 100644 --- a/transport/tuic/congestion_v2/pacer.go +++ b/transport/tuic/congestion_v2/pacer.go @@ -43,6 +43,9 @@ func (p *Pacer) Budget(now time.Time) congestion.ByteCount { return p.maxBurstSize() } budget := p.budgetAtLastSent + (p.getBandwidth()*congestion.ByteCount(now.Sub(p.lastSentTime).Nanoseconds()))/1e9 + if budget < 0 { // protect against overflows + budget = congestion.ByteCount(1<<62 - 1) + } return Min(p.maxBurstSize(), budget) } From ae557c30d3805ca8f58d9c3301e8c9321d5218c4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 8 Oct 2023 13:15:17 +0800 Subject: [PATCH 471/530] fix: quic-go min MTU --- go.mod | 10 ++++---- go.sum | 15 ++++++------ transport/hysteria/congestion/brutal.go | 31 ++++++++++++------------- 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/go.mod b/go.mod index 171fec55..188f00ea 100644 --- a/go.mod +++ b/go.mod @@ -19,8 +19,8 @@ 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.39.1-0.20231007092458-6d5373196838 - github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 + github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0 + github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c @@ -32,7 +32,7 @@ require ( github.com/oschwald/maxminddb-golang v1.12.0 github.com/puzpuzpuz/xsync/v2 v2.5.0 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.12 + github.com/sagernet/sing v0.2.13 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 @@ -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.3 - golang.org/x/crypto v0.13.0 + golang.org/x/crypto v0.14.0 golang.org/x/exp v0.0.0-20230905200255-921286631fa9 golang.org/x/net v0.15.0 golang.org/x/sync v0.3.0 - golang.org/x/sys v0.12.0 + golang.org/x/sys v0.13.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 lukechampine.com/blake3 v1.2.1 diff --git a/go.sum b/go.sum index aa6ff01b..84b186c1 100644 --- a/go.sum +++ b/go.sum @@ -97,12 +97,12 @@ 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-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838 h1:VqiDBQY+MB7vmUF2AHhbExMoLXu+1zoPgMUsDy43wvs= -github.com/metacubex/quic-go v0.39.1-0.20231007092458-6d5373196838/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0 h1:zUNzLFzYAHti3LCSMyM1PILsGovf1QYdWpzFhrdQovA= +github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= -github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255 h1:NfdM4hDFIhq9QxDStJ9Rz1h73sRUO/2L4pRZ6lGWRz8= -github.com/metacubex/sing-quic v0.0.0-20230926004739-7c7c534c2255/go.mod h1:asoMecRyaA6pLSLVR+qFdp/vD24m8KZ1O/QDxWa7RsM= +github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= +github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966/go.mod h1:GU7g2AZesXItk4CspDP8Dc7eGtlA2GVDihyCwsUXRSo= github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= @@ -213,8 +213,8 @@ go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= 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.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= @@ -244,8 +244,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= diff --git a/transport/hysteria/congestion/brutal.go b/transport/hysteria/congestion/brutal.go index 88bf6f34..601949de 100644 --- a/transport/hysteria/congestion/brutal.go +++ b/transport/hysteria/congestion/brutal.go @@ -8,11 +8,13 @@ import ( const ( initMaxDatagramSize = 1252 - pktInfoSlotCount = 4 + pktInfoSlotCount = 5 // slot index is based on seconds, so this is basically how many seconds we sample minSampleCount = 50 minAckRate = 0.8 ) +var _ congestion.CongestionControlEx = &BrutalSender{} + type BrutalSender struct { rttStats congestion.RTTStatsProvider bps congestion.ByteCount @@ -72,30 +74,25 @@ func (b *BrutalSender) OnPacketSent(sentTime time.Time, bytesInFlight congestion func (b *BrutalSender) OnPacketAcked(number congestion.PacketNumber, ackedBytes congestion.ByteCount, priorInFlight congestion.ByteCount, eventTime time.Time) { - currentTimestamp := eventTime.Unix() - slot := currentTimestamp % pktInfoSlotCount - if b.pktInfoSlots[slot].Timestamp == currentTimestamp { - b.pktInfoSlots[slot].AckCount++ - } else { - // uninitialized slot or too old, reset - b.pktInfoSlots[slot].Timestamp = currentTimestamp - b.pktInfoSlots[slot].AckCount = 1 - b.pktInfoSlots[slot].LossCount = 0 - } - b.updateAckRate(currentTimestamp) + // Stub } func (b *BrutalSender) OnCongestionEvent(number congestion.PacketNumber, lostBytes congestion.ByteCount, priorInFlight congestion.ByteCount) { - currentTimestamp := time.Now().Unix() + // Stub +} + +func (b *BrutalSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, eventTime time.Time, ackedPackets []congestion.AckedPacketInfo, lostPackets []congestion.LostPacketInfo) { + currentTimestamp := eventTime.Unix() slot := currentTimestamp % pktInfoSlotCount if b.pktInfoSlots[slot].Timestamp == currentTimestamp { - b.pktInfoSlots[slot].LossCount++ + b.pktInfoSlots[slot].LossCount += uint64(len(lostPackets)) + b.pktInfoSlots[slot].AckCount += uint64(len(ackedPackets)) } else { // uninitialized slot or too old, reset b.pktInfoSlots[slot].Timestamp = currentTimestamp - b.pktInfoSlots[slot].AckCount = 0 - b.pktInfoSlots[slot].LossCount = 1 + b.pktInfoSlots[slot].AckCount = uint64(len(ackedPackets)) + b.pktInfoSlots[slot].LossCount = uint64(len(lostPackets)) } b.updateAckRate(currentTimestamp) } @@ -117,10 +114,12 @@ func (b *BrutalSender) updateAckRate(currentTimestamp int64) { } if ackCount+lossCount < minSampleCount { b.ackRate = 1 + return } rate := float64(ackCount) / float64(ackCount+lossCount) if rate < minAckRate { b.ackRate = minAckRate + return } b.ackRate = rate } From 7ed25ddc7494086e00760ef516f658c1b6a4e36d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 10 Oct 2023 16:34:33 +0800 Subject: [PATCH 472/530] chore: better atomic using --- adapter/adapter.go | 4 ++-- adapter/outboundgroup/groupbase.go | 2 +- adapter/provider/healthcheck.go | 21 +++++++++--------- common/atomic/type.go | 35 ++++++++++++------------------ common/atomic/value.go | 5 ++--- dns/client.go | 6 ++--- dns/resolver.go | 2 +- transport/gun/gun.go | 2 +- tunnel/statistic/manager.go | 12 +++++----- tunnel/statistic/tracker.go | 16 +++++++------- 10 files changed, 48 insertions(+), 57 deletions(-) diff --git a/adapter/adapter.go b/adapter/adapter.go index e9ce59bb..62941e6d 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -30,13 +30,13 @@ const ( type extraProxyState struct { history *queue.Queue[C.DelayHistory] - alive *atomic.Bool + alive atomic.Bool } type Proxy struct { C.ProxyAdapter history *queue.Queue[C.DelayHistory] - alive *atomic.Bool + alive atomic.Bool url string extra *xsync.MapOf[string, *extraProxyState] } diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 66776bf5..22dd407b 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -28,7 +28,7 @@ type GroupBase struct { failedTestMux sync.Mutex failedTimes int failedTime time.Time - failedTesting *atomic.Bool + failedTesting atomic.Bool proxies [][]C.Proxy versions []atomic.Uint32 } diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index 35327b1c..feb972ab 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -34,12 +34,12 @@ type HealthCheck struct { url string extra map[string]*extraOption mu sync.Mutex - started *atomic.Bool + started atomic.Bool proxies []C.Proxy - interval uint + interval time.Duration lazy bool expectedStatus utils.IntRanges[uint16] - lastTouch *atomic.Int64 + lastTouch atomic.TypedValue[time.Time] done chan struct{} singleDo *singledo.Single[struct{}] } @@ -50,13 +50,14 @@ func (hc *HealthCheck) process() { return } - ticker := time.NewTicker(time.Duration(hc.interval) * time.Second) + ticker := time.NewTicker(hc.interval) hc.start() for { select { case <-ticker.C: - now := time.Now().Unix() - if !hc.lazy || now-hc.lastTouch.Load() < int64(hc.interval) { + lastTouch := hc.lastTouch.Load() + since := time.Since(lastTouch) + if !hc.lazy || since < hc.interval { hc.check() } else { log.Debugln("Skip once health check because we are lazy") @@ -85,7 +86,7 @@ func (hc *HealthCheck) registerHealthCheckTask(url string, expectedStatus utils. // 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 + hc.interval = time.Duration(interval) * time.Second } if hc.extra == nil { @@ -135,7 +136,7 @@ func (hc *HealthCheck) auto() bool { } func (hc *HealthCheck) touch() { - hc.lastTouch.Store(time.Now().Unix()) + hc.lastTouch.Store(time.Now()) } func (hc *HealthCheck) start() { @@ -228,11 +229,9 @@ func NewHealthCheck(proxies []C.Proxy, url string, interval uint, lazy bool, exp proxies: proxies, url: url, extra: map[string]*extraOption{}, - started: atomic.NewBool(false), - interval: interval, + interval: time.Duration(interval) * time.Second, lazy: lazy, expectedStatus: expectedStatus, - lastTouch: atomic.NewInt64(0), done: make(chan struct{}, 1), singleDo: singledo.NewSingle[struct{}](time.Second), } diff --git a/common/atomic/type.go b/common/atomic/type.go index f1549235..71695c63 100644 --- a/common/atomic/type.go +++ b/common/atomic/type.go @@ -11,10 +11,9 @@ type Bool struct { atomic.Bool } -func NewBool(val bool) *Bool { - i := &Bool{} +func NewBool(val bool) (i Bool) { i.Store(val) - return i + return } func (i *Bool) MarshalJSON() ([]byte, error) { @@ -39,12 +38,11 @@ type Pointer[T any] struct { atomic.Pointer[T] } -func NewPointer[T any](v *T) *Pointer[T] { - var p Pointer[T] +func NewPointer[T any](v *T) (p Pointer[T]) { if v != nil { p.Store(v) } - return &p + return } func (p *Pointer[T]) MarshalJSON() ([]byte, error) { @@ -68,10 +66,9 @@ type Int32 struct { atomic.Int32 } -func NewInt32(val int32) *Int32 { - i := &Int32{} +func NewInt32(val int32) (i Int32) { i.Store(val) - return i + return } func (i *Int32) MarshalJSON() ([]byte, error) { @@ -96,10 +93,9 @@ type Int64 struct { atomic.Int64 } -func NewInt64(val int64) *Int64 { - i := &Int64{} +func NewInt64(val int64) (i Int64) { i.Store(val) - return i + return } func (i *Int64) MarshalJSON() ([]byte, error) { @@ -124,10 +120,9 @@ type Uint32 struct { atomic.Uint32 } -func NewUint32(val uint32) *Uint32 { - i := &Uint32{} +func NewUint32(val uint32) (i Uint32) { i.Store(val) - return i + return } func (i *Uint32) MarshalJSON() ([]byte, error) { @@ -152,10 +147,9 @@ type Uint64 struct { atomic.Uint64 } -func NewUint64(val uint64) *Uint64 { - i := &Uint64{} +func NewUint64(val uint64) (i Uint64) { i.Store(val) - return i + return } func (i *Uint64) MarshalJSON() ([]byte, error) { @@ -180,10 +174,9 @@ type Uintptr struct { atomic.Uintptr } -func NewUintptr(val uintptr) *Uintptr { - i := &Uintptr{} +func NewUintptr(val uintptr) (i Uintptr) { i.Store(val) - return i + return } func (i *Uintptr) MarshalJSON() ([]byte, error) { diff --git a/common/atomic/value.go b/common/atomic/value.go index ca0eb631..95733533 100644 --- a/common/atomic/value.go +++ b/common/atomic/value.go @@ -51,8 +51,7 @@ func (t *TypedValue[T]) UnmarshalJSON(b []byte) error { return nil } -func NewTypedValue[T any](t T) *TypedValue[T] { - v := &TypedValue[T]{} +func NewTypedValue[T any](t T) (v TypedValue[T]) { v.Store(t) - return v + return } diff --git a/dns/client.go b/dns/client.go index 56f55668..89f083aa 100644 --- a/dns/client.go +++ b/dns/client.go @@ -23,7 +23,7 @@ type client struct { r *Resolver port string host string - iface *atomic.TypedValue[string] + iface atomic.TypedValue[string] proxyAdapter C.ProxyAdapter proxyName string addr string @@ -77,8 +77,8 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) network = "tcp" } - options := []dialer.Option{} - if c.iface != nil && c.iface.Load() != "" { + var options []dialer.Option + if c.iface.Load() != "" { options = append(options, dialer.WithInterface(c.iface.Load())) } diff --git a/dns/resolver.go b/dns/resolver.go index 3a530918..2c429358 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -398,7 +398,7 @@ func (r *Resolver) Invalid() bool { type NameServer struct { Net string Addr string - Interface *atomic.TypedValue[string] + Interface atomic.TypedValue[string] ProxyAdapter C.ProxyAdapter ProxyName string Params map[string]string diff --git a/transport/gun/gun.go b/transport/gun/gun.go index e98f7fb5..cfe8aa3d 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -43,7 +43,7 @@ type Conn struct { transport *TransportWrap writer *io.PipeWriter once sync.Once - close *atomic.Bool + close atomic.Bool err error remain int br *bufio.Reader diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 19ce58d9..4797829f 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -29,12 +29,12 @@ func init() { type Manager struct { connections *xsync.MapOf[string, Tracker] - uploadTemp *atomic.Int64 - downloadTemp *atomic.Int64 - uploadBlip *atomic.Int64 - downloadBlip *atomic.Int64 - uploadTotal *atomic.Int64 - downloadTotal *atomic.Int64 + uploadTemp atomic.Int64 + downloadTemp atomic.Int64 + uploadBlip atomic.Int64 + downloadBlip atomic.Int64 + uploadTotal atomic.Int64 + downloadTotal atomic.Int64 process *process.Process memory uint64 } diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index f0f868de..bc2dbd5c 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -23,14 +23,14 @@ type Tracker interface { } type TrackerInfo struct { - UUID uuid.UUID `json:"id"` - Metadata *C.Metadata `json:"metadata"` - UploadTotal *atomic.Int64 `json:"upload"` - DownloadTotal *atomic.Int64 `json:"download"` - Start time.Time `json:"start"` - Chain C.Chain `json:"chains"` - Rule string `json:"rule"` - RulePayload string `json:"rulePayload"` + UUID uuid.UUID `json:"id"` + Metadata *C.Metadata `json:"metadata"` + UploadTotal atomic.Int64 `json:"upload"` + DownloadTotal atomic.Int64 `json:"download"` + Start time.Time `json:"start"` + Chain C.Chain `json:"chains"` + Rule string `json:"rule"` + RulePayload string `json:"rulePayload"` } type tcpTracker struct { From 6bcd91a801cdc0cfbf29632cb9be43520fbed2e4 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 10 Oct 2023 19:43:26 +0800 Subject: [PATCH 473/530] feat: add `skip-auth-prefixes` --- adapter/inbound/addition.go | 24 +++++++++++++++++++++--- adapter/inbound/auth.go | 27 +++++++++++++++++++++++++++ adapter/inbound/http.go | 9 +-------- adapter/inbound/https.go | 9 +-------- adapter/inbound/packet.go | 14 ++++---------- adapter/inbound/socket.go | 10 +--------- adapter/inbound/util.go | 18 +++++++++++------- config/config.go | 31 +++++++++++++++++-------------- docs/config.yaml | 5 +++++ hub/executor/executor.go | 2 ++ hub/route/configs.go | 7 +++++++ listener/http/proxy.go | 3 +++ listener/socks/tcp.go | 12 ++++++++++-- 13 files changed, 110 insertions(+), 61 deletions(-) create mode 100644 adapter/inbound/auth.go diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 327d00e9..14fc303f 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -38,9 +38,27 @@ func WithSpecialProxy(specialProxy string) Addition { func WithSrcAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - if ip, port, err := parseAddr(addr); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port + if addrPort, err := parseAddr(addr); err == nil { + metadata.SrcIP = addrPort.Addr() + metadata.SrcPort = addrPort.Port() + } + } +} + +func WithDstAddr(addr net.Addr) Addition { + return func(metadata *C.Metadata) { + if addrPort, err := parseAddr(addr); err == nil { + metadata.DstIP = addrPort.Addr() + metadata.DstPort = addrPort.Port() + } + } +} + +func WithInAddr(addr net.Addr) Addition { + return func(metadata *C.Metadata) { + if addrPort, err := parseAddr(addr); err == nil { + metadata.InIP = addrPort.Addr() + metadata.InPort = addrPort.Port() } } } diff --git a/adapter/inbound/auth.go b/adapter/inbound/auth.go new file mode 100644 index 00000000..724b5b7a --- /dev/null +++ b/adapter/inbound/auth.go @@ -0,0 +1,27 @@ +package inbound + +import ( + "net" + "net/netip" +) + +var skipAuthPrefixes []netip.Prefix + +func SetSkipAuthPrefixes(prefixes []netip.Prefix) { + skipAuthPrefixes = prefixes +} + +func SkipAuthPrefixes() []netip.Prefix { + return skipAuthPrefixes +} + +func SkipAuthRemoteAddr(addr net.Addr) bool { + if addrPort, err := parseAddr(addr); err == nil { + for _, prefix := range skipAuthPrefixes { + if prefix.Contains(addrPort.Addr()) { + return true + } + } + } + return false +} diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index b1b881ce..93ec2373 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -13,16 +13,9 @@ func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Ad metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP + additions = append(additions, WithSrcAddr(source), WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(source); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port - } - if ip, port, err := parseAddr(conn.LocalAddr()); err == nil { - metadata.InIP = ip - metadata.InPort = port - } return context.NewConnContext(conn, metadata) } diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index 485e72bb..26f93a45 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -12,16 +12,9 @@ import ( func NewHTTPS(request *http.Request, conn net.Conn, additions ...Addition) *context.ConnContext { metadata := parseHTTPAddr(request) metadata.Type = C.HTTPS + additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(conn.RemoteAddr()); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port - } - if ip, port, err := parseAddr(conn.LocalAddr()); err == nil { - metadata.InIP = ip - metadata.InPort = port - } return context.NewConnContext(conn, metadata) } diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index 44e5e1a7..d481ec09 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -21,19 +21,13 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions metadata := parseSocksAddr(target) metadata.NetWork = C.UDP metadata.Type = source + additions = append(additions, WithSrcAddr(packet.LocalAddr())) + if p, ok := packet.(C.UDPPacketInAddr); ok { + additions = append(additions, WithInAddr(p.InAddr())) + } for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(packet.LocalAddr()); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port - } - if p, ok := packet.(C.UDPPacketInAddr); ok { - if ip, port, err := parseAddr(p.InAddr()); err == nil { - metadata.InIP = ip - metadata.InPort = port - } - } return &PacketAdapter{ packet, diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index d75901f1..5892bebc 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -15,19 +15,11 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = source + additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(metadata) } - if ip, port, err := parseAddr(conn.RemoteAddr()); err == nil { - metadata.SrcIP = ip - metadata.SrcPort = port - } - if ip, port, err := parseAddr(conn.LocalAddr()); err == nil { - metadata.InIP = ip - metadata.InPort = port - } - return context.NewConnContext(conn, metadata) } diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index 626687c0..32ca9f05 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -63,21 +63,25 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } -func parseAddr(addr net.Addr) (netip.Addr, uint16, error) { +func parseAddr(addr net.Addr) (netip.AddrPort, error) { // Filter when net.Addr interface is nil if addr == nil { - return netip.Addr{}, 0, errors.New("nil addr") + return netip.AddrPort{}, errors.New("nil addr") } if rawAddr, ok := addr.(interface{ RawAddr() net.Addr }); ok { - ip, port, err := parseAddr(rawAddr.RawAddr()) - if err == nil { - return ip, port, err + if addrPort, err := parseAddr(rawAddr.RawAddr()); err == nil { + return addrPort, nil + } + } + if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { + if addrPort := addr.AddrPort(); addrPort.IsValid() { + return addrPort, nil } } addrStr := addr.String() host, port, err := net.SplitHostPort(addrStr) if err != nil { - return netip.Addr{}, 0, err + return netip.AddrPort{}, err } var uint16Port uint16 @@ -86,5 +90,5 @@ func parseAddr(addr net.Addr) (netip.Addr, uint16, error) { } ip, err := netip.ParseAddr(host) - return ip, uint16Port, err + return netip.AddrPortFrom(ip, uint16Port), err } diff --git a/config/config.go b/config/config.go index 5ea45a39..dd5ce59a 100644 --- a/config/config.go +++ b/config/config.go @@ -66,20 +66,21 @@ type General struct { // Inbound config type Inbound struct { - Port int `json:"port"` - SocksPort int `json:"socks-port"` - RedirPort int `json:"redir-port"` - TProxyPort int `json:"tproxy-port"` - MixedPort int `json:"mixed-port"` - Tun LC.Tun `json:"tun"` - TuicServer LC.TuicServer `json:"tuic-server"` - ShadowSocksConfig string `json:"ss-config"` - VmessConfig string `json:"vmess-config"` - Authentication []string `json:"authentication"` - AllowLan bool `json:"allow-lan"` - BindAddress string `json:"bind-address"` - InboundTfo bool `json:"inbound-tfo"` - InboundMPTCP bool `json:"inbound-mptcp"` + Port int `json:"port"` + SocksPort int `json:"socks-port"` + RedirPort int `json:"redir-port"` + TProxyPort int `json:"tproxy-port"` + MixedPort int `json:"mixed-port"` + Tun LC.Tun `json:"tun"` + TuicServer LC.TuicServer `json:"tuic-server"` + ShadowSocksConfig string `json:"ss-config"` + VmessConfig string `json:"vmess-config"` + Authentication []string `json:"authentication"` + SkipAuthPrefixes []netip.Prefix `json:"skip-auth-prefixes"` + AllowLan bool `json:"allow-lan"` + BindAddress string `json:"bind-address"` + InboundTfo bool `json:"inbound-tfo"` + InboundMPTCP bool `json:"inbound-mptcp"` } // Controller config @@ -271,6 +272,7 @@ type RawConfig struct { InboundTfo bool `yaml:"inbound-tfo"` InboundMPTCP bool `yaml:"inbound-mptcp"` Authentication []string `yaml:"authentication"` + SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"` AllowLan bool `yaml:"allow-lan"` BindAddress string `yaml:"bind-address"` Mode T.TunnelMode `yaml:"mode"` @@ -620,6 +622,7 @@ func parseGeneral(cfg *RawConfig) (*General, error) { ShadowSocksConfig: cfg.ShadowSocksConfig, VmessConfig: cfg.VmessConfig, AllowLan: cfg.AllowLan, + SkipAuthPrefixes: cfg.SkipAuthPrefixes, BindAddress: cfg.BindAddress, InboundTfo: cfg.InboundTfo, InboundMPTCP: cfg.InboundMPTCP, diff --git a/docs/config.yaml b/docs/config.yaml index bfcdc0cd..e829e5db 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -8,6 +8,11 @@ mixed-port: 10801 # HTTP(S) 和 SOCKS 代理混合端口 allow-lan: true # 允许局域网连接 bind-address: "*" # 绑定 IP 地址,仅作用于 allow-lan 为 true,'*'表示所有地址 +authentication: # http,socks入口的验证用户名,密码 + - "username:password" +skip-auth-prefixes: # 设置跳过验证的IP段 + - 127.0.0.1/8 + - ::1/128 # find-process-mode has 3 values:always, strict, off # - always, 开启,强制匹配所有进程 diff --git a/hub/executor/executor.go b/hub/executor/executor.go index ebcbac91..87e0e0b1 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -140,6 +140,7 @@ func GetGeneral() *config.General { ShadowSocksConfig: ports.ShadowSocksConfig, VmessConfig: ports.VmessConfig, Authentication: authenticator, + SkipAuthPrefixes: inbound.SkipAuthPrefixes(), AllowLan: listener.AllowLan(), BindAddress: listener.BindAddress(), }, @@ -164,6 +165,7 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList allowLan := general.AllowLan listener.SetAllowLan(allowLan) + inbound.SetSkipAuthPrefixes(general.SkipAuthPrefixes) bindAddress := general.BindAddress listener.SetBindAddress(bindAddress) diff --git a/hub/route/configs.go b/hub/route/configs.go index 1f29de0c..6edbf979 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -2,9 +2,11 @@ package route import ( "net/http" + "net/netip" "path/filepath" "sync" + "github.com/Dreamacro/clash/adapter/inbound" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" "github.com/Dreamacro/clash/config" @@ -47,6 +49,7 @@ type configSchema struct { TcptunConfig *string `json:"tcptun-config"` UdptunConfig *string `json:"udptun-config"` AllowLan *bool `json:"allow-lan"` + SkipAuthPrefixes *[]netip.Prefix `json:"skip-auth-prefixes"` BindAddress *string `json:"bind-address"` Mode *tunnel.TunnelMode `json:"mode"` LogLevel *log.LogLevel `json:"log-level"` @@ -231,6 +234,10 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { P.SetAllowLan(*general.AllowLan) } + if general.SkipAuthPrefixes != nil { + inbound.SetSkipAuthPrefixes(*general.SkipAuthPrefixes) + } + if general.BindAddress != nil { P.SetBindAddress(*general.BindAddress) } diff --git a/listener/http/proxy.go b/listener/http/proxy.go index a267fbad..173bb64a 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -100,6 +100,9 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool] func authenticate(request *http.Request, cache *cache.LruCache[string, bool]) *http.Response { authenticator := authStore.Authenticator() + if inbound.SkipAuthRemoteAddr(N.NewCustomAddr("", request.RemoteAddr, nil)) { + authenticator = nil + } if authenticator != nil { credential := parseBasicProxyAuthorization(request) if credential == "" { diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index 89b23562..9448f269 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -86,7 +86,11 @@ func handleSocks(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) } func HandleSocks4(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { - addr, _, err := socks4.ServerHandshake(conn, authStore.Authenticator()) + authenticator := authStore.Authenticator() + if inbound.SkipAuthRemoteAddr(conn.RemoteAddr()) { + authenticator = nil + } + addr, _, err := socks4.ServerHandshake(conn, authenticator) if err != nil { conn.Close() return @@ -95,7 +99,11 @@ func HandleSocks4(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) } func HandleSocks5(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { - target, command, err := socks5.ServerHandshake(conn, authStore.Authenticator()) + authenticator := authStore.Authenticator() + if inbound.SkipAuthRemoteAddr(conn.RemoteAddr()) { + authenticator = nil + } + target, command, err := socks5.ServerHandshake(conn, authenticator) if err != nil { conn.Close() return From 1cf9a55e3ee48e57b4feeb12fc8448b55520fd0c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 10 Oct 2023 19:49:16 +0800 Subject: [PATCH 474/530] chore: code cleanup --- config/config.go | 34 +++++++++---------- hub/route/configs.go | 30 ++++++++--------- listener/config/tun.go | 67 ++++--------------------------------- listener/inbound/tun.go | 8 ++--- listener/listener.go | 8 ++--- listener/sing_tun/server.go | 12 +++---- 6 files changed, 53 insertions(+), 106 deletions(-) diff --git a/config/config.go b/config/config.go index dd5ce59a..97a193a1 100644 --- a/config/config.go +++ b/config/config.go @@ -229,21 +229,21 @@ type RawTun struct { RedirectToTun []string `yaml:"-" json:"-"` MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` - //Inet4Address []LC.ListenPrefix `yaml:"inet4-address" json:"inet4_address,omitempty"` - Inet6Address []LC.ListenPrefix `yaml:"inet6-address" json:"inet6_address,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` - Inet4RouteAddress []LC.ListenPrefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"` - Inet6RouteAddress []LC.ListenPrefix `yaml:"inet6_route_address" json:"inet6_route_address,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` - FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` + //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6_route_address" json:"inet6_route_address,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` } type RawTuicServer struct { @@ -388,7 +388,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query AutoRoute: true, AutoDetectInterface: true, - Inet6Address: []LC.ListenPrefix{LC.ListenPrefix(netip.MustParsePrefix("fdfe:dcba:9876::1/126"))}, + Inet6Address: []netip.Prefix{netip.MustParsePrefix("fdfe:dcba:9876::1/126")}, }, TuicServer: RawTuicServer{ Enable: false, @@ -1364,7 +1364,7 @@ func parseTun(rawTun RawTun, general *General) error { RedirectToTun: rawTun.RedirectToTun, MTU: rawTun.MTU, - Inet4Address: []LC.ListenPrefix{LC.ListenPrefix(tunAddressPrefix)}, + Inet4Address: []netip.Prefix{tunAddressPrefix}, Inet6Address: rawTun.Inet6Address, StrictRoute: rawTun.StrictRoute, Inet4RouteAddress: rawTun.Inet4RouteAddress, diff --git a/hub/route/configs.go b/hub/route/configs.go index 6edbf979..cb500157 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -69,21 +69,21 @@ type tunSchema struct { //RedirectToTun []string `yaml:"-" json:"-"` MTU *uint32 `yaml:"mtu" json:"mtu,omitempty"` - //Inet4Address *[]config.ListenPrefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address *[]LC.ListenPrefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` - Inet4RouteAddress *[]LC.ListenPrefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` - Inet6RouteAddress *[]LC.ListenPrefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` - IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` - IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` - ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` - ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` - IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` - IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` - ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` - EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` - UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` - FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` + //Inet4Address *[]netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` + Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` + Inet4RouteAddress *[]netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` } type tuicServerSchema struct { diff --git a/listener/config/tun.go b/listener/config/tun.go index 50f5cf7d..06e92188 100644 --- a/listener/config/tun.go +++ b/listener/config/tun.go @@ -1,72 +1,19 @@ package config import ( - "encoding/json" "net/netip" C "github.com/Dreamacro/clash/constant" - - "gopkg.in/yaml.v3" ) -type ListenPrefix netip.Prefix - -func (p ListenPrefix) MarshalJSON() ([]byte, error) { - prefix := netip.Prefix(p) - if !prefix.IsValid() { - return json.Marshal(nil) - } - return json.Marshal(prefix.String()) -} - -func (p ListenPrefix) MarshalYAML() (interface{}, error) { - prefix := netip.Prefix(p) - if !prefix.IsValid() { - return nil, nil - } - return prefix.String(), nil -} - -func (p *ListenPrefix) UnmarshalJSON(bytes []byte) error { - var value string - err := json.Unmarshal(bytes, &value) - if err != nil { - return err - } - prefix, err := netip.ParsePrefix(value) - if err != nil { - return err - } - *p = ListenPrefix(prefix) - return nil -} - -func (p *ListenPrefix) UnmarshalYAML(node *yaml.Node) error { - var value string - err := node.Decode(&value) - if err != nil { - return err - } - prefix, err := netip.ParsePrefix(value) - if err != nil { - return err - } - *p = ListenPrefix(prefix) - return nil -} - -func (p ListenPrefix) Build() netip.Prefix { - return netip.Prefix(p) -} - -func StringSliceToListenPrefixSlice(ss []string) ([]ListenPrefix, error) { - lps := make([]ListenPrefix, 0, len(ss)) +func StringSliceToNetipPrefixSlice(ss []string) ([]netip.Prefix, error) { + lps := make([]netip.Prefix, 0, len(ss)) for _, s := range ss { prefix, err := netip.ParsePrefix(s) if err != nil { return nil, err } - lps = append(lps, ListenPrefix(prefix)) + lps = append(lps, prefix) } return lps, nil } @@ -81,11 +28,11 @@ type Tun struct { RedirectToTun []string `yaml:"-" json:"-"` MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` - Inet4Address []ListenPrefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address []ListenPrefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` - Inet4RouteAddress []ListenPrefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` - Inet6RouteAddress []ListenPrefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index 3151e6b0..9ba7ae87 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -56,19 +56,19 @@ func NewTun(options *TunOption) (*Tun, error) { if !exist { return nil, errors.New("invalid tun stack") } - inet4Address, err := LC.StringSliceToListenPrefixSlice(options.Inet4Address) + inet4Address, err := LC.StringSliceToNetipPrefixSlice(options.Inet4Address) if err != nil { return nil, err } - inet6Address, err := LC.StringSliceToListenPrefixSlice(options.Inet6Address) + inet6Address, err := LC.StringSliceToNetipPrefixSlice(options.Inet6Address) if err != nil { return nil, err } - inet4RouteAddress, err := LC.StringSliceToListenPrefixSlice(options.Inet4RouteAddress) + inet4RouteAddress, err := LC.StringSliceToNetipPrefixSlice(options.Inet4RouteAddress) if err != nil { return nil, err } - inet6RouteAddress, err := LC.StringSliceToListenPrefixSlice(options.Inet6RouteAddress) + inet6RouteAddress, err := LC.StringSliceToNetipPrefixSlice(options.Inet6RouteAddress) if err != nil { return nil, err } diff --git a/listener/listener.go b/listener/listener.go index afbcf14c..ad3b2351 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -834,19 +834,19 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { }) sort.Slice(tunConf.Inet4Address, func(i, j int) bool { - return tunConf.Inet4Address[i].Build().String() < tunConf.Inet4Address[j].Build().String() + return tunConf.Inet4Address[i].String() < tunConf.Inet4Address[j].String() }) sort.Slice(tunConf.Inet6Address, func(i, j int) bool { - return tunConf.Inet6Address[i].Build().String() < tunConf.Inet6Address[j].Build().String() + return tunConf.Inet6Address[i].String() < tunConf.Inet6Address[j].String() }) sort.Slice(tunConf.Inet4RouteAddress, func(i, j int) bool { - return tunConf.Inet4RouteAddress[i].Build().String() < tunConf.Inet4RouteAddress[j].Build().String() + return tunConf.Inet4RouteAddress[i].String() < tunConf.Inet4RouteAddress[j].String() }) sort.Slice(tunConf.Inet6RouteAddress, func(i, j int) bool { - return tunConf.Inet6RouteAddress[i].Build().String() < tunConf.Inet6RouteAddress[j].Build().String() + return tunConf.Inet6RouteAddress[i].String() < tunConf.Inet6RouteAddress[j].String() }) sort.Slice(tunConf.IncludeUID, func(i, j int) bool { diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 4ca6fc30..122e9af3 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -142,11 +142,11 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis dnsAdds = append(dnsAdds, addrPort) } for _, a := range options.Inet4Address { - addrPort := netip.AddrPortFrom(a.Build().Addr().Next(), 53) + addrPort := netip.AddrPortFrom(a.Addr().Next(), 53) dnsAdds = append(dnsAdds, addrPort) } for _, a := range options.Inet6Address { - addrPort := netip.AddrPortFrom(a.Build().Addr().Next(), 53) + addrPort := netip.AddrPortFrom(a.Addr().Next(), 53) dnsAdds = append(dnsAdds, addrPort) } @@ -201,12 +201,12 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis tunOptions := tun.Options{ Name: tunName, MTU: tunMTU, - Inet4Address: common.Map(options.Inet4Address, LC.ListenPrefix.Build), - Inet6Address: common.Map(options.Inet6Address, LC.ListenPrefix.Build), + Inet4Address: options.Inet4Address, + Inet6Address: options.Inet6Address, AutoRoute: options.AutoRoute, StrictRoute: options.StrictRoute, - Inet4RouteAddress: common.Map(options.Inet4RouteAddress, LC.ListenPrefix.Build), - Inet6RouteAddress: common.Map(options.Inet6RouteAddress, LC.ListenPrefix.Build), + Inet4RouteAddress: options.Inet4RouteAddress, + Inet6RouteAddress: options.Inet6RouteAddress, IncludeUID: includeUID, ExcludeUID: excludeUID, IncludeAndroidUser: options.IncludeAndroidUser, From 270a080b553cadeb0d9f231f8565acae3be8edc9 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 10:55:12 +0800 Subject: [PATCH 475/530] fix: sing listener panic --- adapter/inbound/http.go | 5 ++-- adapter/inbound/https.go | 5 ++-- adapter/inbound/packet.go | 18 ++------------ adapter/inbound/socket.go | 9 ++++--- constant/adapters.go | 17 ++++++++++++++ constant/tunnel.go | 6 +++-- listener/inner/tcp.go | 3 +-- listener/shadowsocks/udp.go | 2 +- listener/sing/context.go | 9 ++++++- listener/sing/sing.go | 47 ++++++++++++++++++++++++------------- listener/tuic/server.go | 9 ++++--- listener/tunnel/tcp.go | 6 ++--- listener/tunnel/udp.go | 8 +++---- tunnel/tunnel.go | 14 ++++++----- 14 files changed, 91 insertions(+), 67 deletions(-) diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 93ec2373..15376606 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -4,12 +4,11 @@ import ( "net" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/context" "github.com/Dreamacro/clash/transport/socks5" ) // NewHTTP receive normal http request and return HTTPContext -func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Addition) *context.ConnContext { +func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP @@ -17,5 +16,5 @@ func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Ad for _, addition := range additions { addition.Apply(metadata) } - return context.NewConnContext(conn, metadata) + return conn, metadata } diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index 26f93a45..7353fe59 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -5,16 +5,15 @@ import ( "net/http" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/context" ) // NewHTTPS receive CONNECT request and return ConnContext -func NewHTTPS(request *http.Request, conn net.Conn, additions ...Addition) *context.ConnContext { +func NewHTTPS(request *http.Request, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseHTTPAddr(request) metadata.Type = C.HTTPS additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(metadata) } - return context.NewConnContext(conn, metadata) + return conn, metadata } diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index d481ec09..f211f7a5 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -5,19 +5,8 @@ import ( "github.com/Dreamacro/clash/transport/socks5" ) -// PacketAdapter is a UDP Packet adapter for socks/redir/tun -type PacketAdapter struct { - C.UDPPacket - metadata *C.Metadata -} - -// Metadata returns destination metadata -func (s *PacketAdapter) Metadata() *C.Metadata { - return s.metadata -} - // NewPacket is PacketAdapter generator -func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions ...Addition) C.PacketAdapter { +func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions ...Addition) (C.UDPPacket, *C.Metadata) { metadata := parseSocksAddr(target) metadata.NetWork = C.UDP metadata.Type = source @@ -29,8 +18,5 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions addition.Apply(metadata) } - return &PacketAdapter{ - packet, - metadata, - } + return packet, metadata } diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index 5892bebc..65dbe0a2 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -6,12 +6,11 @@ import ( "strconv" C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/context" "github.com/Dreamacro/clash/transport/socks5" ) // NewSocket receive TCP inbound and return ConnContext -func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Addition) *context.ConnContext { +func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = source @@ -20,10 +19,10 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad addition.Apply(metadata) } - return context.NewConnContext(conn, metadata) + return conn, metadata } -func NewInner(conn net.Conn, address string) *context.ConnContext { +func NewInner(conn net.Conn, address string) (net.Conn, *C.Metadata) { metadata := &C.Metadata{} metadata.NetWork = C.TCP metadata.Type = C.INNER @@ -40,5 +39,5 @@ func NewInner(conn net.Conn, address string) *context.ConnContext { } } - return context.NewConnContext(conn, metadata) + return conn, metadata } diff --git a/constant/adapters.go b/constant/adapters.go index 33b9a44f..ad50a8ab 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -252,6 +252,23 @@ type PacketAdapter interface { Metadata() *Metadata } +type packetAdapter struct { + UDPPacket + metadata *Metadata +} + +// Metadata returns destination metadata +func (s *packetAdapter) Metadata() *Metadata { + return s.metadata +} + +func NewPacketAdapter(packet UDPPacket, metadata *Metadata) PacketAdapter { + return &packetAdapter{ + packet, + metadata, + } +} + type WriteBack interface { WriteBack(b []byte, addr net.Addr) (n int, err error) } diff --git a/constant/tunnel.go b/constant/tunnel.go index 39f8936a..7c9d08e2 100644 --- a/constant/tunnel.go +++ b/constant/tunnel.go @@ -1,10 +1,12 @@ package constant +import "net" + type Tunnel interface { // HandleTCPConn will handle a tcp connection blocking - HandleTCPConn(connCtx ConnContext) + HandleTCPConn(conn net.Conn, metadata *Metadata) // HandleUDPPacket will handle a udp packet nonblocking - HandleUDPPacket(packet PacketAdapter) + HandleUDPPacket(packet UDPPacket, metadata *Metadata) // NatTable return nat table NatTable() NatTable } diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index 4a54a82f..cbd27cd6 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -20,7 +20,6 @@ func HandleTcp(address string) (conn net.Conn, err error) { } // executor Parsed conn1, conn2 := net.Pipe() - context := inbound.NewInner(conn2, address) - go tunnel.HandleTCPConn(context) + go tunnel.HandleTCPConn(inbound.NewInner(conn2, address)) return conn1, nil } diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index cc055853..53f5549a 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -67,7 +67,7 @@ func handleSocksUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, put func(), } return } - target := socks5.ParseAddr(tgtAddr.String()) + target := tgtAddr payload := buf[len(tgtAddr):] packet := &packet{ diff --git a/listener/sing/context.go b/listener/sing/context.go index a500e4a4..32b2a161 100644 --- a/listener/sing/context.go +++ b/listener/sing/context.go @@ -26,7 +26,7 @@ func getAdditions(ctx context.Context) []inbound.Addition { return nil } -func combineAdditions(ctx context.Context, additions []inbound.Addition) []inbound.Addition { +func combineAdditions(ctx context.Context, additions []inbound.Addition, extraAdditions ...inbound.Addition) []inbound.Addition { additionsCloned := false if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { additions = slices.Clone(additions) @@ -40,5 +40,12 @@ func combineAdditions(ctx context.Context, additions []inbound.Addition) []inbou } additions = append(additions, inbound.WithInUser(user)) } + if len(extraAdditions) > 0 { + if !additionsCloned { + additions = slices.Clone(additions) + additionsCloned = true + } + additions = append(additions, extraAdditions...) + } return additions } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index a9bee564..301dc783 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -12,7 +12,6 @@ import ( N "github.com/Dreamacro/clash/common/net" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/socks5" vmess "github.com/metacubex/sing-vmess" mux "github.com/sagernet/sing-mux" @@ -85,15 +84,26 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta if h.IsSpecialFqdn(metadata.Destination.Fqdn) { return h.ParseSpecialFqdn(ctx, conn, metadata) } - target := socks5.ParseAddr(metadata.Destination.String()) if deadline.NeedAdditionalReadDeadline(conn) { conn = N.NewDeadlineConn(conn) // conn from sing should check NeedAdditionalReadDeadline } - connCtx := inbound.NewSocket(target, conn, h.Type, combineAdditions(ctx, h.Additions)...) - inbound.WithSrcAddr(metadata.Source.TCPAddr()).Apply(connCtx.Metadata()) // set srcAddr from sing's metadata - h.Tunnel.HandleTCPConn(connCtx) // this goroutine must exit after conn unused + cMetadata := &C.Metadata{ + NetWork: C.TCP, + Type: h.Type, + Host: metadata.Destination.Fqdn, + DstIP: metadata.Destination.Addr, + DstPort: metadata.Destination.Port, + SrcIP: metadata.Source.Addr, + SrcPort: metadata.Source.Port, + } + additions := combineAdditions(ctx, h.Additions, inbound.WithInAddr(conn.LocalAddr())) + for _, addition := range additions { + addition.Apply(cMetadata) + } + + h.Tunnel.HandleTCPConn(conn, cMetadata) // this goroutine must exit after conn unused return nil } @@ -138,8 +148,7 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. } return err } - target := socks5.ParseAddr(dest.String()) - packet := &packet{ + cPacket := &packet{ conn: &conn2, mutex: &mutex, rAddr: metadata.Source.UDPAddr(), @@ -147,7 +156,21 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. buff: buff, } - h.Tunnel.HandleUDPPacket(inbound.NewPacket(target, packet, h.Type, combineAdditions(ctx, h.Additions)...)) + cMetadata := &C.Metadata{ + NetWork: C.UDP, + Type: h.Type, + Host: dest.Fqdn, + DstIP: dest.Addr, + DstPort: dest.Port, + SrcIP: metadata.Source.Addr, + SrcPort: metadata.Source.Port, + } + additions := combineAdditions(ctx, h.Additions, inbound.WithInAddr(conn.LocalAddr())) + for _, addition := range additions { + addition.Apply(cMetadata) + } + + h.Tunnel.HandleUDPPacket(cPacket, cMetadata) } return nil } @@ -215,11 +238,3 @@ func (c *packet) Drop() { func (c *packet) InAddr() net.Addr { return c.lAddr } - -func (c *packet) SetNatTable(natTable C.NatTable) { - // no need -} - -func (c *packet) SetUdpInChan(in chan<- C.PacketAdapter) { - // no need -} diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 70cf4a01..544f1328 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -94,19 +94,18 @@ func New(config LC.TuicServer, tunnel C.Tunnel, additions ...inbound.Addition) ( newAdditions = slices.Clone(additions) newAdditions = append(newAdditions, _additions...) } - connCtx := inbound.NewSocket(addr, conn, C.TUIC, newAdditions...) - metadata := sing.ConvertMetadata(connCtx.Metadata()) - if h.IsSpecialFqdn(metadata.Destination.Fqdn) { + conn, metadata := inbound.NewSocket(addr, conn, C.TUIC, newAdditions...) + if h.IsSpecialFqdn(metadata.Host) { go func() { // ParseSpecialFqdn will block, so open a new goroutine _ = h.ParseSpecialFqdn( sing.WithAdditions(context.Background(), newAdditions...), conn, - metadata, + sing.ConvertMetadata(metadata), ) }() return nil } - go tunnel.HandleTCPConn(connCtx) + go tunnel.HandleTCPConn(conn, metadata) return nil } handleUdpFn := func(addr socks5.Addr, packet C.UDPPacket, _additions ...inbound.Addition) error { diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index 8cc527fb..dd2059db 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -36,9 +36,9 @@ func (l *Listener) Close() error { func (l *Listener) handleTCP(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { N.TCPKeepAlive(conn) - ctx := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...) - ctx.Metadata().SpecialProxy = l.proxy - tunnel.HandleTCPConn(ctx) + conn, metadata := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...) + metadata.SpecialProxy = l.proxy + tunnel.HandleTCPConn(conn, metadata) } func New(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { diff --git a/listener/tunnel/udp.go b/listener/tunnel/udp.go index c2f1dcc3..38b779c4 100644 --- a/listener/tunnel/udp.go +++ b/listener/tunnel/udp.go @@ -70,13 +70,13 @@ func NewUDP(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Ad } func (l *PacketConn) handleUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, addr net.Addr, additions ...inbound.Addition) { - packet := &packet{ + cPacket := &packet{ pc: pc, rAddr: addr, payload: buf, } - ctx := inbound.NewPacket(l.target, packet, C.TUNNEL, additions...) - ctx.Metadata().SpecialProxy = l.proxy - tunnel.HandleUDPPacket(ctx) + packet, metadata := inbound.NewPacket(l.target, cPacket, C.TUNNEL, additions...) + metadata.SpecialProxy = l.proxy + tunnel.HandleUDPPacket(packet, metadata) } diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 1e73a833..13bf6d8c 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -53,13 +53,15 @@ type tunnel struct{} var Tunnel C.Tunnel = tunnel{} -func (t tunnel) HandleTCPConn(connCtx C.ConnContext) { +func (t tunnel) HandleTCPConn(conn net.Conn, metadata *C.Metadata) { + connCtx := icontext.NewConnContext(conn, metadata) handleTCPConn(connCtx) } -func (t tunnel) HandleUDPPacket(packet C.PacketAdapter) { +func (t tunnel) HandleUDPPacket(packet C.UDPPacket, metadata *C.Metadata) { + packetAdapter := C.NewPacketAdapter(packet, metadata) select { - case udpQueue <- packet: + case udpQueue <- packetAdapter: default: } } @@ -274,7 +276,7 @@ func preHandleMetadata(metadata *C.Metadata) error { return nil } -func resolveMetadata(ctx C.PlainContext, metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) { +func resolveMetadata(metadata *C.Metadata) (proxy C.Proxy, rule C.Rule, err error) { if metadata.SpecialProxy != "" { var exist bool proxy, exist = proxies[metadata.SpecialProxy] @@ -369,7 +371,7 @@ func handleUDPConn(packet C.PacketAdapter) { }() pCtx := icontext.NewPacketConnContext(metadata) - proxy, rule, err := resolveMetadata(pCtx, metadata) + proxy, rule, err := resolveMetadata(metadata) if err != nil { log.Warnln("[UDP] Parse metadata failed: %s", err.Error()) return @@ -477,7 +479,7 @@ func handleTCPConn(connCtx C.ConnContext) { }() } - proxy, rule, err := resolveMetadata(connCtx, metadata) + proxy, rule, err := resolveMetadata(metadata) if err != nil { log.Warnln("[Metadata] parse failed: %s", err.Error()) return From 9a16eb289565406c3b2a4bd6ec933b920da5037e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 11:01:17 +0800 Subject: [PATCH 476/530] fix: BBR memory leak from: https://github.com/apernet/hysteria/commit/7c46e845a6e4d1355c1a4515fb8e94ebec2c89c3 --- transport/tuic/congestion_v2/bbr_sender.go | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/transport/tuic/congestion_v2/bbr_sender.go b/transport/tuic/congestion_v2/bbr_sender.go index 68c10d20..084f85b1 100644 --- a/transport/tuic/congestion_v2/bbr_sender.go +++ b/transport/tuic/congestion_v2/bbr_sender.go @@ -484,10 +484,19 @@ func (b *bbrSender) OnCongestionEventEx(priorInFlight congestion.ByteCount, even b.calculateRecoveryWindow(bytesAcked, bytesLost) // Cleanup internal state. - if len(lostPackets) != 0 { - lastLostPacket := lostPackets[len(lostPackets)-1].PacketNumber - b.sampler.RemoveObsoletePackets(lastLostPacket) + // This is where we clean up obsolete (acked or lost) packets from the bandwidth sampler. + // The "least unacked" should actually be FirstOutstanding, but since we are not passing + // that through OnCongestionEventEx, we will only do an estimate using acked/lost packets + // for now. Because of fast retransmission, they should differ by no more than 2 packets. + // (this is controlled by packetThreshold in quic-go's sentPacketHandler) + var leastUnacked congestion.PacketNumber + if len(ackedPackets) != 0 { + leastUnacked = ackedPackets[len(ackedPackets)-1].PacketNumber - 2 + } else { + leastUnacked = lostPackets[len(lostPackets)-1].PacketNumber + 1 } + b.sampler.RemoveObsoletePackets(leastUnacked) + if isRoundStart { b.numLossEventsInRound = 0 b.bytesLostInRound = 0 From 4636499439d7d549b4ddeb178f071508d9ff96e2 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 13:01:14 +0800 Subject: [PATCH 477/530] chore: support reject proxy type --- adapter/inbound/socket.go | 22 ---------------------- adapter/outbound/reject.go | 14 ++++++++++++++ adapter/parser.go | 7 +++++++ listener/inner/tcp.go | 22 ++++++++++++++++++++-- 4 files changed, 41 insertions(+), 24 deletions(-) diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index 65dbe0a2..dbe1712d 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -2,8 +2,6 @@ package inbound import ( "net" - "net/netip" - "strconv" C "github.com/Dreamacro/clash/constant" "github.com/Dreamacro/clash/transport/socks5" @@ -21,23 +19,3 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad return conn, metadata } - -func NewInner(conn net.Conn, address string) (net.Conn, *C.Metadata) { - metadata := &C.Metadata{} - metadata.NetWork = C.TCP - metadata.Type = C.INNER - metadata.DNSMode = C.DNSNormal - metadata.Process = C.ClashName - if h, port, err := net.SplitHostPort(address); err == nil { - 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 { - metadata.Host = h - } - } - - return conn, metadata -} diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index a72dc377..f1de3981 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -15,6 +15,10 @@ type Reject struct { *Base } +type RejectOption struct { + Name string `proxy:"name"` +} + // DialContext implements C.ProxyAdapter func (r *Reject) DialContext(ctx context.Context, metadata *C.Metadata, opts ...dialer.Option) (C.Conn, error) { return NewConn(nopConn{}, r), nil @@ -25,6 +29,16 @@ func (r *Reject) ListenPacketContext(ctx context.Context, metadata *C.Metadata, return newPacketConn(nopPacketConn{}, r), nil } +func NewRejectWithOption(option RejectOption) *Reject { + return &Reject{ + Base: &Base{ + name: option.Name, + tp: C.Direct, + udp: true, + }, + } +} + func NewReject() *Reject { return &Reject{ Base: &Base{ diff --git a/adapter/parser.go b/adapter/parser.go index eeb0fd59..43ebfe5f 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -120,6 +120,13 @@ func ParseProxy(mapping map[string]any) (C.Proxy, error) { break } proxy = outbound.NewDirectWithOption(*directOption) + case "reject": + rejectOption := &outbound.RejectOption{} + err = decoder.Decode(mapping, rejectOption) + if err != nil { + break + } + proxy = outbound.NewRejectWithOption(*rejectOption) default: return nil, fmt.Errorf("unsupport proxy type: %s", proxyType) } diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index cbd27cd6..8973c431 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -3,8 +3,9 @@ package inner import ( "errors" "net" + "net/netip" + "strconv" - "github.com/Dreamacro/clash/adapter/inbound" C "github.com/Dreamacro/clash/constant" ) @@ -20,6 +21,23 @@ func HandleTcp(address string) (conn net.Conn, err error) { } // executor Parsed conn1, conn2 := net.Pipe() - go tunnel.HandleTCPConn(inbound.NewInner(conn2, address)) + + metadata := &C.Metadata{} + metadata.NetWork = C.TCP + metadata.Type = C.INNER + metadata.DNSMode = C.DNSNormal + metadata.Process = C.ClashName + if h, port, err := net.SplitHostPort(address); err == nil { + 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 { + metadata.Host = h + } + } + + go tunnel.HandleTCPConn(conn2, metadata) return conn1, nil } From 0dc6a726c1f56f32d690bc5a480e983057d9837f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 18:17:39 +0800 Subject: [PATCH 478/530] fix: unmap 4in6 ip --- adapter/inbound/addition.go | 21 +++++++++------------ adapter/inbound/auth.go | 4 ++-- adapter/inbound/util.go | 21 +++++++++------------ listener/sing/sing.go | 12 ++---------- 4 files changed, 22 insertions(+), 36 deletions(-) diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 14fc303f..2754ee1e 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -38,27 +38,24 @@ func WithSpecialProxy(specialProxy string) Addition { func WithSrcAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - if addrPort, err := parseAddr(addr); err == nil { - metadata.SrcIP = addrPort.Addr() - metadata.SrcPort = addrPort.Port() - } + addrPort := parseAddr(addr) + metadata.SrcIP = addrPort.Addr().Unmap() + metadata.SrcPort = addrPort.Port() } } func WithDstAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - if addrPort, err := parseAddr(addr); err == nil { - metadata.DstIP = addrPort.Addr() - metadata.DstPort = addrPort.Port() - } + addrPort := parseAddr(addr) + metadata.DstIP = addrPort.Addr().Unmap() + metadata.DstPort = addrPort.Port() } } func WithInAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - if addrPort, err := parseAddr(addr); err == nil { - metadata.InIP = addrPort.Addr() - metadata.InPort = addrPort.Port() - } + addrPort := parseAddr(addr) + metadata.InIP = addrPort.Addr().Unmap() + metadata.InPort = addrPort.Port() } } diff --git a/adapter/inbound/auth.go b/adapter/inbound/auth.go index 724b5b7a..93c56c99 100644 --- a/adapter/inbound/auth.go +++ b/adapter/inbound/auth.go @@ -16,9 +16,9 @@ func SkipAuthPrefixes() []netip.Prefix { } func SkipAuthRemoteAddr(addr net.Addr) bool { - if addrPort, err := parseAddr(addr); err == nil { + if addrPort := parseAddr(addr); addrPort.IsValid() { for _, prefix := range skipAuthPrefixes { - if prefix.Contains(addrPort.Addr()) { + if prefix.Contains(addrPort.Addr().Unmap()) { return true } } diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index 32ca9f05..e4d2630d 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -1,7 +1,6 @@ package inbound import ( - "errors" "net" "net/http" "net/netip" @@ -63,25 +62,23 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } -func parseAddr(addr net.Addr) (netip.AddrPort, error) { +func parseAddr(addr net.Addr) netip.AddrPort { // Filter when net.Addr interface is nil if addr == nil { - return netip.AddrPort{}, errors.New("nil addr") + return netip.AddrPort{} } - if rawAddr, ok := addr.(interface{ RawAddr() net.Addr }); ok { - if addrPort, err := parseAddr(rawAddr.RawAddr()); err == nil { - return addrPort, nil + if addr, ok := addr.(interface{ RawAddr() net.Addr }); ok { + if rawAddr := addr.RawAddr(); rawAddr != nil { + return parseAddr(rawAddr) } } if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { - if addrPort := addr.AddrPort(); addrPort.IsValid() { - return addrPort, nil - } + return addr.AddrPort() } addrStr := addr.String() host, port, err := net.SplitHostPort(addrStr) if err != nil { - return netip.AddrPort{}, err + return netip.AddrPort{} } var uint16Port uint16 @@ -89,6 +86,6 @@ func parseAddr(addr net.Addr) (netip.AddrPort, error) { uint16Port = uint16(port) } - ip, err := netip.ParseAddr(host) - return netip.AddrPortFrom(ip, uint16Port), err + ip, _ := netip.ParseAddr(host) + return netip.AddrPortFrom(ip, uint16Port) } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 301dc783..d03bebb1 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -93,12 +93,8 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta NetWork: C.TCP, Type: h.Type, Host: metadata.Destination.Fqdn, - DstIP: metadata.Destination.Addr, - DstPort: metadata.Destination.Port, - SrcIP: metadata.Source.Addr, - SrcPort: metadata.Source.Port, } - additions := combineAdditions(ctx, h.Additions, inbound.WithInAddr(conn.LocalAddr())) + additions := combineAdditions(ctx, h.Additions, inbound.WithDstAddr(metadata.Destination), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(cMetadata) } @@ -160,12 +156,8 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. NetWork: C.UDP, Type: h.Type, Host: dest.Fqdn, - DstIP: dest.Addr, - DstPort: dest.Port, - SrcIP: metadata.Source.Addr, - SrcPort: metadata.Source.Port, } - additions := combineAdditions(ctx, h.Additions, inbound.WithInAddr(conn.LocalAddr())) + additions := combineAdditions(ctx, h.Additions, inbound.WithDstAddr(dest), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) for _, addition := range additions { addition.Apply(cMetadata) } From 129283066fbf3bbb217833fff65ff5f9d875ee16 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 11 Oct 2023 22:54:19 +0800 Subject: [PATCH 479/530] chore: code cleanup --- adapter/inbound/addition.go | 30 ++++++++++++++++------------ adapter/inbound/auth.go | 22 ++++++++++++++++++-- adapter/inbound/http.go | 6 ++---- adapter/inbound/https.go | 6 ++---- adapter/inbound/packet.go | 8 +++----- adapter/inbound/socket.go | 7 ++----- adapter/inbound/util.go | 28 -------------------------- component/proxydialer/proxydialer.go | 5 +---- constant/metadata.go | 28 ++++++++++++++++++++++++++ listener/http/proxy.go | 2 +- listener/sing/context.go | 28 ++++---------------------- listener/sing/sing.go | 16 ++++++--------- listener/tunnel/tcp.go | 8 +++++--- listener/tunnel/udp.go | 9 ++++++--- 14 files changed, 97 insertions(+), 106 deletions(-) diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index 2754ee1e..df03b84a 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -8,8 +8,10 @@ import ( type Addition func(metadata *C.Metadata) -func (a Addition) Apply(metadata *C.Metadata) { - a(metadata) +func ApplyAdditions(metadata *C.Metadata, additions ...Addition) { + for _, addition := range additions { + addition(metadata) + } } func WithInName(name string) Addition { @@ -36,26 +38,28 @@ func WithSpecialProxy(specialProxy string) Addition { } } -func WithSrcAddr(addr net.Addr) Addition { +func WithDstAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - addrPort := parseAddr(addr) - metadata.SrcIP = addrPort.Addr().Unmap() - metadata.SrcPort = addrPort.Port() + _ = metadata.SetRemoteAddr(addr) } } -func WithDstAddr(addr net.Addr) Addition { +func WithSrcAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - addrPort := parseAddr(addr) - metadata.DstIP = addrPort.Addr().Unmap() - metadata.DstPort = addrPort.Port() + m := C.Metadata{} + if err := m.SetRemoteAddr(addr);err ==nil{ + metadata.SrcIP = m.DstIP + metadata.SrcPort = m.DstPort + } } } func WithInAddr(addr net.Addr) Addition { return func(metadata *C.Metadata) { - addrPort := parseAddr(addr) - metadata.InIP = addrPort.Addr().Unmap() - metadata.InPort = addrPort.Port() + m := C.Metadata{} + if err := m.SetRemoteAddr(addr);err ==nil{ + metadata.InIP = m.DstIP + metadata.InPort = m.DstPort + } } } diff --git a/adapter/inbound/auth.go b/adapter/inbound/auth.go index 93c56c99..4022659f 100644 --- a/adapter/inbound/auth.go +++ b/adapter/inbound/auth.go @@ -3,6 +3,8 @@ package inbound import ( "net" "net/netip" + + C "github.com/Dreamacro/clash/constant" ) var skipAuthPrefixes []netip.Prefix @@ -16,9 +18,25 @@ func SkipAuthPrefixes() []netip.Prefix { } func SkipAuthRemoteAddr(addr net.Addr) bool { - if addrPort := parseAddr(addr); addrPort.IsValid() { + m := C.Metadata{} + if err := m.SetRemoteAddr(addr); err != nil { + return false + } + return skipAuth(m.AddrPort().Addr()) +} + +func SkipAuthRemoteAddress(addr string) bool { + m := C.Metadata{} + if err := m.SetRemoteAddress(addr); err != nil { + return false + } + return skipAuth(m.AddrPort().Addr()) +} + +func skipAuth(addr netip.Addr) bool { + if addr.IsValid() { for _, prefix := range skipAuthPrefixes { - if prefix.Contains(addrPort.Addr().Unmap()) { + if prefix.Contains(addr.Unmap()) { return true } } diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 15376606..2a6050e5 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -12,9 +12,7 @@ func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Ad metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP - additions = append(additions, WithSrcAddr(source), WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(metadata) - } + ApplyAdditions(metadata, WithSrcAddr(source), WithInAddr(conn.LocalAddr())) + ApplyAdditions(metadata, additions...) return conn, metadata } diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index 7353fe59..891ac9e7 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -11,9 +11,7 @@ import ( func NewHTTPS(request *http.Request, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseHTTPAddr(request) metadata.Type = C.HTTPS - additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(metadata) - } + ApplyAdditions(metadata, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) + ApplyAdditions(metadata, additions...) return conn, metadata } diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index f211f7a5..0e3f6c48 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -10,13 +10,11 @@ func NewPacket(target socks5.Addr, packet C.UDPPacket, source C.Type, additions metadata := parseSocksAddr(target) metadata.NetWork = C.UDP metadata.Type = source - additions = append(additions, WithSrcAddr(packet.LocalAddr())) + ApplyAdditions(metadata, WithSrcAddr(packet.LocalAddr())) if p, ok := packet.(C.UDPPacketInAddr); ok { - additions = append(additions, WithInAddr(p.InAddr())) - } - for _, addition := range additions { - addition.Apply(metadata) + ApplyAdditions(metadata, WithInAddr(p.InAddr())) } + ApplyAdditions(metadata, additions...) return packet, metadata } diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index dbe1712d..21cb490b 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -12,10 +12,7 @@ func NewSocket(target socks5.Addr, conn net.Conn, source C.Type, additions ...Ad metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = source - additions = append(additions, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(metadata) - } - + ApplyAdditions(metadata, WithSrcAddr(conn.RemoteAddr()), WithInAddr(conn.LocalAddr())) + ApplyAdditions(metadata, additions...) return conn, metadata } diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index e4d2630d..acae7c3e 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -61,31 +61,3 @@ func parseHTTPAddr(request *http.Request) *C.Metadata { return metadata } - -func parseAddr(addr net.Addr) netip.AddrPort { - // Filter when net.Addr interface is nil - if addr == nil { - return netip.AddrPort{} - } - if addr, ok := addr.(interface{ RawAddr() net.Addr }); ok { - if rawAddr := addr.RawAddr(); rawAddr != nil { - return parseAddr(rawAddr) - } - } - if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { - return addr.AddrPort() - } - addrStr := addr.String() - host, port, err := net.SplitHostPort(addrStr) - if err != nil { - return netip.AddrPort{} - } - - var uint16Port uint16 - if port, err := strconv.ParseUint(port, 10, 16); err == nil { - uint16Port = uint16(port) - } - - ip, _ := netip.ParseAddr(host) - return netip.AddrPortFrom(ip, uint16Port) -} diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index 83010f96..2d14abae 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -70,10 +70,7 @@ func (p proxyDialer) DialContext(ctx context.Context, network, address string) ( } func (p proxyDialer) ListenPacket(ctx context.Context, network, address string, rAddrPort netip.AddrPort) (net.PacketConn, error) { - currentMeta := &C.Metadata{Type: C.INNER} - if err := currentMeta.SetRemoteAddress(rAddrPort.String()); err != nil { - return nil, err - } + currentMeta := &C.Metadata{Type: C.INNER, DstIP: rAddrPort.Addr(), DstPort: rAddrPort.Port()} return p.listenPacket(ctx, currentMeta) } diff --git a/constant/metadata.go b/constant/metadata.go index 70478911..5f472205 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -240,6 +240,34 @@ func (m *Metadata) Valid() bool { return m.Host != "" || m.DstIP.IsValid() } +func (m *Metadata) SetRemoteAddr(addr net.Addr) error { + if addr == nil { + return nil + } + if rawAddr, ok := addr.(interface{ RawAddr() net.Addr }); ok { + if rawAddr := rawAddr.RawAddr(); rawAddr != nil { + if err := m.SetRemoteAddr(rawAddr); err == nil { + return nil + } + } + } + if addr, ok := addr.(interface{ AddrPort() netip.AddrPort }); ok { // *net.TCPAddr, *net.UDPAddr, M.Socksaddr + if addrPort := addr.AddrPort(); addrPort.Port() != 0 { + m.DstPort = addrPort.Port() + if addrPort.IsValid() { // sing's M.Socksaddr maybe return an invalid AddrPort if it's a DomainName + m.DstIP = addrPort.Addr().Unmap() + return nil + } else { + if addr, ok := addr.(interface{ AddrString() string }); ok { // must be sing's M.Socksaddr + m.Host = addr.AddrString() // actually is M.Socksaddr.Fqdn + return nil + } + } + } + } + return m.SetRemoteAddress(addr.String()) +} + func (m *Metadata) SetRemoteAddress(rawAddress string) error { host, port, err := net.SplitHostPort(rawAddress) if err != nil { diff --git a/listener/http/proxy.go b/listener/http/proxy.go index 173bb64a..44ff04c7 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -100,7 +100,7 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool] func authenticate(request *http.Request, cache *cache.LruCache[string, bool]) *http.Response { authenticator := authStore.Authenticator() - if inbound.SkipAuthRemoteAddr(N.NewCustomAddr("", request.RemoteAddr, nil)) { + if inbound.SkipAuthRemoteAddress(request.RemoteAddr) { authenticator = nil } if authenticator != nil { diff --git a/listener/sing/context.go b/listener/sing/context.go index 32b2a161..4204757a 100644 --- a/listener/sing/context.go +++ b/listener/sing/context.go @@ -17,35 +17,15 @@ func WithAdditions(ctx context.Context, additions ...inbound.Addition) context.C return context.WithValue(ctx, ctxKeyAdditions, additions) } -func getAdditions(ctx context.Context) []inbound.Addition { +func getAdditions(ctx context.Context) (additions []inbound.Addition) { if v := ctx.Value(ctxKeyAdditions); v != nil { if a, ok := v.([]inbound.Addition); ok { - return a + additions = a } } - return nil -} - -func combineAdditions(ctx context.Context, additions []inbound.Addition, extraAdditions ...inbound.Addition) []inbound.Addition { - additionsCloned := false - if ctxAdditions := getAdditions(ctx); len(ctxAdditions) > 0 { - additions = slices.Clone(additions) - additionsCloned = true - additions = append(additions, ctxAdditions...) - } if user, ok := auth.UserFromContext[string](ctx); ok { - if !additionsCloned { - additions = slices.Clone(additions) - additionsCloned = true - } + additions = slices.Clone(additions) additions = append(additions, inbound.WithInUser(user)) } - if len(extraAdditions) > 0 { - if !additionsCloned { - additions = slices.Clone(additions) - additionsCloned = true - } - additions = append(additions, extraAdditions...) - } - return additions + return } diff --git a/listener/sing/sing.go b/listener/sing/sing.go index d03bebb1..1837951d 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -92,12 +92,10 @@ func (h *ListenerHandler) NewConnection(ctx context.Context, conn net.Conn, meta cMetadata := &C.Metadata{ NetWork: C.TCP, Type: h.Type, - Host: metadata.Destination.Fqdn, - } - additions := combineAdditions(ctx, h.Additions, inbound.WithDstAddr(metadata.Destination), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(cMetadata) } + inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(metadata.Destination), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) + inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) + inbound.ApplyAdditions(cMetadata, h.Additions...) h.Tunnel.HandleTCPConn(conn, cMetadata) // this goroutine must exit after conn unused return nil @@ -155,12 +153,10 @@ func (h *ListenerHandler) NewPacketConnection(ctx context.Context, conn network. cMetadata := &C.Metadata{ NetWork: C.UDP, Type: h.Type, - Host: dest.Fqdn, - } - additions := combineAdditions(ctx, h.Additions, inbound.WithDstAddr(dest), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) - for _, addition := range additions { - addition.Apply(cMetadata) } + inbound.ApplyAdditions(cMetadata, inbound.WithDstAddr(dest), inbound.WithSrcAddr(metadata.Source), inbound.WithInAddr(conn.LocalAddr())) + inbound.ApplyAdditions(cMetadata, getAdditions(ctx)...) + inbound.ApplyAdditions(cMetadata, h.Additions...) h.Tunnel.HandleUDPPacket(cPacket, cMetadata) } diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index dd2059db..9fca14dd 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -36,9 +36,7 @@ func (l *Listener) Close() error { func (l *Listener) handleTCP(conn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) { N.TCPKeepAlive(conn) - conn, metadata := inbound.NewSocket(l.target, conn, C.TUNNEL, additions...) - metadata.SpecialProxy = l.proxy - tunnel.HandleTCPConn(conn, metadata) + tunnel.HandleTCPConn(inbound.NewSocket(l.target, conn, C.TUNNEL, additions...)) } func New(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addition) (*Listener, error) { @@ -59,6 +57,10 @@ func New(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Addit addr: addr, } + if proxy != "" { + additions = append([]inbound.Addition{inbound.WithSpecialProxy(proxy)}, additions...) + } + go func() { for { c, err := l.Accept() diff --git a/listener/tunnel/udp.go b/listener/tunnel/udp.go index 38b779c4..00d61663 100644 --- a/listener/tunnel/udp.go +++ b/listener/tunnel/udp.go @@ -51,6 +51,11 @@ func NewUDP(addr, target, proxy string, tunnel C.Tunnel, additions ...inbound.Ad proxy: proxy, addr: addr, } + + if proxy != "" { + additions = append([]inbound.Addition{inbound.WithSpecialProxy(proxy)}, additions...) + } + go func() { for { buf := pool.Get(pool.UDPBufferSize) @@ -76,7 +81,5 @@ func (l *PacketConn) handleUDP(pc net.PacketConn, tunnel C.Tunnel, buf []byte, a payload: buf, } - packet, metadata := inbound.NewPacket(l.target, cPacket, C.TUNNEL, additions...) - metadata.SpecialProxy = l.proxy - tunnel.HandleUDPPacket(packet, metadata) + tunnel.HandleUDPPacket(inbound.NewPacket(l.target, cPacket, C.TUNNEL, additions...)) } From 9f530525d7fe6812567ee8a1254878f4228af85b Mon Sep 17 00:00:00 2001 From: sduoduo233 <85996970+sduoduo233@users.noreply.github.com> Date: Mon, 16 Oct 2023 09:16:36 +0800 Subject: [PATCH 480/530] fix: method in vmess http-opts is not used --- common/util/manipulation.go | 8 ++++++++ transport/vmess/http.go | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 common/util/manipulation.go diff --git a/common/util/manipulation.go b/common/util/manipulation.go new file mode 100644 index 00000000..d2c861eb --- /dev/null +++ b/common/util/manipulation.go @@ -0,0 +1,8 @@ +package util + +import "github.com/samber/lo" + +func EmptyOr[T comparable](v T, def T) T { + ret, _ := lo.Coalesce(v, def) + return ret +} diff --git a/transport/vmess/http.go b/transport/vmess/http.go index c4f27c4c..d9e73f68 100644 --- a/transport/vmess/http.go +++ b/transport/vmess/http.go @@ -8,6 +8,8 @@ import ( "net/http" "net/textproto" + "github.com/Dreamacro/clash/common/util" + "github.com/zhangyunhao116/fastrand" ) @@ -59,7 +61,7 @@ func (hc *httpConn) Write(b []byte) (int, error) { } u := fmt.Sprintf("http://%s%s", host, path) - req, _ := http.NewRequest("GET", u, bytes.NewBuffer(b)) + req, _ := http.NewRequest(util.EmptyOr(hc.cfg.Method, http.MethodGet), u, bytes.NewBuffer(b)) for key, list := range hc.cfg.Headers { req.Header.Set(key, list[fastrand.Intn(len(list))]) } From 81bbbe4eece2ca88a33d813f3935c2ad2cbe8a55 Mon Sep 17 00:00:00 2001 From: Jiahao Lu Date: Mon, 16 Oct 2023 09:21:06 +0800 Subject: [PATCH 481/530] fix: DNS NCACHE TTL and OPT RRs (#2900) * Fix: DNS NCACHE TTL and OPT RRs 1. DNS NCACHE was not correctly implemented. 2. OPT RRs must not be cached or forwarded. Closes #2889. --- dns/resolver.go | 6 +++++- dns/util.go | 47 +++++++++++++++++++++++------------------------ 2 files changed, 28 insertions(+), 25 deletions(-) diff --git a/dns/resolver.go b/dns/resolver.go index 2c429358..4696515f 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -195,7 +195,11 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M msg := result.(*D.Msg) if cache { - putMsgToCache(r.lruCache, q.String(), msg) + // OPT RRs MUST NOT be cached, forwarded, or stored in or loaded from master files. + msg.Extra = lo.Filter(msg.Extra, func(rr D.RR, index int) bool { + return rr.Header().Rrtype != D.TypeOPT + }) + putMsgToCache(r.lruCache, q.String(), q, msg) } }() diff --git a/dns/util.go b/dns/util.go index 29de4e2a..433ea9e2 100644 --- a/dns/util.go +++ b/dns/util.go @@ -29,14 +29,16 @@ const ( MaxMsgSize = 65535 ) +const serverFailureCacheTTL uint32 = 5 + func minimalTTL(records []D.RR) uint32 { - minObj := lo.MinBy(records, func(r1 D.RR, r2 D.RR) bool { + rr := lo.MinBy(records, func(r1 D.RR, r2 D.RR) bool { return r1.Header().Ttl < r2.Header().Ttl }) - if minObj != nil { - return minObj.Header().Ttl + if rr == nil { + return 0 } - return 0 + return rr.Header().Ttl } func updateTTL(records []D.RR, ttl uint32) { @@ -49,28 +51,25 @@ func updateTTL(records []D.RR, ttl uint32) { } } -func putMsgToCache(c *cache.LruCache[string, *D.Msg], key string, msg *D.Msg) { - putMsgToCacheWithExpire(c, key, msg, 0) -} - -func putMsgToCacheWithExpire(c *cache.LruCache[string, *D.Msg], key string, msg *D.Msg, sec uint32) { - if sec == 0 { - if sec = minimalTTL(msg.Answer); sec == 0 { - if sec = minimalTTL(msg.Ns); sec == 0 { - sec = minimalTTL(msg.Extra) - } - } - if sec == 0 { - return - } - - if sec > 120 { - sec = 120 // at least 2 minutes to cache - } - +func putMsgToCache(c *cache.LruCache[string, *D.Msg], key string, q D.Question, msg *D.Msg) { + // skip dns cache for acme challenge + if q.Qtype == D.TypeTXT && strings.HasPrefix(q.Name, "_acme-challenge.") { + log.Debugln("[DNS] dns cache ignored because of acme challenge for: %s", q.Name) + return } - c.SetWithExpire(key, msg.Copy(), time.Now().Add(time.Duration(sec)*time.Second)) + var ttl uint32 + if msg.Rcode == D.RcodeServerFailure { + // [...] a resolver MAY cache a server failure response. + // If it does so it MUST NOT cache it for longer than five (5) minutes [...] + ttl = serverFailureCacheTTL + } else { + ttl = minimalTTL(append(append(msg.Answer, msg.Ns...), msg.Extra...)) + } + if ttl == 0 { + return + } + c.SetWithExpire(key, msg.Copy(), time.Now().Add(time.Duration(ttl)*time.Second)) } func setMsgTTL(msg *D.Msg, ttl uint32) { From 98df77439c036d0c9d76924854c714e5f41d02be Mon Sep 17 00:00:00 2001 From: septs Date: Mon, 16 Oct 2023 09:22:16 +0800 Subject: [PATCH 482/530] feature: add environs startup option support (#2909) --- main.go | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/main.go b/main.go index e9f66058..d41450b6 100644 --- a/main.go +++ b/main.go @@ -21,7 +21,6 @@ import ( ) var ( - flagset map[string]bool version bool testConfig bool geodataMode bool @@ -33,20 +32,15 @@ var ( ) func init() { - flag.StringVar(&homeDir, "d", "", "set configuration directory") - flag.StringVar(&configFile, "f", "", "specify configuration file") - flag.StringVar(&externalUI, "ext-ui", "", "override external ui directory") - flag.StringVar(&externalController, "ext-ctl", "", "override external controller address") - flag.StringVar(&secret, "secret", "", "override secret for RESTful API") + flag.StringVar(&homeDir, "d", os.Getenv("CLASH_HOME_DIR"), "set configuration directory") + flag.StringVar(&configFile, "f", os.Getenv("CLASH_CONFIG_FILE"), "specify configuration file") + flag.StringVar(&externalUI, "ext-ui", os.Getenv("CLASH_OVERRIDE_EXTERNAL_UI_DIR"), "override external ui directory") + flag.StringVar(&externalController, "ext-ctl", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER"), "override external controller address") + flag.StringVar(&secret, "secret", os.Getenv("CLASH_OVERRIDE_SECRET"), "override secret for RESTful API") flag.BoolVar(&geodataMode, "m", false, "set geodata mode") flag.BoolVar(&version, "v", false, "show current version of clash") flag.BoolVar(&testConfig, "t", false, "test configuration and exit") flag.Parse() - - flagset = map[string]bool{} - flag.Visit(func(f *flag.Flag) { - flagset[f.Name] = true - }) } func main() { @@ -99,13 +93,13 @@ func main() { } var options []hub.Option - if flagset["ext-ui"] { + if externalUI != "" { options = append(options, hub.WithExternalUI(externalUI)) } - if flagset["ext-ctl"] { + if externalController != "" { options = append(options, hub.WithExternalController(externalController)) } - if flagset["secret"] { + if secret != "" { options = append(options, hub.WithSecret(secret)) } From d2499cd69d5998cd1c64b77397ddaacecc95025c Mon Sep 17 00:00:00 2001 From: septs Date: Mon, 16 Oct 2023 09:23:31 +0800 Subject: [PATCH 483/530] feature: add xdg base support (#2913) --- constant/path.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/constant/path.go b/constant/path.go index d7477e0e..0d82f549 100644 --- a/constant/path.go +++ b/constant/path.go @@ -18,6 +18,9 @@ var ( ) // Path is used to get the configuration path +// +// on Unix systems, `$HOME/.config/clash`. +// on Windows, `%USERPROFILE%/.config/clash`. var Path = func() *path { homeDir, err := os.UserHomeDir() if err != nil { @@ -25,6 +28,13 @@ var Path = func() *path { } allowUnsafePath, _ := strconv.ParseBool(os.Getenv("SKIP_SAFE_PATH_CHECK")) homeDir = P.Join(homeDir, ".config", Name) + + if _, err = os.Stat(homeDir); err != nil { + if configHome, ok := os.LookupEnv("XDG_CONFIG_HOME"); ok { + homeDir = P.Join(configHome, Name) + } + } + return &path{homeDir: homeDir, configFile: "config.yaml", allowUnsafePath: allowUnsafePath} }() From 1faad7338164fee305ea8446c10007198add3597 Mon Sep 17 00:00:00 2001 From: Dreamacro <8615343+dreamacro@users.noreply.github.com> Date: Mon, 16 Oct 2023 09:27:55 +0800 Subject: [PATCH 484/530] fix: socks5 udp associate --- adapter/outbound/socks5.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 864500c5..43dfe8ef 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net" + "net/netip" "strconv" N "github.com/Dreamacro/clash/common/net" @@ -136,7 +137,8 @@ func (ss *Socks5) ListenPacketContext(ctx context.Context, metadata *C.Metadata, } } - bindAddr, err := socks5.ClientHandshake(c, serializesSocksAddr(metadata), socks5.CmdUDPAssociate, user) + udpAssocateAddr := socks5.AddrFromStdAddrPort(netip.AddrPortFrom(netip.IPv4Unspecified(), 0)) + bindAddr, err := socks5.ClientHandshake(c, udpAssocateAddr, socks5.CmdUDPAssociate, user) if err != nil { err = fmt.Errorf("client hanshake error: %w", err) return From d75a0e69a090e49219e1f7b7440a5dad0f16456c Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 16 Oct 2023 09:56:41 +0800 Subject: [PATCH 485/530] chore: Update dependencies --- go.mod | 16 ++++++++-------- go.sum | 32 ++++++++++++++++---------------- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 188f00ea..08dd7c25 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( github.com/3andne/restls-client-go v0.1.6 github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da - github.com/cilium/ebpf v0.11.0 + github.com/cilium/ebpf v0.12.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 @@ -30,7 +30,7 @@ require ( github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 github.com/oschwald/maxminddb-golang v1.12.0 - github.com/puzpuzpuz/xsync/v2 v2.5.0 + github.com/puzpuzpuz/xsync/v2 v2.5.1 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 github.com/sagernet/sing v0.2.13 github.com/sagernet/sing-mux v0.1.3 @@ -39,16 +39,16 @@ require ( github.com/sagernet/utls v0.0.0-20230309024959-6732c2ab36f2 github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f github.com/samber/lo v1.38.1 - github.com/shirou/gopsutil/v3 v3.23.8 + github.com/shirou/gopsutil/v3 v3.23.9 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.3 golang.org/x/crypto v0.14.0 - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 - golang.org/x/net v0.15.0 - golang.org/x/sync v0.3.0 + golang.org/x/exp v0.0.0-20231006140011-7918f672742d + golang.org/x/net v0.17.0 + golang.org/x/sync v0.4.0 golang.org/x/sys v0.13.0 google.golang.org/protobuf v1.31.0 gopkg.in/yaml.v3 v3.0.1 @@ -101,10 +101,10 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.3.0 // indirect - golang.org/x/mod v0.12.0 // indirect + golang.org/x/mod v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/tools v0.14.0 // indirect ) replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 diff --git a/go.sum b/go.sum index 84b186c1..3e48dc07 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.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= -github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= +github.com/cilium/ebpf v0.12.0 h1:oQEuIQIXgYhe1v7sYUG0P9vtJTYZLLdA6tiQmrOB1mo= +github.com/cilium/ebpf v0.12.0/go.mod h1:u9H29/Iq+8cy70YqI6p5pfADkFl3vdnV2qXDg5JL0Zo= 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= @@ -137,8 +137,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g= -github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErpE8c= -github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= +github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= 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.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= @@ -164,8 +164,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.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= 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= @@ -215,19 +215,19 @@ 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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= 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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/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/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= +golang.org/x/sync v0.4.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= @@ -253,8 +253,8 @@ golang.org/x/text v0.13.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-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= From 11ed4a56bda6adbfb8583a54519682ccb3f0e7c1 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 17 Oct 2023 12:46:41 +0800 Subject: [PATCH 486/530] chore: code cleanup --- transport/vmess/websocket.go | 56 +++++++++++++++++------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 6d679e29..83f5e3c2 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -353,17 +353,11 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, RawQuery: u.RawQuery, } - headers := http.Header{"User-Agent": []string{"Go-http-client/1.1"}} // match golang's net/http + headers := http.Header{} + headers.Set("User-Agent", "Go-http-client/1.1") // match golang's net/http if c.Headers != nil { - cHeaders := c.Headers - // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` - // if headers has "Host" will send repeatedly - if host := cHeaders.Get("Host"); host != "" { - cHeaders.Del("Host") - uri.Host = host - } - for k := range cHeaders { - headers.Add(k, cHeaders.Get(k)) + for k := range c.Headers { + headers.Add(k, c.Headers.Get(k)) } } @@ -372,19 +366,26 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if c.EarlyDataHeaderName == "" { uri.Path += earlyDataString } else { - // gobwas/ws will check server's response "Sec-Websocket-Protocol" so must add Protocols to ws.Dialer - // if not will cause ws.ErrHandshakeBadSubProtocol - if c.EarlyDataHeaderName == "Sec-WebSocket-Protocol" { - // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols - // to avoid send repeatedly don't set it to headers - dialer.Protocols = []string{earlyDataString} - } else { - headers.Set(c.EarlyDataHeaderName, earlyDataString) - } - + headers.Set(c.EarlyDataHeaderName, earlyDataString) } } + // gobwas/ws will check server's response "Sec-Websocket-Protocol" so must add Protocols to ws.Dialer + // if not will cause ws.ErrHandshakeBadSubProtocol + if secProtocol := headers.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { + // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols + // to avoid send repeatedly don't set it to headers + headers.Del("Sec-WebSocket-Protocol") + dialer.Protocols = []string{secProtocol} + } + + // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` + // if headers has "Host" will send repeatedly + if host := headers.Get("Host"); host != "" { + headers.Del("Host") + uri.Host = host + } + dialer.Header = ws.HandshakeHeaderHTTP(headers) conn, reader, _, err := dialer.Dial(ctx, uri.String()) @@ -447,26 +448,23 @@ func decodeEd(s string) ([]byte, error) { return base64.RawURLEncoding.DecodeString(replacer.Replace(s)) } -func decodeXray0rtt(requestHeader http.Header) ([]byte, http.Header) { - var edBuf []byte - responseHeader := http.Header{} +func decodeXray0rtt(requestHeader http.Header) []byte { // read inHeader's `Sec-WebSocket-Protocol` for Xray's 0rtt ws if secProtocol := requestHeader.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { - if buf, err := decodeEd(secProtocol); err == nil { // sure could base64 decode - edBuf = buf + if edBuf, err := decodeEd(secProtocol); err == nil { // sure could base64 decode + return edBuf } } - return edBuf, responseHeader + return nil } func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Conn, error) { - edBuf, responseHeader := decodeXray0rtt(r.Header) - wsConn, rw, _, err := ws.HTTPUpgrader{Header: responseHeader}.Upgrade(r, w) + wsConn, rw, _, err := ws.UpgradeHTTP(r, w) if err != nil { return nil, err } conn := newWebsocketConn(wsConn, rw.Reader, ws.StateServerSide) - if len(edBuf) > 0 { + if edBuf := decodeXray0rtt(r.Header); len(edBuf) > 0 { return N.NewDeadlineConn(&websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}), nil } return N.NewDeadlineConn(conn), nil From 0129a8579f7bea79f82906ff357cb8407fbbbeba Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 19 Oct 2023 11:08:14 +0800 Subject: [PATCH 487/530] chore: merge some quic-go fix --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 08dd7c25..f6e02548 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.39.1-0.20231008050334-3d067d335ce0 + github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 diff --git a/go.sum b/go.sum index 3e48dc07..f3de8013 100644 --- a/go.sum +++ b/go.sum @@ -97,8 +97,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-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0 h1:zUNzLFzYAHti3LCSMyM1PILsGovf1QYdWpzFhrdQovA= -github.com/metacubex/quic-go v0.39.1-0.20231008050334-3d067d335ce0/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= +github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b h1:uZ++sW8yg7Fr/Wvmmrb/V+SfxvRs0iMC+2+u2bRmO8g= +github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9 h1:F0+IuW0tZ96QHEmrebXAdYnz7ab7Gz4l5yYC4g6Cg8k= github.com/metacubex/sing v0.0.0-20231001053806-1230641572b9/go.mod h1:GQ673iPfUnkbK/dIPkfd1Xh1MjOGo36gkl/mkiHY7Jg= github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= From de90c276afe434d02e88a9bf0e3fa413c14536f8 Mon Sep 17 00:00:00 2001 From: 5aaee9 <7685264+5aaee9@users.noreply.github.com> Date: Thu, 19 Oct 2023 18:30:20 +0800 Subject: [PATCH 488/530] feat(sniffer): add quic sniffer --- component/sniffer/base_sniffer.go | 4 +- component/sniffer/dispatcher.go | 40 ++++- component/sniffer/http_sniffer.go | 2 +- component/sniffer/quic_sniffer.go | 289 +++++++++++++++++++++++++++++- component/sniffer/sniff_test.go | 28 +++ component/sniffer/tls_sniffer.go | 2 +- constant/sniffer/sniffer.go | 7 +- test/go.mod | 44 ++--- test/go.sum | 23 +++ tunnel/tunnel.go | 4 + 10 files changed, 412 insertions(+), 31 deletions(-) diff --git a/component/sniffer/base_sniffer.go b/component/sniffer/base_sniffer.go index cf7cb940..6d869aa0 100644 --- a/component/sniffer/base_sniffer.go +++ b/component/sniffer/base_sniffer.go @@ -23,8 +23,8 @@ func (*BaseSniffer) Protocol() string { return "unknown" } -// SniffTCP implements sniffer.Sniffer -func (*BaseSniffer) SniffTCP(bytes []byte) (string, error) { +// SniffData implements sniffer.Sniffer +func (*BaseSniffer) SniffData(bytes []byte) (string, error) { return "", errors.New("TODO") } diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index a1c8a93f..8df6313c 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -35,9 +35,43 @@ type SnifferDispatcher struct { parsePureIp bool } +func (sd *SnifferDispatcher) shouldOverride(metadata *C.Metadata) bool { + return (metadata.Host == "" && sd.parsePureIp) || + sd.forceDomain.Has(metadata.Host) || + (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) +} + +func (sd *SnifferDispatcher) UDPSniff(packet C.PacketAdapter) bool { + metadata := packet.Metadata() + + if sd.shouldOverride(packet.Metadata()) { + for sniffer, config := range sd.sniffers { + if sniffer.SupportNetwork() == C.UDP || sniffer.SupportNetwork() == C.ALLNet { + inWhitelist := sniffer.SupportPort(metadata.DstPort) + overrideDest := config.OverrideDest + + if inWhitelist { + var copyBuf = make([]byte, len(packet.Data())) + copy(copyBuf, packet.Data()) + + host, err := sniffer.SniffData(copyBuf) + if err != nil { + continue + } + + sd.replaceDomain(metadata, host, overrideDest) + return true + } + } + } + } + + return false +} + // TCPSniff returns true if the connection is sniffed to have a domain func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata) bool { - if (metadata.Host == "" && sd.parsePureIp) || sd.forceDomain.Has(metadata.Host) || (metadata.DNSMode == C.DNSMapping && sd.forceDnsMapping) { + if sd.shouldOverride(metadata) { inWhitelist := false overrideDest := false for sniffer, config := range sd.sniffers { @@ -125,7 +159,7 @@ func (sd *SnifferDispatcher) sniffDomain(conn *N.BufferedConn, metadata *C.Metad continue } - host, err := s.SniffTCP(bytes) + host, err := s.SniffData(bytes) if err != nil { //log.Debugln("[Sniffer] [%s] Sniff data failed %s", s.Protocol(), metadata.DstIP) continue @@ -194,6 +228,8 @@ func NewSniffer(name sniffer.Type, snifferConfig SnifferConfig) (sniffer.Sniffer return NewTLSSniffer(snifferConfig) case sniffer.HTTP: return NewHTTPSniffer(snifferConfig) + case sniffer.QUIC: + return NewQuicSniffer(snifferConfig) default: return nil, ErrorUnsupportedSniffer } diff --git a/component/sniffer/http_sniffer.go b/component/sniffer/http_sniffer.go index beb4bd20..ee958a1c 100644 --- a/component/sniffer/http_sniffer.go +++ b/component/sniffer/http_sniffer.go @@ -58,7 +58,7 @@ func (http *HTTPSniffer) SupportNetwork() C.NetWork { return C.TCP } -func (http *HTTPSniffer) SniffTCP(bytes []byte) (string, error) { +func (http *HTTPSniffer) SniffData(bytes []byte) (string, error) { domain, err := SniffHTTP(bytes) if err == nil { return *domain, nil diff --git a/component/sniffer/quic_sniffer.go b/component/sniffer/quic_sniffer.go index de78cf82..ab721c41 100644 --- a/component/sniffer/quic_sniffer.go +++ b/component/sniffer/quic_sniffer.go @@ -1,3 +1,290 @@ package sniffer -//TODO +import ( + "crypto" + "crypto/aes" + "crypto/cipher" + "crypto/tls" + _ "crypto/tls" + "encoding/binary" + "errors" + "github.com/Dreamacro/clash/common/buf" + "github.com/Dreamacro/clash/common/utils" + C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/quic-go/quicvarint" + "golang.org/x/crypto/hkdf" + "io" + _ "unsafe" +) + +// Modified from https://github.com/v2fly/v2ray-core/blob/master/common/protocol/quic/sniff.go + +const ( + versionDraft29 uint32 = 0xff00001d + version1 uint32 = 0x1 +) + +type cipherSuiteTLS13 struct { + ID uint16 + KeyLen int + AEAD func(key, fixedNonce []byte) cipher.AEAD + Hash crypto.Hash +} + +// github.com/quic-go/quic-go/internal/handshake/cipher_suite.go describes these cipher suite implementations are copied from the standard library crypto/tls package. +// So we can user go:linkname to implement the same feature. + +//go:linkname aeadAESGCMTLS13 crypto/tls.aeadAESGCMTLS13 +func aeadAESGCMTLS13(key, nonceMask []byte) cipher.AEAD + +var ( + quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99} + quicSalt = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a} + initialSuite = &cipherSuiteTLS13{ + ID: tls.TLS_AES_128_GCM_SHA256, + KeyLen: 16, + AEAD: aeadAESGCMTLS13, + Hash: crypto.SHA256, + } + errNotQuic = errors.New("not QUIC") + errNotQuicInitial = errors.New("not QUIC initial packet") +) + +type QuicSniffer struct { + *BaseSniffer +} + +func NewQuicSniffer(snifferConfig SnifferConfig) (*QuicSniffer, error) { + ports := snifferConfig.Ports + if len(ports) == 0 { + ports = utils.IntRanges[uint16]{utils.NewRange[uint16](443, 443)} + } + return &QuicSniffer{ + BaseSniffer: NewBaseSniffer(ports, C.UDP), + }, nil +} + +func (quic QuicSniffer) Protocol() string { + return "quic" +} + +func (quic QuicSniffer) SupportNetwork() C.NetWork { + return C.UDP +} + +func (quic QuicSniffer) SniffData(b []byte) (string, error) { + buffer := buf.As(b) + typeByte, err := buffer.ReadByte() + if err != nil { + return "", errNotQuic + } + isLongHeader := typeByte&0x80 > 0 + if !isLongHeader || typeByte&0x40 == 0 { + return "", errNotQuicInitial + } + + vb, err := buffer.ReadBytes(4) + if err != nil { + return "", errNotQuic + } + + versionNumber := binary.BigEndian.Uint32(vb) + + if versionNumber != 0 && typeByte&0x40 == 0 { + return "", errNotQuic + } else if versionNumber != versionDraft29 && versionNumber != version1 { + return "", errNotQuic + } + + if (typeByte&0x30)>>4 != 0x0 { + return "", errNotQuicInitial + } + + var destConnID []byte + if l, err := buffer.ReadByte(); err != nil { + return "", errNotQuic + } else if destConnID, err = buffer.ReadBytes(int(l)); err != nil { + return "", errNotQuic + } + + if l, err := buffer.ReadByte(); err != nil { + return "", errNotQuic + } else if _, err := buffer.ReadBytes(int(l)); err != nil { + return "", errNotQuic + } + + tokenLen, err := quicvarint.Read(buffer) + if err != nil || tokenLen > uint64(len(b)) { + return "", errNotQuic + } + + if _, err = buffer.ReadBytes(int(tokenLen)); err != nil { + return "", errNotQuic + } + + packetLen, err := quicvarint.Read(buffer) + if err != nil { + return "", errNotQuic + } + + hdrLen := len(b) - int(buffer.Len()) + + origPNBytes := make([]byte, 4) + copy(origPNBytes, b[hdrLen:hdrLen+4]) + + var salt []byte + if versionNumber == version1 { + salt = quicSalt + } else { + salt = quicSaltOld + } + initialSecret := hkdf.Extract(crypto.SHA256.New, destConnID, salt) + secret := hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size()) + hpKey := hkdfExpandLabel(initialSuite.Hash, secret, []byte{}, "quic hp", initialSuite.KeyLen) + block, err := aes.NewCipher(hpKey) + if err != nil { + return "", err + } + + cache := buf.New() + defer cache.Release() + + mask := cache.Extend(int(block.BlockSize())) + block.Encrypt(mask, b[hdrLen+4:hdrLen+4+16]) + b[0] ^= mask[0] & 0xf + for i := range b[hdrLen : hdrLen+4] { + b[hdrLen+i] ^= mask[i+1] + } + packetNumberLength := b[0]&0x3 + 1 + var packetNumber uint32 + { + n, err := buffer.ReadByte() + if err != nil { + return "", err + } + packetNumber = uint32(n) + } + + if packetNumber != 0 && packetNumber != 1 { + return "", errNotQuicInitial + } + + extHdrLen := hdrLen + int(packetNumberLength) + copy(b[extHdrLen:hdrLen+4], origPNBytes[packetNumberLength:]) + data := b[extHdrLen : int(packetLen)+hdrLen] + + key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16) + iv := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12) + c := aeadAESGCMTLS13(key, iv) + nonce := cache.Extend(int(c.NonceSize())) + binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber)) + decrypted, err := c.Open(b[extHdrLen:extHdrLen], nonce, data, b[:extHdrLen]) + if err != nil { + return "", err + } + buffer = buf.As(decrypted) + + cryptoLen := uint(0) + cryptoData := make([]byte, buffer.Len()) + for i := 0; !buffer.IsEmpty(); i++ { + frameType := byte(0x0) // Default to PADDING frame + for frameType == 0x0 && !buffer.IsEmpty() { + frameType, _ = buffer.ReadByte() + } + switch frameType { + case 0x00: // PADDING frame + case 0x01: // PING frame + case 0x02, 0x03: // ACK frame + if _, err = quicvarint.Read(buffer); err != nil { // Field: Largest Acknowledged + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Delay + return "", io.ErrUnexpectedEOF + } + ackRangeCount, err := quicvarint.Read(buffer) // Field: ACK Range Count + if err != nil { + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: First ACK Range + return "", io.ErrUnexpectedEOF + } + for i := 0; i < int(ackRangeCount); i++ { // Field: ACK Range + if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> Gap + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: ACK Range -> ACK Range Length + return "", io.ErrUnexpectedEOF + } + } + if frameType == 0x03 { + if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT0 Count + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: ECN Counts -> ECT1 Count + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { //nolint:misspell // Field: ECN Counts -> ECT-CE Count + return "", io.ErrUnexpectedEOF + } + } + case 0x06: // CRYPTO frame, we will use this frame + offset, err := quicvarint.Read(buffer) // Field: Offset + if err != nil { + return "", io.ErrUnexpectedEOF + } + length, err := quicvarint.Read(buffer) // Field: Length + if err != nil || length > uint64(buffer.Len()) { + return "", io.ErrUnexpectedEOF + } + if cryptoLen < uint(offset+length) { + cryptoLen = uint(offset + length) + } + if _, err := buffer.Read(cryptoData[offset : offset+length]); err != nil { // Field: Crypto Data + return "", io.ErrUnexpectedEOF + } + case 0x1c: // CONNECTION_CLOSE frame, only 0x1c is permitted in initial packet + if _, err = quicvarint.Read(buffer); err != nil { // Field: Error Code + return "", io.ErrUnexpectedEOF + } + if _, err = quicvarint.Read(buffer); err != nil { // Field: Frame Type + return "", io.ErrUnexpectedEOF + } + length, err := quicvarint.Read(buffer) // Field: Reason Phrase Length + if err != nil { + return "", io.ErrUnexpectedEOF + } + if _, err := buffer.ReadBytes(int(length)); err != nil { // Field: Reason Phrase + return "", io.ErrUnexpectedEOF + } + default: + // Only above frame types are permitted in initial packet. + // See https://www.rfc-editor.org/rfc/rfc9000.html#section-17.2.2-8 + return "", errNotQuicInitial + } + } + + domain, err := ReadClientHello(cryptoData[:cryptoLen]) + if err != nil { + return "", err + } + + return *domain, nil +} + +func hkdfExpandLabel(hash crypto.Hash, secret, context []byte, label string, length int) []byte { + b := make([]byte, 3, 3+6+len(label)+1+len(context)) + binary.BigEndian.PutUint16(b, uint16(length)) + b[2] = uint8(6 + len(label)) + b = append(b, []byte("tls13 ")...) + b = append(b, []byte(label)...) + b = b[:3+6+len(label)+1] + b[3+6+len(label)] = uint8(len(context)) + b = append(b, context...) + + out := make([]byte, length) + n, err := hkdf.Expand(hash.New, secret, b).Read(out) + if err != nil || n != length { + panic("quic: HKDF-Expand-Label invocation failed unexpectedly") + } + return out +} diff --git a/component/sniffer/sniff_test.go b/component/sniffer/sniff_test.go index e7ced43c..4c59d432 100644 --- a/component/sniffer/sniff_test.go +++ b/component/sniffer/sniff_test.go @@ -1,9 +1,37 @@ package sniffer import ( + "encoding/hex" + "github.com/stretchr/testify/assert" "testing" ) +func TestQuicHeaders(t *testing.T) { + cases := []struct { + input string + domain string + }{ + { + input: "cd0000000108f1fb7bcc78aa5e7203a8f86400421531fe825b19541876db6c55c38890cd73149d267a084afee6087304095417a3033df6a81bbb71d8512e7a3e16df1e277cae5df3182cb214b8fe982ba3fdffbaa9ffec474547d55945f0fddbeadfb0b5243890b2fa3da45169e2bd34ec04b2e29382f48d612b28432a559757504d158e9e505407a77dd34f4b60b8d3b555ee85aacd6648686802f4de25e7216b19e54c5f78e8a5963380c742d861306db4c16e4f7fc94957aa50b9578a0b61f1e406b2ad5f0cd3cd271c4d99476409797b0c3cb3efec256118912d4b7e4fd79d9cb9016b6e5eaa4f5e57b637b217755daf8968a4092bed0ed5413f5d04904b3a61e4064f9211b2629e5b52a89c7b19f37a713e41e27743ea6dfa736dfa1bb0a4b2bc8c8dc632c6ce963493a20c550e6fdb2475213665e9a85cfc394da9cec0cf41f0c8abed3fc83be5245b2b5aa5e825d29349f721d30774ef5bf965b540f3d8d98febe20956b1fc8fa047e10e7d2f921c9c6622389e02322e80621a1cf5264e245b7276966eb02932584e3f7038bd36aa908766ad3fb98344025dec18670d6db43a1c5daac00937fce7b7c7d61ff4e6efd01a2bdee0ee183108b926393df4f3d74bbcbb015f240e7e346b7d01c41111a401225ce3b095ab4623a5836169bf9599eeca79d1d2e9b2202b5960a09211e978058d6fc0484eff3e91ce4649a5e3ba15b906d334cf66e28d9ff575406e1ae1ac2febafd72870b6f5d58fc5fb949cb1f40feb7c1d9ce5e71b", + domain: "www.google.com", + }, + { + input: "c3000000011266f50524e8d0fe88cbf51e3ad71a13198235000044c82dc5d943fb34cc6d5c5e433610dc7a44f5951935c2c1d14ac641b02472340a892c4492dbfe3f8262109108fc36d96bdc1e9e46b5f1f6ef6104add2aafbfd8e79246eb3b4637541aaed7d195571724e642ab4d31c909f1db86e7d8516117ce8716bd1e3acb664c499086b0f3bc7258595420e7bb969f934457d195e832ffff4ffddf11123eeadacc48190e356c8f0f6abc381deb7e285e3b0613a795b19bddb9f002ffdf6fd70f0ff2072302b33d2421aac6540bb9f0e85c7237af0dd56225b2264d769160febab952e64bd5155f23e58c6113891143f946591032b41816aed3ac54f521f60605f86791de24c5765b664c1348cc53d5d631b4bbefe1915f2b21fefafb47badeb72d8ba1fd5c3cfeb0ba9d0112396f170e94cd33952c4fa87997b870931bf1a300e8e127f530815ff087815b4f9d004cbcd17013ac143847572a1655a5b36e054e8b9951d747c2c6ff25d7b2edb13a2a6b8074062332f2191f6830cf435a4ed9db5d9c4eb43a143bf3edf0c48f6f9435dafad4afb743a5a33990379df953ecd388e848aff0ebba9ccc052b8303c0bd1fee7e7553af1894e81b7772818bb69249540ccb8cfb47b1517abaf71c81c3bd271f1a5f1b66465f850f377c9db682b8e543c3d0c10fcd2dee263630889b7d1d521d1d27e866ea4ab5f43790d6a7f76ceefd5783678ca92cc131fa42fc4a01e2a81cad734ddf17a53e1bda8e0a21afc9e8c1118c9459b13519f5b3c3d9692c92234f01129d47ae8ec70625170847472801190b46d36f73b868f55f5a18a3cb05af6d38610e0829e4fbf13ddcc202341702e43dcf33be76ff4afe327e5783287c137aad075752940b41e7d9f5146e36d908897c6d7a9fdc343fde2d9c9d6e6a6b237669bd3e6abe0a732861a679eadfa29a876c6a646953c9361830811b012b26b31c9e7158f8de9c9a108346ddee3dd3886da6258364c1281bff8e055f6384e3a23e198b5e6b726fa7f811b3338072019d4b5fd05891770d11e3ed6ab5f7ed33db1c6220c5aa8fa1909949ac55d5435b75982e17aa80940fa574f0aba4dc340129cad491fdf1f5e05c4e83e36ad29ff38f15e1c9436c792024442f57f07583d671dd05446c84ea20b471303f6ae4e5e13f244d671e0ebe94d3d5c17d3f3f378cdd51fa8a6d2c977c78a2397dd1e251cd979803d617d45f575e5d9db0a28b3c4c25fe2af24af5bddac09786b6d6d8aa19cfbd5409bdbfed7d518ef5c863f3ee757bd9d37cddc546cc57d2e52b6ae58789f297a300f1d76c3842603eae4b1224de31a939a68875c86e697aeebf7ebc65568f43fc681bacab830ac4a2164d324e90067125bad702192d01cb3cb3d2689ae681967e86fd7ac93a25cf2e905c88ca5ad7d11962f021754cf3f61224517bd3411d5b5a83955bcea79d702466d073a6eaadc1202b3693e555b051a5b19457023a01e7f943742bb7f5f8aeba8d4e363973aebdccfb12479619cfb93e833be702a307e796dc7431a48abd9b755b392c510b98cd20ef778e2ac88d6a04f23ba8a253d7eb7c13e0c88c3a21f7e23857c58704d139703a47e0965bf2dc8810dc36894ac1f3da73c155e271c106a718b2d184e4e5637c820fe909984642960edfc9e62ac50af5dd3feee6bc560ced7bda676d4e290c9c5916fad52180bbc83d3483e95c79bac15c209936f21042dc2b6253eefdac06e7f4745044eaa0acedabf1d1c8cd9402738", + domain: "cloudflare-dns.com", + }, + } + q, err := NewQuicSniffer(SnifferConfig{}) + assert.NoError(t, err) + + for _, test := range cases { + pkt, err := hex.DecodeString(test.input) + assert.NoError(t, err) + domain, err := q.SniffData(pkt) + assert.NoError(t, err) + assert.Equal(t, test.domain, domain) + } +} + func TestTLSHeaders(t *testing.T) { cases := []struct { input []byte diff --git a/component/sniffer/tls_sniffer.go b/component/sniffer/tls_sniffer.go index 58e1e29e..b695c76f 100644 --- a/component/sniffer/tls_sniffer.go +++ b/component/sniffer/tls_sniffer.go @@ -39,7 +39,7 @@ func (tls *TLSSniffer) SupportNetwork() C.NetWork { return C.TCP } -func (tls *TLSSniffer) SniffTCP(bytes []byte) (string, error) { +func (tls *TLSSniffer) SniffData(bytes []byte) (string, error) { domain, err := SniffTLS(bytes) if err == nil { return *domain, nil diff --git a/constant/sniffer/sniffer.go b/constant/sniffer/sniffer.go index 6b20b3f6..d5414b14 100644 --- a/constant/sniffer/sniffer.go +++ b/constant/sniffer/sniffer.go @@ -4,7 +4,7 @@ import "github.com/Dreamacro/clash/constant" type Sniffer interface { SupportNetwork() constant.NetWork - SniffTCP(bytes []byte) (string, error) + SniffData(bytes []byte) (string, error) Protocol() string SupportPort(port uint16) bool } @@ -12,10 +12,11 @@ type Sniffer interface { const ( TLS Type = iota HTTP + QUIC ) var ( - List = []Type{TLS, HTTP} + List = []Type{TLS, HTTP, QUIC} ) type Type int @@ -26,6 +27,8 @@ func (rt Type) String() string { return "TLS" case HTTP: return "HTTP" + case QUIC: + return "QUIC" default: return "Unknown" } diff --git a/test/go.mod b/test/go.mod index 5582dd04..36fa7256 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.55 + github.com/miekg/dns v1.1.56 github.com/stretchr/testify v1.8.4 - golang.org/x/net v0.15.0 + golang.org/x/net v0.17.0 ) replace github.com/Dreamacro/clash => ../ @@ -20,7 +20,7 @@ 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.11.0 // indirect + github.com/cilium/ebpf v0.12.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 @@ -32,7 +32,7 @@ require ( github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-ole/go-ole v1.3.0 // 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 @@ -52,13 +52,13 @@ 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-20230611153922-78842f086475 // indirect - github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf // 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/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 // indirect + github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b // indirect + github.com/metacubex/sing-shadowsocks v0.2.5 // indirect + github.com/metacubex/sing-shadowsocks2 v0.1.4 // indirect + github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c // indirect + github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 // indirect + github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/mroth/weightedrand/v2 v2.1.0 // indirect @@ -72,13 +72,13 @@ require ( 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/puzpuzpuz/xsync/v2 v2.5.0 // indirect + github.com/puzpuzpuz/xsync/v2 v2.5.1 // indirect github.com/quic-go/qpack v0.4.0 // indirect - github.com/quic-go/qtls-go1-20 v0.3.3 // indirect + github.com/quic-go/qtls-go1-20 v0.3.4 // 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.10-0.20230807080248-4db0062caa0a // indirect - github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c // indirect + github.com/sagernet/sing v0.2.13 // indirect + github.com/sagernet/sing-mux v0.1.3 // 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-20230816093905-5a5c285d44a6 // indirect @@ -86,7 +86,7 @@ require ( github.com/sagernet/wireguard-go v0.0.0-20230807125731-5d4a7ef2dc5f // 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.8 // indirect + github.com/shirou/gopsutil/v3 v3.23.9 // 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 @@ -100,14 +100,14 @@ require ( 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.13.0 // indirect - golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect - golang.org/x/mod v0.12.0 // indirect - golang.org/x/sync v0.3.0 // indirect - golang.org/x/sys v0.12.0 // indirect + golang.org/x/crypto v0.14.0 // indirect + golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect + golang.org/x/mod v0.13.0 // indirect + golang.org/x/sync v0.4.0 // indirect + golang.org/x/sys v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect - golang.org/x/tools v0.13.0 // indirect + golang.org/x/tools v0.14.0 // 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 609d2fcb..10d016c9 100644 --- a/test/go.sum +++ b/test/go.sum @@ -17,6 +17,7 @@ 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/cilium/ebpf v0.12.0/go.mod h1:u9H29/Iq+8cy70YqI6p5pfADkFl3vdnV2qXDg5JL0Zo= 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= @@ -49,6 +50,7 @@ github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67d 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-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 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= @@ -101,20 +103,28 @@ 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/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= +github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= 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-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= 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-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= 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-tun v0.1.15-0.20231003075803-dffa0200e64c/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= 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-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= 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/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= 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= @@ -147,10 +157,12 @@ 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/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErpE8c= github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= 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.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.4/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= @@ -160,8 +172,10 @@ github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2 github.com/sagernet/sing v0.1.8/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a h1:b89t6Mjgk4rJ5lrNMnCzy1/J116XkhgdB3YNd9FHyF4= github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= +github.com/sagernet/sing v0.2.13/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c h1:35/FowAvt3Z62mck0TXzVc4jS5R5CWq62qcV2P1cp0I= github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY= +github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= 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= @@ -178,6 +192,7 @@ github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9 h1:rc/CcqLH3lh github.com/scjalliance/comshim v0.0.0-20230315213746-5e51f40bd3b9/go.mod h1:a/83NAfUXvEuLpmxDssAXxgUgrEy12MId3Wd7OTs76s= github.com/shirou/gopsutil/v3 v3.23.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= 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= @@ -227,8 +242,10 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= 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= @@ -236,6 +253,7 @@ 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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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= @@ -243,12 +261,14 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.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= @@ -265,11 +285,13 @@ golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.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/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.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= @@ -285,6 +307,7 @@ golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index 13bf6d8c..fe37d75e 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -323,6 +323,10 @@ func handleUDPConn(packet C.PacketAdapter) { return } + if sniffer.Dispatcher.Enable() && sniffingEnable { + sniffer.Dispatcher.UDPSniff(packet) + } + // local resolve UDP dns if !metadata.Resolved() { ip, err := resolver.ResolveIP(context.Background(), metadata.Host) From 981c69040faff74c893ed2dcaeb765ac8d29f638 Mon Sep 17 00:00:00 2001 From: 5aaee9 <7685264+5aaee9@users.noreply.github.com> Date: Thu, 19 Oct 2023 19:09:13 +0800 Subject: [PATCH 489/530] docs: update about quic sniffer --- docs/config.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/config.yaml b/docs/config.yaml index e829e5db..80fc2995 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -142,7 +142,9 @@ sniffer: # 是否使用嗅探结果作为实际访问,默认 true # 全局配置,优先级低于 sniffer.sniff 实际配置 override-destination: false - sniff: # TLS 默认如果不配置 ports 默认嗅探 443 + sniff: # TLS 和 QUIC 默认如果不配置 ports 默认嗅探 443 + QUIC: + # ports: [ 443 ] TLS: # ports: [443, 8443] From 8e637a2ec77a0bf720ee10f7023c57399764335d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 19 Oct 2023 20:44:49 +0800 Subject: [PATCH 490/530] chore: code cleanup --- component/sniffer/quic_sniffer.go | 53 ++++++++++++++----------------- 1 file changed, 24 insertions(+), 29 deletions(-) diff --git a/component/sniffer/quic_sniffer.go b/component/sniffer/quic_sniffer.go index ab721c41..24e1bcc4 100644 --- a/component/sniffer/quic_sniffer.go +++ b/component/sniffer/quic_sniffer.go @@ -4,17 +4,16 @@ import ( "crypto" "crypto/aes" "crypto/cipher" - "crypto/tls" - _ "crypto/tls" "encoding/binary" "errors" + "io" + "github.com/Dreamacro/clash/common/buf" "github.com/Dreamacro/clash/common/utils" C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/quic-go/quicvarint" "golang.org/x/crypto/hkdf" - "io" - _ "unsafe" ) // Modified from https://github.com/v2fly/v2ray-core/blob/master/common/protocol/quic/sniff.go @@ -24,28 +23,9 @@ const ( version1 uint32 = 0x1 ) -type cipherSuiteTLS13 struct { - ID uint16 - KeyLen int - AEAD func(key, fixedNonce []byte) cipher.AEAD - Hash crypto.Hash -} - -// github.com/quic-go/quic-go/internal/handshake/cipher_suite.go describes these cipher suite implementations are copied from the standard library crypto/tls package. -// So we can user go:linkname to implement the same feature. - -//go:linkname aeadAESGCMTLS13 crypto/tls.aeadAESGCMTLS13 -func aeadAESGCMTLS13(key, nonceMask []byte) cipher.AEAD - var ( - quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99} - quicSalt = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a} - initialSuite = &cipherSuiteTLS13{ - ID: tls.TLS_AES_128_GCM_SHA256, - KeyLen: 16, - AEAD: aeadAESGCMTLS13, - Hash: crypto.SHA256, - } + quicSaltOld = []byte{0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97, 0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99} + quicSalt = []byte{0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a} errNotQuic = errors.New("not QUIC") errNotQuicInitial = errors.New("not QUIC initial packet") ) @@ -140,7 +120,7 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { } initialSecret := hkdf.Extract(crypto.SHA256.New, destConnID, salt) secret := hkdfExpandLabel(crypto.SHA256, initialSecret, []byte{}, "client in", crypto.SHA256.Size()) - hpKey := hkdfExpandLabel(initialSuite.Hash, secret, []byte{}, "quic hp", initialSuite.KeyLen) + hpKey := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic hp", 16) block, err := aes.NewCipher(hpKey) if err != nil { return "", err @@ -175,10 +155,25 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16) iv := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic iv", 12) - c := aeadAESGCMTLS13(key, iv) - nonce := cache.Extend(int(c.NonceSize())) + aesCipher, err := aes.NewCipher(key) + if err != nil { + return "", err + } + aead, err := cipher.NewGCM(aesCipher) + if err != nil { + return "", err + } + nonce := cache.Extend(8) // 64-bit sequence number binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber)) - decrypted, err := c.Open(b[extHdrLen:extHdrLen], nonce, data, b[:extHdrLen]) + // copy from crypto/tls.aeadAESGCMTLS13 + for i, b := range nonce { + iv[4+i] ^= b + } + decrypted, err := aead.Open(b[extHdrLen:extHdrLen], iv, data, b[:extHdrLen]) + // We only decrypt once, so we do not need to XOR it back. + //for i, b := range nonce { + // iv[4+i] ^= b + //} if err != nil { return "", err } From ea7e15b447299ffa3d742d7b9fee3d44eb830457 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 19 Oct 2023 23:51:37 +0800 Subject: [PATCH 491/530] chore: decrease memory copy in quic sniffer --- common/buf/sing.go | 1 + component/sniffer/dispatcher.go | 5 +-- component/sniffer/quic_sniffer.go | 64 ++++++++++++++++--------------- component/sniffer/sniff_test.go | 5 +++ constant/sniffer/sniffer.go | 1 + 5 files changed, 41 insertions(+), 35 deletions(-) diff --git a/common/buf/sing.go b/common/buf/sing.go index d204ba11..0907a95c 100644 --- a/common/buf/sing.go +++ b/common/buf/sing.go @@ -10,6 +10,7 @@ const BufferSize = buf.BufferSize type Buffer = buf.Buffer var New = buf.New +var NewPacket = buf.NewPacket var NewSize = buf.NewSize var With = buf.With var As = buf.As diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 8df6313c..271be8bb 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -51,10 +51,7 @@ func (sd *SnifferDispatcher) UDPSniff(packet C.PacketAdapter) bool { overrideDest := config.OverrideDest if inWhitelist { - var copyBuf = make([]byte, len(packet.Data())) - copy(copyBuf, packet.Data()) - - host, err := sniffer.SniffData(copyBuf) + host, err := sniffer.SniffData(packet.Data()) if err != nil { continue } diff --git a/component/sniffer/quic_sniffer.go b/component/sniffer/quic_sniffer.go index 24e1bcc4..ef49e5ad 100644 --- a/component/sniffer/quic_sniffer.go +++ b/component/sniffer/quic_sniffer.go @@ -107,10 +107,7 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { return "", errNotQuic } - hdrLen := len(b) - int(buffer.Len()) - - origPNBytes := make([]byte, 4) - copy(origPNBytes, b[hdrLen:hdrLen+4]) + hdrLen := len(b) - buffer.Len() var salt []byte if versionNumber == version1 { @@ -126,31 +123,40 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { return "", err } - cache := buf.New() + cache := buf.NewPacket() defer cache.Release() - mask := cache.Extend(int(block.BlockSize())) + mask := cache.Extend(block.BlockSize()) block.Encrypt(mask, b[hdrLen+4:hdrLen+4+16]) - b[0] ^= mask[0] & 0xf - for i := range b[hdrLen : hdrLen+4] { - b[hdrLen+i] ^= mask[i+1] + firstByte := b[0] + // Encrypt/decrypt first byte. + if isLongHeader { + // Long header: 4 bits masked + // High 4 bits are not protected. + firstByte ^= mask[0] & 0x0f + } else { + // Short header: 5 bits masked + // High 3 bits are not protected. + firstByte ^= mask[0] & 0x1f } - packetNumberLength := b[0]&0x3 + 1 - var packetNumber uint32 - { - n, err := buffer.ReadByte() - if err != nil { - return "", err - } - packetNumber = uint32(n) + packetNumberLength := int(firstByte&0x3 + 1) // max = 4 (64-bit sequence number) + extHdrLen := hdrLen + packetNumberLength + + // copy to avoid modify origin data + extHdr := cache.Extend(extHdrLen) + copy(extHdr, b) + extHdr[0] = firstByte + + packetNumber := extHdr[hdrLen:extHdrLen] + // Encrypt/decrypt packet number. + for i := range packetNumber { + packetNumber[i] ^= mask[1+i] } - if packetNumber != 0 && packetNumber != 1 { + if packetNumber[0] != 0 && packetNumber[0] != 1 { return "", errNotQuicInitial } - extHdrLen := hdrLen + int(packetNumberLength) - copy(b[extHdrLen:hdrLen+4], origPNBytes[packetNumberLength:]) data := b[extHdrLen : int(packetLen)+hdrLen] key := hkdfExpandLabel(crypto.SHA256, secret, []byte{}, "quic key", 16) @@ -163,24 +169,20 @@ func (quic QuicSniffer) SniffData(b []byte) (string, error) { if err != nil { return "", err } - nonce := cache.Extend(8) // 64-bit sequence number - binary.BigEndian.PutUint64(nonce[len(nonce)-8:], uint64(packetNumber)) - // copy from crypto/tls.aeadAESGCMTLS13 - for i, b := range nonce { - iv[4+i] ^= b - } - decrypted, err := aead.Open(b[extHdrLen:extHdrLen], iv, data, b[:extHdrLen]) // We only decrypt once, so we do not need to XOR it back. - //for i, b := range nonce { - // iv[4+i] ^= b - //} + // https://github.com/quic-go/qtls-go1-20/blob/e132a0e6cb45e20ac0b705454849a11d09ba5a54/cipher_suites.go#L496 + for i, b := range packetNumber { + iv[len(iv)-len(packetNumber)+i] ^= b + } + dst := cache.Extend(len(data)) + decrypted, err := aead.Open(dst[:0], iv, data, extHdr) if err != nil { return "", err } buffer = buf.As(decrypted) cryptoLen := uint(0) - cryptoData := make([]byte, buffer.Len()) + cryptoData := cache.Extend(buffer.Len()) for i := 0; !buffer.IsEmpty(); i++ { frameType := byte(0x0) // Default to PADDING frame for frameType == 0x0 && !buffer.IsEmpty() { diff --git a/component/sniffer/sniff_test.go b/component/sniffer/sniff_test.go index 4c59d432..18cc9152 100644 --- a/component/sniffer/sniff_test.go +++ b/component/sniffer/sniff_test.go @@ -1,6 +1,7 @@ package sniffer import ( + "bytes" "encoding/hex" "github.com/stretchr/testify/assert" "testing" @@ -26,9 +27,11 @@ func TestQuicHeaders(t *testing.T) { for _, test := range cases { pkt, err := hex.DecodeString(test.input) assert.NoError(t, err) + oriPkt := bytes.Clone(pkt) domain, err := q.SniffData(pkt) assert.NoError(t, err) assert.Equal(t, test.domain, domain) + assert.Equal(t, oriPkt, pkt) // ensure input data not changed } } @@ -170,6 +173,7 @@ func TestTLSHeaders(t *testing.T) { } for _, test := range cases { + input := bytes.Clone(test.input) domain, err := SniffTLS(test.input) if test.err { if err == nil { @@ -183,5 +187,6 @@ func TestTLSHeaders(t *testing.T) { t.Error("expect domain ", test.domain, " but got ", domain) } } + assert.Equal(t, input, test.input) } } diff --git a/constant/sniffer/sniffer.go b/constant/sniffer/sniffer.go index d5414b14..47dbd069 100644 --- a/constant/sniffer/sniffer.go +++ b/constant/sniffer/sniffer.go @@ -4,6 +4,7 @@ import "github.com/Dreamacro/clash/constant" type Sniffer interface { SupportNetwork() constant.NetWork + // SniffData must not change input bytes SniffData(bytes []byte) (string, error) Protocol() string SupportPort(port uint16) bool From 51004b14d98087392d4fa29084823128adeb7acc Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Thu, 19 Oct 2023 23:41:43 +0800 Subject: [PATCH 492/530] docs: update readme.md --- README.md | 303 +++--------------------------------------------------- 1 file changed, 16 insertions(+), 287 deletions(-) diff --git a/README.md b/README.md index bbf5cf43..d5022dfb 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ ## Features - Local HTTP/HTTPS/SOCKS server with authentication support -- VMess, Shadowsocks, Trojan, Snell protocol support for remote connections +- VMess, VLESS, Shadowsocks, Trojan, Snell, TUIC, Hysteria protocol support - Built-in DNS server that aims to minimize DNS pollution attack impact, supports DoH/DoT upstream and fake IP. - Rules based off domains, GEOIP, IPCIDR or Process to forward packets to different nodes - Remote groups allow users to implement powerful rules. Supports automatic fallback, load balancing or auto select node @@ -32,259 +32,41 @@ ## Dashboard -We made an official web dashboard providing first class support for this project, check it out -at [metacubexd](https://github.com/MetaCubeX/metacubexd) +A web dashboard with first-class support for this project has been created; it can be checked out at [metacubexd](https://github.com/MetaCubeX/metacubexd). -## Wiki +## Configration example -Configuration examples can be found -at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml), while documentation can be -found [Clash.Meta Wiki](https://clash-meta.wiki). +Configuration example is located at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml). -## Build +## Docs -You should install [golang](https://go.dev) first. +Documentation can be found in [Clash.Meta Docs](https://clash-meta.wiki). -Then get the source code of Clash.Meta: +## For development + +Requirements: +[Go 1.20 or newer](https://go.dev/dl/) + +Build Clash.Meta: ```shell git clone https://github.com/MetaCubeX/Clash.Meta.git cd Clash.Meta && go mod download +go build ``` -If you can't visit GitHub, you should set proxy first: +Set go proxy if a connection to GitHub is not possible: ```shell go env -w GOPROXY=https://goproxy.io,direct ``` -Now you can build it: - -```shell -go build -``` - -If you need gvisor for tun stack, build with: +Build with gvisor tun stack: ```shell go build -tags with_gvisor ``` - - - - ### IPTABLES configuration Work on Linux OS which supported `iptables` @@ -298,62 +80,9 @@ iptables: inbound-interface: eth0 # detect the inbound interface, default is 'lo' ``` -### General installation guide for Linux - -- Create user given name `clash-meta` - -- Download and decompress pre-built binaries from [releases](https://github.com/MetaCubeX/Clash.Meta/releases) - -- Rename executable file to `Clash-Meta` and move to `/usr/local/bin/` - -- Create folder `/etc/Clash-Meta/` as working directory - -Run Meta Kernel by user `clash-meta` as a daemon. - -Create the systemd configuration file at `/etc/systemd/system/Clash-Meta.service`: - -``` -[Unit] -Description=Clash-Meta Daemon, Another Clash Kernel. -After=network.target NetworkManager.service systemd-networkd.service iwd.service - -[Service] -Type=simple -User=clash-meta -Group=clash-meta -LimitNPROC=500 -LimitNOFILE=1000000 -CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE -AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW CAP_NET_BIND_SERVICE -Restart=always -ExecStartPre=/usr/bin/sleep 1s -ExecStart=/usr/local/bin/Clash-Meta -d /etc/Clash-Meta -ExecReload=/bin/kill -HUP $MAINPID - -[Install] -WantedBy=multi-user.target -``` - -Launch clash-meta daemon on system startup with: - -```shell -$ systemctl enable Clash-Meta -``` - -Launch clash-meta daemon immediately with: - -```shell -$ systemctl start Clash-Meta -``` - -## Development - -If you want to build an application that uses clash as a library, check out -the [GitHub Wiki](https://github.com/Dreamacro/clash/wiki/use-clash-as-a-library) - ## Debugging -Check [wiki](https://github.com/MetaCubeX/Clash.Meta/wiki/How-to-use-debug-api) to get an instruction on using debug +Check [wiki](https://wiki.metacubex.one/api/#debug) to get an instruction on using debug API. ## Credits From 150bf7fc65c7736d7c56e2ce7866f03a620d9014 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 20 Oct 2023 08:39:04 +0800 Subject: [PATCH 493/530] chore: decrease memory copy in sing listener --- listener/sing/sing.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/listener/sing/sing.go b/listener/sing/sing.go index 1837951d..ff72f67d 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -193,12 +193,6 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { err = errors.New("address is invalid") return } - buff := buf.NewPacket() - defer buff.Release() - n, err = buff.Write(b) - if err != nil { - return - } c.mutex.Lock() defer c.mutex.Unlock() @@ -207,6 +201,14 @@ func (c *packet) WriteBack(b []byte, addr net.Addr) (n int, err error) { err = errors.New("writeBack to closed connection") return } + + buff := buf.NewPacket() + defer buff.Release() + n, err = buff.Write(b) + if err != nil { + return + } + err = conn.WritePacket(buff, M.SocksaddrFromNet(addr)) if err != nil { return From 0d3197e4371e6e2c81f32c8fb876e06a0b828dc5 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Fri, 20 Oct 2023 22:36:29 +0800 Subject: [PATCH 494/530] chore: fix sniffer log error --- component/sniffer/dispatcher.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 271be8bb..11deb1ed 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -117,7 +117,8 @@ func (sd *SnifferDispatcher) TCPSniff(conn *N.BufferedConn, metadata *C.Metadata func (sd *SnifferDispatcher) replaceDomain(metadata *C.Metadata, host string, overrideDest bool) { // show log early, since the following code may mutate `metadata.Host` - log.Debugln("[Sniffer] Sniff TCP [%s]-->[%s] success, replace domain [%s]-->[%s]", + log.Debugln("[Sniffer] Sniff %s [%s]-->[%s] success, replace domain [%s]-->[%s]", + metadata.NetWork, metadata.SourceDetail(), metadata.RemoteAddress(), metadata.Host, host) From f794c090a52f41c78d12a946f21b0d338c9e0299 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 22 Oct 2023 23:38:25 +0800 Subject: [PATCH 495/530] chore: update sing-tun --- go.mod | 6 +++--- go.sum | 9 ++++----- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index f6e02548..f355a977 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c + github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700 github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 @@ -32,7 +32,7 @@ require ( github.com/oschwald/maxminddb-golang v1.12.0 github.com/puzpuzpuz/xsync/v2 v2.5.1 github.com/sagernet/netlink v0.0.0-20220905062125-8043b4a9aa97 - github.com/sagernet/sing v0.2.13 + github.com/sagernet/sing v0.2.14 github.com/sagernet/sing-mux v0.1.3 github.com/sagernet/sing-shadowtls v0.1.4 github.com/sagernet/tfo-go v0.0.0-20230816093905-5a5c285d44a6 @@ -65,7 +65,7 @@ require ( github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect diff --git a/go.sum b/go.sum index f3de8013..be89ca4d 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4Rfsap 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.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/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk= @@ -107,8 +107,8 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c h1:vzueqPO6LCdgE+KpGdZ89PwxcDGQW+lCnc7Leq2s1yY= -github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= +github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700 h1:JToLa8cxHrd6tOUHWCg9YM+o/4MXmjgagG909itmnyE= +github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700/go.mod h1:atkIOs6Y5NeUzstK5SBvnrFo4z1JLuORhEfQECEVUpI= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= @@ -238,7 +238,6 @@ golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 6cd0e58fd03f362ff98380f07746653ca9a365c7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 22 Oct 2023 23:39:46 +0800 Subject: [PATCH 496/530] fix: ssr panic --- transport/ssr/protocol/auth_chain_a.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/transport/ssr/protocol/auth_chain_a.go b/transport/ssr/protocol/auth_chain_a.go index 23efb390..12345db6 100644 --- a/transport/ssr/protocol/auth_chain_a.go +++ b/transport/ssr/protocol/auth_chain_a.go @@ -7,6 +7,7 @@ import ( "crypto/rc4" "encoding/base64" "encoding/binary" + "errors" "net" "strconv" "strings" @@ -107,6 +108,10 @@ func (a *authChainA) Decode(dst, src *bytes.Buffer) error { dataLength := int(binary.LittleEndian.Uint16(src.Bytes()[:2]) ^ binary.LittleEndian.Uint16(a.lastServerHash[14:16])) randDataLength := a.randDataLength(dataLength, a.lastServerHash, &a.randomServer) length := dataLength + randDataLength + // Temporary workaround for https://github.com/Dreamacro/clash/issues/1352 + if dataLength < 0 || randDataLength < 0 || length < 0 { + return errors.New("ssr crashing blocked") + } if length >= 4096 { a.rawTrans = true @@ -130,6 +135,11 @@ func (a *authChainA) Decode(dst, src *bytes.Buffer) error { if dataLength > 0 && randDataLength > 0 { pos += getRandStartPos(randDataLength, &a.randomServer) } + // Temporary workaround for https://github.com/Dreamacro/clash/issues/1352 + if pos < 0 || pos+dataLength < 0 || dataLength < 0 { + return errors.New("ssr crashing blocked") + } + wantedData := src.Bytes()[pos : pos+dataLength] a.decrypter.XORKeyStream(wantedData, wantedData) if a.recvID == 1 { From e987cdaaae202749aadeed0e051bc882cd84c0db Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Mon, 23 Oct 2023 00:27:37 +0800 Subject: [PATCH 497/530] chore: add CMFA auto update-dependencies trigger --- .../workflows/cmfa-update-deps-trigger.yml | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/cmfa-update-deps-trigger.yml diff --git a/.github/workflows/cmfa-update-deps-trigger.yml b/.github/workflows/cmfa-update-deps-trigger.yml new file mode 100644 index 00000000..51736644 --- /dev/null +++ b/.github/workflows/cmfa-update-deps-trigger.yml @@ -0,0 +1,28 @@ +name: CMFA auto update-dependencies trigger +on: + workflow_dispatch: + push: + tags: + - "v*" + pull_request_target: + branches: + - Alpha + +jobs: + update-dependencies: + runs-on: ubuntu-latest + steps: + - uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.MAINTAINER_APPID }} + private_key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }} + + - name: Trigger update-dependencies + run: | + curl -X POST https://api.github.com/repos/MetaCubeX/ClashMetaForAndroid/dispatches \ + -H "Accept: application/vnd.github.everest-preview+json" \ + -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ + -d '{"event_type": "core-updated"}' + # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies + \ No newline at end of file From dff54464c635297e3da32dff4e605ea9ca475fbb Mon Sep 17 00:00:00 2001 From: Steve Johnson <144257728+stevejohnson7@users.noreply.github.com> Date: Mon, 23 Oct 2023 07:01:03 +0800 Subject: [PATCH 498/530] Add auto sync Alpha rebase android-open -> android-real (#817) * chore: add android branch auto sync * chore: fix * chore: fix missing * chore: fix actions * chore: write branch auto sync --- .../workflows/android-branch-auto-sync.yml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/android-branch-auto-sync.yml diff --git a/.github/workflows/android-branch-auto-sync.yml b/.github/workflows/android-branch-auto-sync.yml new file mode 100644 index 00000000..f1a5b2d8 --- /dev/null +++ b/.github/workflows/android-branch-auto-sync.yml @@ -0,0 +1,50 @@ +name: Android Branch Auto Sync +on: + workflow_dispatch: + push: + paths-ignore: + - "docs/**" + - "README.md" + - ".github/ISSUE_TEMPLATE/**" + branches: + - Alpha + - android-open + tags: + - "v*" + pull_request_target: + branches: + - Alpha + - android-open + +jobs: + update-dependencies: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Configure Git + run: | + git config --global user.name 'GitHub Action' + git config --global user.email 'action@github.com' + + - name: Sync android-real with Alpha rebase android-open + run: | + git fetch origin + git checkout origin/Alpha -b android-real + git rebase origin/android-open + + - name: Check for conflicts + run: | + CONFLICTS=$(git diff --name-only --diff-filter=U) + if [ ! -z "$CONFLICTS" ]; then + echo "There are conflicts in the following files:" + echo $CONFLICTS + exit 1 + fi + + - name: Push changes + run: | + git push origin android-real --force \ No newline at end of file From f6f8f27668763581e12b916b976aee8335781f44 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 23 Oct 2023 07:30:54 +0800 Subject: [PATCH 499/530] action: update sync --- .github/workflows/android-branch-auto-sync.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/android-branch-auto-sync.yml b/.github/workflows/android-branch-auto-sync.yml index f1a5b2d8..5dbbd5be 100644 --- a/.github/workflows/android-branch-auto-sync.yml +++ b/.github/workflows/android-branch-auto-sync.yml @@ -34,7 +34,8 @@ jobs: run: | git fetch origin git checkout origin/Alpha -b android-real - git rebase origin/android-open + git merge --squash origin/android-open + git commit -m "Android: patch" - name: Check for conflicts run: | From 3564e96a0010a415e5dd22fc9deeb7efd381dcb5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 23 Oct 2023 16:45:22 +0800 Subject: [PATCH 500/530] chore: share some code --- adapter/inbound/http.go | 4 ++-- component/http/http.go | 2 ++ dns/{patch.go => local.go} | 0 listener/http/client.go | 4 ++-- listener/http/proxy.go | 2 +- listener/http/upgrade.go | 2 +- 6 files changed, 8 insertions(+), 6 deletions(-) rename dns/{patch.go => local.go} (100%) diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 2a6050e5..7f3b143f 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -8,11 +8,11 @@ import ( ) // NewHTTP receive normal http request and return HTTPContext -func NewHTTP(target socks5.Addr, source net.Addr, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { +func NewHTTP(target socks5.Addr, srcConn net.Conn, conn net.Conn, additions ...Addition) (net.Conn, *C.Metadata) { metadata := parseSocksAddr(target) metadata.NetWork = C.TCP metadata.Type = C.HTTP - ApplyAdditions(metadata, WithSrcAddr(source), WithInAddr(conn.LocalAddr())) + ApplyAdditions(metadata, WithSrcAddr(srcConn.RemoteAddr()), WithInAddr(conn.LocalAddr())) ApplyAdditions(metadata, additions...) return conn, metadata } diff --git a/component/http/http.go b/component/http/http.go index 8e682e94..073f0237 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -7,6 +7,7 @@ import ( "net" "net/http" URL "net/url" + "runtime" "strings" "time" @@ -47,6 +48,7 @@ func HttpRequest(ctx context.Context, url, method string, header map[string][]st transport := &http.Transport{ // from http.DefaultTransport + DisableKeepAlives: runtime.GOOS == "android", MaxIdleConns: 100, IdleConnTimeout: 30 * time.Second, TLSHandshakeTimeout: 10 * time.Second, diff --git a/dns/patch.go b/dns/local.go similarity index 100% rename from dns/patch.go rename to dns/local.go diff --git a/listener/http/client.go b/listener/http/client.go index 76c7c8eb..84c284ff 100644 --- a/listener/http/client.go +++ b/listener/http/client.go @@ -12,7 +12,7 @@ import ( "github.com/Dreamacro/clash/transport/socks5" ) -func newClient(source net.Addr, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client { +func newClient(srcConn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client { return &http.Client{ Transport: &http.Transport{ // from http.DefaultTransport @@ -32,7 +32,7 @@ func newClient(source net.Addr, tunnel C.Tunnel, additions ...inbound.Addition) left, right := net.Pipe() - go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, source, right, additions...)) + go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, srcConn, right, additions...)) return left, nil }, diff --git a/listener/http/proxy.go b/listener/http/proxy.go index 44ff04c7..fa1d8f88 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -15,7 +15,7 @@ import ( ) func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { - client := newClient(c.RemoteAddr(), tunnel, additions...) + client := newClient(c, tunnel, additions...) defer client.CloseIdleConnections() conn := N.NewBufferedConn(c) diff --git a/listener/http/upgrade.go b/listener/http/upgrade.go index e67928ce..6e4f063d 100644 --- a/listener/http/upgrade.go +++ b/listener/http/upgrade.go @@ -43,7 +43,7 @@ func handleUpgrade(conn net.Conn, request *http.Request, tunnel C.Tunnel, additi left, right := net.Pipe() - go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, conn.RemoteAddr(), right, additions...)) + go tunnel.HandleTCPConn(inbound.NewHTTP(dstAddr, conn, right, additions...)) var bufferedLeft *N.BufferedConn if request.TLS != nil { From 01bc84db02f606693343eee9452f00e0744da079 Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Mon, 23 Oct 2023 17:02:04 +0800 Subject: [PATCH 501/530] chore: add labels to issue template --- .github/ISSUE_TEMPLATE/bug_report.yml | 1 + .github/ISSUE_TEMPLATE/feature_request.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index f8a0f4ae..bd44d025 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,7 @@ name: Bug report description: Create a report to help us improve title: "[Bug] " +labels: ["bug"] body: - type: checkboxes id: ensure diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index c8f70b19..a32d313d 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,7 @@ name: Feature request description: Suggest an idea for this project title: "[Feature] " +labels: ["enhancement"] body: - type: checkboxes id: ensure From 875561891064ee1983adfe93d0c39931a66bf48a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 23 Oct 2023 23:33:44 +0800 Subject: [PATCH 502/530] fix: reality panic --- component/tls/reality.go | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index c995af0a..2902aa4b 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -43,7 +43,8 @@ type RealityConfig struct { 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 { + retry := 0 + for fingerprint, exists := GetFingerprint(ClientFingerprint); exists; retry++ { verifier := &realityVerifier{ serverName: tlsConfig.ServerName, } @@ -80,7 +81,15 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string //log.Debugln("REALITY hello.sessionId[:16]: %v", hello.SessionId[:16]) - authKey := uConn.HandshakeState.State13.EcdheParams.SharedKey(realityConfig.PublicKey[:]) + ecdheParams := uConn.HandshakeState.State13.EcdheParams + if ecdheParams == nil { + // WTF??? + if retry > 2 { + return nil, errors.New("nil ecdheParams") + } + continue // retry + } + authKey := ecdheParams.SharedKey(realityConfig.PublicKey[:]) if authKey == nil { return nil, errors.New("nil auth_key") } From e1e999180af7426790747b453bc5081fa480a91e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Tue, 24 Oct 2023 21:25:03 +0800 Subject: [PATCH 503/530] chore: inMemoryAuthenticator unneed sync map --- component/auth/auth.go | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/component/auth/auth.go b/component/auth/auth.go index 9b351606..b52fa135 100644 --- a/component/auth/auth.go +++ b/component/auth/auth.go @@ -1,9 +1,5 @@ package auth -import ( - "github.com/puzpuzpuz/xsync/v2" -) - type Authenticator interface { Verify(user string, pass string) bool Users() []string @@ -15,12 +11,12 @@ type AuthUser struct { } type inMemoryAuthenticator struct { - storage *xsync.MapOf[string, string] + storage map[string]string usernames []string } func (au *inMemoryAuthenticator) Verify(user string, pass string) bool { - realPass, ok := au.storage.Load(user) + realPass, ok := au.storage[user] return ok && realPass == pass } @@ -30,17 +26,13 @@ func NewAuthenticator(users []AuthUser) Authenticator { if len(users) == 0 { return nil } - - au := &inMemoryAuthenticator{storage: xsync.NewMapOf[string]()} - for _, user := range users { - au.storage.Store(user.User, user.Pass) + au := &inMemoryAuthenticator{ + storage: make(map[string]string), + usernames: make([]string, 0, len(users)), + } + for _, user := range users { + au.storage[user.User] = user.Pass + au.usernames = append(au.usernames, user.User) } - usernames := make([]string, 0, len(users)) - au.storage.Range(func(key string, value string) bool { - usernames = append(usernames, key) - return true - }) - au.usernames = usernames - return au } From fc5a3cf80c3352d33ff2a328e97b546fececd5ff Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Tue, 24 Oct 2023 21:53:56 +0800 Subject: [PATCH 504/530] action: ban black issues --- .github/ISSUE_TEMPLATE/config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000..3ba13e0c --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1 @@ +blank_issues_enabled: false From c1f24d8f0ee648ed268b98b037da037a2f8e9fc5 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 25 Oct 2023 18:07:45 +0800 Subject: [PATCH 505/530] chore: code cleanup --- dns/client.go | 4 ---- dns/dhcp.go | 9 --------- dns/doh.go | 5 ----- dns/doq.go | 5 ----- dns/rcode.go | 6 +----- dns/resolver.go | 19 +++---------------- dns/util.go | 2 +- 7 files changed, 5 insertions(+), 45 deletions(-) diff --git a/dns/client.go b/dns/client.go index 89f083aa..f228b08e 100644 --- a/dns/client.go +++ b/dns/client.go @@ -48,10 +48,6 @@ func (c *client) Address() string { return c.addr } -func (c *client) Exchange(m *D.Msg) (*D.Msg, error) { - return c.ExchangeContext(context.Background(), m) -} - func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) { var ( ip netip.Addr diff --git a/dns/dhcp.go b/dns/dhcp.go index 7d420d89..e0373ab4 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -11,8 +11,6 @@ import ( "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/dhcp" "github.com/Dreamacro/clash/component/iface" - "github.com/Dreamacro/clash/component/resolver" - D "github.com/miekg/dns" ) @@ -46,13 +44,6 @@ func (d *dhcpClient) Address() string { return strings.Join(addrs, ",") } -func (d *dhcpClient) Exchange(m *D.Msg) (msg *D.Msg, err error) { - ctx, cancel := context.WithTimeout(context.Background(), resolver.DefaultDNSTimeout) - defer cancel() - - return d.ExchangeContext(ctx, m) -} - func (d *dhcpClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { clients, err := d.resolve(ctx) if err != nil { diff --git a/dns/doh.go b/dns/doh.go index 0d84fc4f..488e9025 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -157,11 +157,6 @@ func (doh *dnsOverHTTPS) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D. return msg, err } -// Exchange implements the Upstream interface for *dnsOverHTTPS. -func (doh *dnsOverHTTPS) Exchange(m *D.Msg) (*D.Msg, error) { - return doh.ExchangeContext(context.Background(), m) -} - // Close implements the Upstream interface for *dnsOverHTTPS. func (doh *dnsOverHTTPS) Close() (err error) { doh.clientMu.Lock() diff --git a/dns/doq.go b/dns/doq.go index afa8259a..76da913f 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -134,11 +134,6 @@ func (doq *dnsOverQUIC) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.M return msg, err } -// Exchange implements the Upstream interface for *dnsOverQUIC. -func (doq *dnsOverQUIC) Exchange(m *D.Msg) (msg *D.Msg, err error) { - return doq.ExchangeContext(context.Background(), m) -} - // Close implements the Upstream interface for *dnsOverQUIC. func (doq *dnsOverQUIC) Close() (err error) { doq.connMu.Lock() diff --git a/dns/rcode.go b/dns/rcode.go index 61fc8d72..9777d2e7 100644 --- a/dns/rcode.go +++ b/dns/rcode.go @@ -39,16 +39,12 @@ type rcodeClient struct { var _ dnsClient = rcodeClient{} -func (r rcodeClient) Exchange(m *D.Msg) (*D.Msg, error) { +func (r rcodeClient) ExchangeContext(ctx context.Context, 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/resolver.go b/dns/resolver.go index 4696515f..f0183c16 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -23,7 +23,6 @@ import ( ) type dnsClient interface { - Exchange(m *D.Msg) (msg *D.Msg, err error) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) Address() string } @@ -136,11 +135,6 @@ func (r *Resolver) shouldIPFallback(ip netip.Addr) bool { return false } -// Exchange a batch of dns request, and it use cache -func (r *Resolver) Exchange(m *D.Msg) (msg *D.Msg, err error) { - return r.ExchangeContext(context.Background(), m) -} - // ExchangeContext a batch of dns request with context.Context, and it use cache func (r *Resolver) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { if len(m.Question) == 0 { @@ -210,10 +204,10 @@ func (r *Resolver) exchangeWithoutCache(ctx context.Context, m *D.Msg) (msg *D.M } if matched := r.matchPolicy(m); len(matched) != 0 { - result, cache, err = r.batchExchange(ctx, matched, m) + result, cache, err = batchExchange(ctx, matched, m) return } - result, cache, err = r.batchExchange(ctx, r.main, m) + result, cache, err = batchExchange(ctx, r.main, m) return } @@ -255,13 +249,6 @@ 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, cache bool, err error) { - ctx, cancel := context.WithTimeout(ctx, resolver.DefaultDNSTimeout) - defer cancel() - - return batchExchange(ctx, clients, m) -} - func (r *Resolver) matchPolicy(m *D.Msg) []dnsClient { if r.policy == nil { return nil @@ -385,7 +372,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 := batchExchange(ctx, client, msg) ch <- &result{Msg: res, Error: err} }() return ch diff --git a/dns/util.go b/dns/util.go index 433ea9e2..6c196517 100644 --- a/dns/util.go +++ b/dns/util.go @@ -306,7 +306,7 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M domain := msgToDomain(m) for _, client := range clients { if _, isRCodeClient := client.(rcodeClient); isRCodeClient { - msg, err = client.Exchange(m) + msg, err = client.ExchangeContext(ctx, 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 From 431d52f2500f413450752d496c2013080fe065fa Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 25 Oct 2023 19:20:44 +0800 Subject: [PATCH 506/530] chore: system resolver can autoupdate --- dns/system.go | 116 ++++++++++++++++++++++++++++++++++++++++++++------ dns/util.go | 11 +---- 2 files changed, 104 insertions(+), 23 deletions(-) diff --git a/dns/system.go b/dns/system.go index f5ab0efb..20282929 100644 --- a/dns/system.go +++ b/dns/system.go @@ -1,23 +1,113 @@ package dns import ( + "context" + "fmt" "net" + "strings" + "sync" + "time" + + "github.com/Dreamacro/clash/log" + + D "github.com/miekg/dns" + "golang.org/x/exp/slices" ) -func loadSystemResolver() (clients []dnsClient, err error) { - nameservers, err := dnsReadConfig() +const ( + SystemDnsFlushTime = 5 * time.Minute + SystemDnsDeleteTimes = 12 // 12*5 = 60min +) + +type systemDnsClient struct { + disableTimes uint32 + dnsClient +} + +type systemClient struct { + mu sync.Mutex + dnsClients map[string]*systemDnsClient + lastFlush time.Time +} + +func (c *systemClient) getDnsClients() ([]dnsClient, error) { + c.mu.Lock() + defer c.mu.Unlock() + var err error + if time.Since(c.lastFlush) > SystemDnsFlushTime { + var nameservers []string + if nameservers, err = dnsReadConfig(); err == nil { + log.Debugln("[DNS] system dns update to %s", nameservers) + for _, addr := range nameservers { + if _, ok := c.dnsClients[addr]; !ok { + clients := transform( + []NameServer{{ + Addr: net.JoinHostPort(addr, "53"), + Net: "udp", + }}, + nil, + ) + if len(clients) > 0 { + c.dnsClients[addr] = &systemDnsClient{ + disableTimes: 0, + dnsClient: clients[0], + } + } + } + } + available := 0 + for nameserver, sdc := range c.dnsClients { + if slices.Contains(nameservers, nameserver) { + sdc.disableTimes = 0 // enable + available++ + } else { + if sdc.disableTimes > SystemDnsDeleteTimes { + delete(c.dnsClients, nameserver) // drop too old dnsClient + } else { + sdc.disableTimes++ + } + } + } + if available > 0 { + c.lastFlush = time.Now() + } + } + } + dnsClients := make([]dnsClient, 0, len(c.dnsClients)) + for _, sdc := range c.dnsClients { + if sdc.disableTimes == 0 { + dnsClients = append(dnsClients, sdc.dnsClient) + } + } + if len(dnsClients) > 0 { + return dnsClients, nil + } + return nil, err +} + +func (c *systemClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { + dnsClients, err := c.getDnsClients() if err != nil { return } - if len(nameservers) == 0 { - return - } - servers := make([]NameServer, 0, len(nameservers)) - for _, addr := range nameservers { - servers = append(servers, NameServer{ - Addr: net.JoinHostPort(addr, "53"), - Net: "udp", - }) - } - return transform(servers, nil), nil + msg, _, err = batchExchange(ctx, dnsClients, m) + return +} + +// Address implements dnsClient +func (c *systemClient) Address() string { + dnsClients, _ := c.getDnsClients() + addrs := make([]string, 0, len(dnsClients)) + for _, c := range dnsClients { + addrs = append(addrs, c.Address()) + } + return fmt.Sprintf("system(%s)", strings.Join(addrs, ",")) +} + +var _ dnsClient = (*systemClient)(nil) + +func newSystemClient() *systemClient { + return &systemClient{ + dnsClients: map[string]*systemDnsClient{}, + } } diff --git a/dns/util.go b/dns/util.go index 6c196517..e8bdfd0b 100644 --- a/dns/util.go +++ b/dns/util.go @@ -107,16 +107,7 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { ret = append(ret, newDHCPClient(s.Addr)) continue case "system": - clients, err := loadSystemResolver() - if err != nil { - log.Errorln("[DNS:system] load system resolver failed: %s", err.Error()) - continue - } - if len(clients) == 0 { - log.Errorln("[DNS:system] no nameserver found in system") - continue - } - ret = append(ret, clients...) + ret = append(ret, newSystemClient()) continue case "rcode": ret = append(ret, newRCodeClient(s.Addr)) From 55f626424f944aedb2d7690dd10002d94c2b851f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 25 Oct 2023 20:16:44 +0800 Subject: [PATCH 507/530] chore: better dns batchExchange --- dns/util.go | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/dns/util.go b/dns/util.go index e8bdfd0b..668a3a2e 100644 --- a/dns/util.go +++ b/dns/util.go @@ -290,11 +290,14 @@ func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName st return proxyAdapter.ListenPacketContext(ctx, metadata, opts...) } +var errIPNotFound = errors.New("couldn't find ip") + 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) + var noIpMsg *D.Msg for _, client := range clients { if _, isRCodeClient := client.(rcodeClient); isRCodeClient { msg, err = client.ExchangeContext(ctx, m) @@ -311,13 +314,31 @@ func batchExchange(ctx context.Context, clients []dnsClient, m *D.Msg) (msg *D.M // so we would ignore RCode errors from RCode clients. return nil, errors.New("server failure: " + D.RcodeToString[m.Rcode]) } - log.Debugln("[DNS] %s --> %s, from %s", domain, msgToIP(m), client.Address()) + if ips := msgToIP(m); len(m.Question) > 0 { + qType := m.Question[0].Qtype + log.Debugln("[DNS] %s --> %s %s from %s", domain, ips, D.Type(qType), client.Address()) + switch qType { + case D.TypeAAAA: + if len(ips) == 0 { + noIpMsg = m + return nil, errIPNotFound + } + case D.TypeA: + if len(ips) == 0 { + noIpMsg = m + return nil, errIPNotFound + } + } + } return m, nil }) } msg = fast.Wait() if msg == nil { + if noIpMsg != nil { + return noIpMsg, false, nil + } err = errors.New("all DNS requests failed") if fErr := fast.Error(); fErr != nil { err = fmt.Errorf("%w, first error: %w", err, fErr) From cf93f69f40c7de2b298829671140cccd2e9e20e7 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 09:07:49 +0800 Subject: [PATCH 508/530] chore: cleanup error using of dialer.DefaultInterface --- common/atomic/value.go | 7 +++++++ config/config.go | 2 -- dns/client.go | 7 +++---- dns/dhcp.go | 3 +-- dns/resolver.go | 3 +-- 5 files changed, 12 insertions(+), 10 deletions(-) diff --git a/common/atomic/value.go b/common/atomic/value.go index 95733533..708fcf90 100644 --- a/common/atomic/value.go +++ b/common/atomic/value.go @@ -12,6 +12,7 @@ func DefaultValue[T any]() T { type TypedValue[T any] struct { value atomic.Value + _ noCopy } func (t *TypedValue[T]) Load() T { @@ -55,3 +56,9 @@ func NewTypedValue[T any](t T) (v TypedValue[T]) { v.Store(t) return } + +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} +func (*noCopy) Unlock() {} diff --git a/config/config.go b/config/config.go index 97a193a1..994f897d 100644 --- a/config/config.go +++ b/config/config.go @@ -20,7 +20,6 @@ import ( N "github.com/Dreamacro/clash/common/net" "github.com/Dreamacro/clash/common/utils" "github.com/Dreamacro/clash/component/auth" - "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/geodata" "github.com/Dreamacro/clash/component/geodata/router" @@ -1048,7 +1047,6 @@ func parseNameServer(servers []string, preferH3 bool) ([]dns.NameServer, error) Net: dnsNetType, Addr: addr, ProxyName: proxyName, - Interface: dialer.DefaultInterface, Params: params, PreferH3: preferH3, }, diff --git a/dns/client.go b/dns/client.go index f228b08e..5cdd1ec0 100644 --- a/dns/client.go +++ b/dns/client.go @@ -8,7 +8,6 @@ import ( "net/netip" "strings" - "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/ca" "github.com/Dreamacro/clash/component/dialer" "github.com/Dreamacro/clash/component/resolver" @@ -23,7 +22,7 @@ type client struct { r *Resolver port string host string - iface atomic.TypedValue[string] + iface string proxyAdapter C.ProxyAdapter proxyName string addr string @@ -74,8 +73,8 @@ func (c *client) ExchangeContext(ctx context.Context, m *D.Msg) (*D.Msg, error) } var options []dialer.Option - if c.iface.Load() != "" { - options = append(options, dialer.WithInterface(c.iface.Load())) + if c.iface != "" { + options = append(options, dialer.WithInterface(c.iface)) } conn, err := getDialHandler(c.r, c.proxyAdapter, c.proxyName, options...)(ctx, network, net.JoinHostPort(ip.String(), c.port)) diff --git a/dns/dhcp.go b/dns/dhcp.go index e0373ab4..2fa2e8a4 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -8,7 +8,6 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/component/dhcp" "github.com/Dreamacro/clash/component/iface" D "github.com/miekg/dns" @@ -77,7 +76,7 @@ func (d *dhcpClient) resolve(ctx context.Context) ([]dnsClient, error) { for _, item := range dns { nameserver = append(nameserver, NameServer{ Addr: net.JoinHostPort(item.String(), "53"), - Interface: atomic.NewTypedValue(d.ifaceName), + Interface: d.ifaceName, }) } diff --git a/dns/resolver.go b/dns/resolver.go index f0183c16..2851f012 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -7,7 +7,6 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/atomic" "github.com/Dreamacro/clash/common/cache" "github.com/Dreamacro/clash/component/fakeip" "github.com/Dreamacro/clash/component/geodata/router" @@ -389,7 +388,7 @@ func (r *Resolver) Invalid() bool { type NameServer struct { Net string Addr string - Interface atomic.TypedValue[string] + Interface string ProxyAdapter C.ProxyAdapter ProxyName string Params map[string]string From 4314b37d0445091acd20f0b4b75a96890bd61240 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 10:27:38 +0800 Subject: [PATCH 509/530] fix: dhcp not working on windows --- component/dhcp/conn.go | 12 +++++++- component/dialer/bind.go | 50 +++++++++++++++++++++++++++++++++ component/dialer/bind_others.go | 47 +++---------------------------- component/dialer/dialer.go | 12 ++++++-- component/dialer/options.go | 7 +++++ dns/util.go | 2 +- 6 files changed, 83 insertions(+), 47 deletions(-) diff --git a/component/dhcp/conn.go b/component/dhcp/conn.go index 90a9e25b..5b71d3cd 100644 --- a/component/dhcp/conn.go +++ b/component/dhcp/conn.go @@ -14,5 +14,15 @@ func ListenDHCPClient(ctx context.Context, ifaceName string) (net.PacketConn, er listenAddr = "255.255.255.255:68" } - return dialer.ListenPacket(ctx, "udp4", listenAddr, dialer.WithInterface(ifaceName), dialer.WithAddrReuse(true)) + options := []dialer.Option{ + dialer.WithInterface(ifaceName), + dialer.WithAddrReuse(true), + } + + // fallback bind on windows, because syscall bind can not receive broadcast + if runtime.GOOS == "windows" { + options = append(options, dialer.WithFallbackBind(true)) + } + + return dialer.ListenPacket(ctx, "udp4", listenAddr, options...) } diff --git a/component/dialer/bind.go b/component/dialer/bind.go index edfc79c7..4accabb3 100644 --- a/component/dialer/bind.go +++ b/component/dialer/bind.go @@ -3,6 +3,7 @@ package dialer import ( "net" "net/netip" + "strconv" "strings" "github.com/Dreamacro/clash/component/iface" @@ -49,3 +50,52 @@ func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination return nil, iface.ErrAddrNotFound } + +func fallbackBindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error { + if !destination.IsGlobalUnicast() { + return nil + } + + local := uint64(0) + if dialer.LocalAddr != nil { + _, port, err := net.SplitHostPort(dialer.LocalAddr.String()) + if err == nil { + local, _ = strconv.ParseUint(port, 10, 16) + } + } + + addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, destination, int(local)) + if err != nil { + return err + } + + dialer.LocalAddr = addr + + return nil +} + +func fallbackBindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string) (string, error) { + _, port, err := net.SplitHostPort(address) + if err != nil { + port = "0" + } + + local, _ := strconv.ParseUint(port, 10, 16) + + addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, netip.Addr{}, int(local)) + if err != nil { + return "", err + } + + return addr.String(), nil +} + +func fallbackParseNetwork(network string, addr netip.Addr) string { + // fix fallbackBindIfaceToListenConfig() force bind to an ipv4 address + if !strings.HasSuffix(network, "4") && + !strings.HasSuffix(network, "6") && + addr.Unmap().Is6() { + network += "6" + } + return network +} diff --git a/component/dialer/bind_others.go b/component/dialer/bind_others.go index 5fd02a66..44181610 100644 --- a/component/dialer/bind_others.go +++ b/component/dialer/bind_others.go @@ -5,55 +5,16 @@ package dialer import ( "net" "net/netip" - "strconv" - "strings" ) func bindIfaceToDialer(ifaceName string, dialer *net.Dialer, network string, destination netip.Addr) error { - if !destination.IsGlobalUnicast() { - return nil - } - - local := uint64(0) - if dialer.LocalAddr != nil { - _, port, err := net.SplitHostPort(dialer.LocalAddr.String()) - if err == nil { - local, _ = strconv.ParseUint(port, 10, 16) - } - } - - addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, destination, int(local)) - if err != nil { - return err - } - - dialer.LocalAddr = addr - - return nil + return fallbackBindIfaceToDialer(ifaceName, dialer, network, destination) } -func bindIfaceToListenConfig(ifaceName string, _ *net.ListenConfig, network, address string) (string, error) { - _, port, err := net.SplitHostPort(address) - if err != nil { - port = "0" - } - - local, _ := strconv.ParseUint(port, 10, 16) - - addr, err := LookupLocalAddrFromIfaceName(ifaceName, network, netip.Addr{}, int(local)) - if err != nil { - return "", err - } - - return addr.String(), nil +func bindIfaceToListenConfig(ifaceName string, lc *net.ListenConfig, network, address string) (string, error) { + return fallbackBindIfaceToListenConfig(ifaceName, lc, network, address) } func ParseNetwork(network string, addr netip.Addr) string { - // fix bindIfaceToListenConfig() force bind to an ipv4 address - if !strings.HasSuffix(network, "4") && - !strings.HasSuffix(network, "6") && - addr.Unmap().Is6() { - network += "6" - } - return network + return fallbackParseNetwork(network, addr) } diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 0cfa1b6c..3cb8bba9 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -74,7 +74,11 @@ func ListenPacket(ctx context.Context, network, address string, options ...Optio lc := &net.ListenConfig{} if cfg.interfaceName != "" { - addr, err := bindIfaceToListenConfig(cfg.interfaceName, lc, network, address) + bind := bindIfaceToListenConfig + if cfg.fallbackBind { + bind = fallbackBindIfaceToListenConfig + } + addr, err := bind(cfg.interfaceName, lc, network, address) if err != nil { return nil, err } @@ -125,7 +129,11 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po dialer := netDialer.(*net.Dialer) if opt.interfaceName != "" { - if err := bindIfaceToDialer(opt.interfaceName, dialer, network, destination); err != nil { + bind := bindIfaceToDialer + if opt.fallbackBind { + bind = fallbackBindIfaceToDialer + } + if err := bind(opt.interfaceName, dialer, network, destination); err != nil { return nil, err } } diff --git a/component/dialer/options.go b/component/dialer/options.go index 30771e71..781d7164 100644 --- a/component/dialer/options.go +++ b/component/dialer/options.go @@ -20,6 +20,7 @@ type NetDialer interface { type option struct { interfaceName string + fallbackBind bool addrReuse bool routingMark int network int @@ -38,6 +39,12 @@ func WithInterface(name string) Option { } } +func WithFallbackBind(fallback bool) Option { + return func(opt *option) { + opt.fallbackBind = fallback + } +} + func WithAddrReuse(reuse bool) Option { return func(opt *option) { opt.addrReuse = reuse diff --git a/dns/util.go b/dns/util.go index 668a3a2e..34f7aa94 100644 --- a/dns/util.go +++ b/dns/util.go @@ -280,7 +280,7 @@ func listenPacket(ctx context.Context, proxyAdapter C.ProxyAdapter, proxyName st DstPort: uint16(uintPort), } if proxyAdapter == nil { - return dialer.NewDialer(opts...).ListenPacket(ctx, dialer.ParseNetwork(network, dstIP), "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort)) + return dialer.NewDialer(opts...).ListenPacket(ctx, network, "", netip.AddrPortFrom(metadata.DstIP, metadata.DstPort)) } if !proxyAdapter.SupportUDP() { From bffe47a9746c286c982091c21e61a84b1cd20841 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 10:39:54 +0800 Subject: [PATCH 510/530] chore: netip.Prefix should not using pointer --- component/dialer/bind.go | 2 +- component/fakeip/pool.go | 8 ++++---- component/fakeip/pool_test.go | 24 ++++++++++++------------ component/iface/iface.go | 24 ++++++++++++------------ config/config.go | 12 ++++++------ dns/dhcp.go | 2 +- dns/filters.go | 2 +- dns/resolver.go | 2 +- rules/common/ipcidr.go | 4 ++-- 9 files changed, 40 insertions(+), 40 deletions(-) diff --git a/component/dialer/bind.go b/component/dialer/bind.go index 4accabb3..c90212ef 100644 --- a/component/dialer/bind.go +++ b/component/dialer/bind.go @@ -15,7 +15,7 @@ func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination return nil, err } - var addr *netip.Prefix + var addr netip.Prefix switch network { case "udp4", "tcp4": addr, err = ifaceObj.PickIPv4Addr(destination) diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index ee11fedd..9b51929e 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -36,7 +36,7 @@ type Pool struct { cycle bool mux sync.Mutex host *trie.DomainTrie[struct{}] - ipnet *netip.Prefix + ipnet netip.Prefix store store } @@ -91,7 +91,7 @@ func (p *Pool) Broadcast() netip.Addr { } // IPNet return raw ipnet -func (p *Pool) IPNet() *netip.Prefix { +func (p *Pool) IPNet() netip.Prefix { return p.ipnet } @@ -153,7 +153,7 @@ func (p *Pool) restoreState() { } type Options struct { - IPNet *netip.Prefix + IPNet netip.Prefix Host *trie.DomainTrie[struct{}] // Size sets the maximum number of entries in memory @@ -171,7 +171,7 @@ func New(options Options) (*Pool, error) { hostAddr = options.IPNet.Masked().Addr() gateway = hostAddr.Next() first = gateway.Next().Next().Next() // default start with 198.18.0.4 - last = nnip.UnMasked(*options.IPNet) + last = nnip.UnMasked(options.IPNet) ) if !options.IPNet.IsValid() || !first.IsValid() || !first.Less(last) { diff --git a/component/fakeip/pool_test.go b/component/fakeip/pool_test.go index ae343f96..183a7185 100644 --- a/component/fakeip/pool_test.go +++ b/component/fakeip/pool_test.go @@ -51,7 +51,7 @@ func createCachefileStore(options Options) (*Pool, string, error) { func TestPool_Basic(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.0/28") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -79,7 +79,7 @@ func TestPool_Basic(t *testing.T) { func TestPool_BasicV6(t *testing.T) { ipnet := netip.MustParsePrefix("2001:4860:4860::8888/118") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -107,7 +107,7 @@ func TestPool_BasicV6(t *testing.T) { func TestPool_Case_Insensitive(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/29") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -128,7 +128,7 @@ func TestPool_Case_Insensitive(t *testing.T) { func TestPool_CycleUsed(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.16/28") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -152,7 +152,7 @@ func TestPool_Skip(t *testing.T) { tree := trie.New[struct{}]() tree.Insert("example.com", struct{}{}) pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, Host: tree, }) @@ -168,7 +168,7 @@ func TestPool_Skip(t *testing.T) { func TestPool_MaxCacheSize(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/24") pool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 2, }) @@ -183,7 +183,7 @@ func TestPool_MaxCacheSize(t *testing.T) { func TestPool_DoubleMapping(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/24") pool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 2, }) @@ -213,7 +213,7 @@ func TestPool_DoubleMapping(t *testing.T) { func TestPool_Clone(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/24") pool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 2, }) @@ -223,7 +223,7 @@ func TestPool_Clone(t *testing.T) { assert.True(t, last == netip.AddrFrom4([4]byte{192, 168, 0, 5})) newPool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 2, }) newPool.CloneFrom(pool) @@ -236,7 +236,7 @@ func TestPool_Clone(t *testing.T) { func TestPool_Error(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/31") _, err := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) @@ -246,7 +246,7 @@ func TestPool_Error(t *testing.T) { func TestPool_FlushFileCache(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/28") pools, tempfile, err := createPools(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) assert.Nil(t, err) @@ -278,7 +278,7 @@ func TestPool_FlushFileCache(t *testing.T) { func TestPool_FlushMemoryCache(t *testing.T) { ipnet := netip.MustParsePrefix("192.168.0.1/28") pool, _ := New(Options{ - IPNet: &ipnet, + IPNet: ipnet, Size: 10, }) diff --git a/component/iface/iface.go b/component/iface/iface.go index c32b65ab..03051cb3 100644 --- a/component/iface/iface.go +++ b/component/iface/iface.go @@ -13,7 +13,7 @@ import ( type Interface struct { Index int Name string - Addrs []*netip.Prefix + Addrs []netip.Prefix HardwareAddr net.HardwareAddr } @@ -43,7 +43,7 @@ func ResolveInterface(name string) (*Interface, error) { continue } - ipNets := make([]*netip.Prefix, 0, len(addrs)) + ipNets := make([]netip.Prefix, 0, len(addrs)) for _, addr := range addrs { ipNet := addr.(*net.IPNet) ip, _ := netip.AddrFromSlice(ipNet.IP) @@ -59,7 +59,7 @@ func ResolveInterface(name string) (*Interface, error) { } pf := netip.PrefixFrom(ip, ones) - ipNets = append(ipNets, &pf) + ipNets = append(ipNets, pf) } r[iface.Name] = &Interface{ @@ -89,27 +89,27 @@ func FlushCache() { interfaces.Reset() } -func (iface *Interface) PickIPv4Addr(destination netip.Addr) (*netip.Prefix, error) { - return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool { +func (iface *Interface) PickIPv4Addr(destination netip.Addr) (netip.Prefix, error) { + return iface.pickIPAddr(destination, func(addr netip.Prefix) bool { return addr.Addr().Is4() }) } -func (iface *Interface) PickIPv6Addr(destination netip.Addr) (*netip.Prefix, error) { - return iface.pickIPAddr(destination, func(addr *netip.Prefix) bool { +func (iface *Interface) PickIPv6Addr(destination netip.Addr) (netip.Prefix, error) { + return iface.pickIPAddr(destination, func(addr netip.Prefix) bool { return addr.Addr().Is6() }) } -func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr *netip.Prefix) bool) (*netip.Prefix, error) { - var fallback *netip.Prefix +func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr netip.Prefix) bool) (netip.Prefix, error) { + var fallback netip.Prefix for _, addr := range iface.Addrs { if !accept(addr) { continue } - if fallback == nil && !addr.Addr().IsLinkLocalUnicast() { + if !fallback.IsValid() && !addr.Addr().IsLinkLocalUnicast() { fallback = addr if !destination.IsValid() { @@ -122,8 +122,8 @@ func (iface *Interface) pickIPAddr(destination netip.Addr, accept func(addr *net } } - if fallback == nil { - return nil, ErrAddrNotFound + if !fallback.IsValid() { + return netip.Prefix{}, ErrAddrNotFound } return fallback, nil diff --git a/config/config.go b/config/config.go index 994f897d..ed2505d9 100644 --- a/config/config.go +++ b/config/config.go @@ -122,7 +122,7 @@ type DNS struct { type FallbackFilter struct { GeoIP bool `yaml:"geoip"` GeoIPCode string `yaml:"geoip-code"` - IPCIDR []*netip.Prefix `yaml:"ipcidr"` + IPCIDR []netip.Prefix `yaml:"ipcidr"` Domain []string `yaml:"domain"` GeoSite []*router.DomainMatcher `yaml:"geosite"` } @@ -1148,15 +1148,15 @@ func parseNameServerPolicy(nsPolicy map[string]any, ruleProviders map[string]pro return policy, nil } -func parseFallbackIPCIDR(ips []string) ([]*netip.Prefix, error) { - var ipNets []*netip.Prefix +func parseFallbackIPCIDR(ips []string) ([]netip.Prefix, error) { + var ipNets []netip.Prefix for idx, ip := range ips { ipnet, err := netip.ParsePrefix(ip) if err != nil { return nil, fmt.Errorf("DNS FallbackIP[%d] format error: %s", idx, err.Error()) } - ipNets = append(ipNets, &ipnet) + ipNets = append(ipNets, ipnet) } return ipNets, nil @@ -1224,7 +1224,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul IPv6: cfg.IPv6, EnhancedMode: cfg.EnhancedMode, FallbackFilter: FallbackFilter{ - IPCIDR: []*netip.Prefix{}, + IPCIDR: []netip.Prefix{}, GeoSite: []*router.DomainMatcher{}, }, } @@ -1298,7 +1298,7 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul } pool, err := fakeip.New(fakeip.Options{ - IPNet: &fakeIPRange, + IPNet: fakeIPRange, Size: 1000, Host: host, Persistence: rawCfg.Profile.StoreFakeIP, diff --git a/dns/dhcp.go b/dns/dhcp.go index 2fa2e8a4..70f9aeeb 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -26,7 +26,7 @@ type dhcpClient struct { ifaceInvalidate time.Time dnsInvalidate time.Time - ifaceAddr *netip.Prefix + ifaceAddr netip.Prefix done chan struct{} clients []dnsClient err error diff --git a/dns/filters.go b/dns/filters.go index 47e7adcd..f7e953e8 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -45,7 +45,7 @@ func (gf *geoipFilter) Match(ip netip.Addr) bool { } type ipnetFilter struct { - ipnet *netip.Prefix + ipnet netip.Prefix } func (inf *ipnetFilter) Match(ip netip.Addr) bool { diff --git a/dns/resolver.go b/dns/resolver.go index 2851f012..d27f7bcc 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -398,7 +398,7 @@ type NameServer struct { type FallbackFilter struct { GeoIP bool GeoIPCode string - IPCIDR []*netip.Prefix + IPCIDR []netip.Prefix Domain []string GeoSite []*router.DomainMatcher } diff --git a/rules/common/ipcidr.go b/rules/common/ipcidr.go index 8ab6cf5a..4cdf9106 100644 --- a/rules/common/ipcidr.go +++ b/rules/common/ipcidr.go @@ -22,7 +22,7 @@ func WithIPCIDRNoResolve(noResolve bool) IPCIDROption { type IPCIDR struct { *Base - ipnet *netip.Prefix + ipnet netip.Prefix adapter string isSourceIP bool noResolveIP bool @@ -63,7 +63,7 @@ func NewIPCIDR(s string, adapter string, opts ...IPCIDROption) (*IPCIDR, error) ipcidr := &IPCIDR{ Base: &Base{}, - ipnet: &ipnet, + ipnet: ipnet, adapter: adapter, } From c3a61e2db5f38c29139e9a77a1be3ee7f277d7ac Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 11:09:19 +0800 Subject: [PATCH 511/530] build: add go120 build for win7/8.1 --- .github/rename-go120.sh | 12 ++++++++++++ .github/workflows/build.yml | 23 ++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 .github/rename-go120.sh diff --git a/.github/rename-go120.sh b/.github/rename-go120.sh new file mode 100644 index 00000000..136d74b5 --- /dev/null +++ b/.github/rename-go120.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +FILENAMES=$(ls) +for FILENAME in $FILENAMES +do + if [[ ! ($FILENAME =~ ".exe" || $FILENAME =~ ".sh")]];then + mc $FILENAME ${FILENAME}-go120 + elif [[ $FILENAME =~ ".exe" ]];then + mv $FILENAME ${FILENAME%.*}-go120.exe + else echo "skip $FILENAME" + fi +done \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index defd294b..df603041 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,6 +69,8 @@ jobs: target: "darwin-amd64 darwin-arm64 android-arm64", id: "9", } + # Go 1.21 requires at least Windows 10 or Windows Server 2016; support for previous versions has been discontinued. + - { type: "WithoutCGO-GO120", target: "windows-amd64-compatible windows-amd64 windows-386",id: "10" } - { type: "WithCGO", target: "windows/*", id: "1" } - { type: "WithCGO", target: "linux/386", id: "2" } - { type: "WithCGO", target: "linux/amd64", id: "3" } @@ -126,18 +128,26 @@ jobs: shell: bash - name: Setup Go + if: ${{ matrix.job.type!='WithoutCGO-GO120' }} uses: actions/setup-go@v4 with: go-version: "1.21" check-latest: true + - name: Setup Go + if: ${{ matrix.job.type=='WithoutCGO-GO120' }} + uses: actions/setup-go@v4 + with: + go-version: "1.20" + check-latest: true + - name: Test if: ${{ matrix.job.id=='1' && matrix.job.type=='WithoutCGO' }} run: | go test ./... - name: Build WithoutCGO - if: ${{ matrix.job.type=='WithoutCGO' }} + if: ${{ matrix.job.type!='WithCGO' }} env: NAME: Clash.Meta BINDIR: bin @@ -185,6 +195,17 @@ jobs: ls -la cd .. + - name: Rename + if: ${{ matrix.job.type=='WithoutCGO-GO120' }} + run: | + cd bin + ls -la + cp ../.github/rename-go120.sh ./ + bash ./rename-go120.sh + rm ./rename-go120.sh + ls -la + cd .. + - name: Zip if: ${{ success() }} run: | From 81a8a63861c56f1b81f59bc6b53d62d556a06baa Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 26 Oct 2023 11:39:54 +0800 Subject: [PATCH 512/530] build: more go120 build --- .github/rename-go120.sh | 2 +- .github/workflows/build.yml | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.github/rename-go120.sh b/.github/rename-go120.sh index 136d74b5..eddb1769 100644 --- a/.github/rename-go120.sh +++ b/.github/rename-go120.sh @@ -4,7 +4,7 @@ FILENAMES=$(ls) for FILENAME in $FILENAMES do if [[ ! ($FILENAME =~ ".exe" || $FILENAME =~ ".sh")]];then - mc $FILENAME ${FILENAME}-go120 + mv $FILENAME ${FILENAME}-go120 elif [[ $FILENAME =~ ".exe" ]];then mv $FILENAME ${FILENAME%.*}-go120.exe else echo "skip $FILENAME" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index df603041..57a00f3e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,8 +69,12 @@ jobs: target: "darwin-amd64 darwin-arm64 android-arm64", id: "9", } - # Go 1.21 requires at least Windows 10 or Windows Server 2016; support for previous versions has been discontinued. - - { type: "WithoutCGO-GO120", target: "windows-amd64-compatible windows-amd64 windows-386",id: "10" } + # only for test + - { type: "WithoutCGO-GO120", target: "linux-amd64 linux-amd64-compatible",id: "1" } + # Go 1.20 is the last release that will run on any release of Windows 7, 8, Server 2008 and Server 2012. Go 1.21 will require at least Windows 10 or Server 2016. + - { type: "WithoutCGO-GO120", target: "windows-amd64-compatible windows-amd64 windows-386",id: "2" } + # Go 1.20 is the last release that will run on macOS 10.13 High Sierra or 10.14 Mojave. Go 1.21 will require macOS 10.15 Catalina or later. + - { type: "WithoutCGO-GO120", target: "darwin-amd64 darwin-arm64 android-arm64",id: "3" } - { type: "WithCGO", target: "windows/*", id: "1" } - { type: "WithCGO", target: "linux/386", id: "2" } - { type: "WithCGO", target: "linux/amd64", id: "3" } @@ -142,7 +146,7 @@ jobs: check-latest: true - name: Test - if: ${{ matrix.job.id=='1' && matrix.job.type=='WithoutCGO' }} + if: ${{ matrix.job.id=='1' && matrix.job.type!='WithCGO' }} run: | go test ./... From d42e3f74ad89ef7827f4b7861efd0cdf880a8cde Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Thu, 26 Oct 2023 19:08:03 +0800 Subject: [PATCH 513/530] action: add question issue guidance --- .github/ISSUE_TEMPLATE/config.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 3ba13e0c..0cf54628 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1,5 @@ blank_issues_enabled: false +contact_links: + - name: Clash.Meta Community Support + url: https://github.com/MetaCubeX/Clash.Meta/discussions + about: Please ask and answer questions about Clash.Meta here. From 55255faa52455fdc51ae2037f3fc885f2cecb5b8 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Fri, 27 Oct 2023 17:49:12 +0800 Subject: [PATCH 514/530] chore: modify configuration fields --- config/config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index ed2505d9..e467c603 100644 --- a/config/config.go +++ b/config/config.go @@ -231,8 +231,8 @@ type RawTun struct { //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` - Inet4RouteAddress []netip.Prefix `yaml:"inet4_route_address" json:"inet4_route_address,omitempty"` - Inet6RouteAddress []netip.Prefix `yaml:"inet6_route_address" json:"inet6_route_address,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` From 2b9141e0e56c749382f3cd4c3bc1377b8b48206a Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Mon, 30 Oct 2023 19:46:56 +0800 Subject: [PATCH 515/530] chore: geo link replaced with github --- config/config.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/config.go b/config/config.go index e467c603..6b324286 100644 --- a/config/config.go +++ b/config/config.go @@ -461,9 +461,9 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { StoreSelected: true, }, 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", + Mmdb: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + GeoIp: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", + GeoSite: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat", }, ExternalUIURL: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip", } From 261b6e8dce1f5d3519282b87bb4f53ba6d5b1dd9 Mon Sep 17 00:00:00 2001 From: Steve Johnson <144257728+stevejohnson7@users.noreply.github.com> Date: Mon, 30 Oct 2023 20:00:15 +0800 Subject: [PATCH 516/530] action: small fix to cmfa core-update trigger --- .github/workflows/cmfa-update-deps-trigger.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmfa-update-deps-trigger.yml b/.github/workflows/cmfa-update-deps-trigger.yml index 51736644..549b0098 100644 --- a/.github/workflows/cmfa-update-deps-trigger.yml +++ b/.github/workflows/cmfa-update-deps-trigger.yml @@ -3,7 +3,7 @@ on: workflow_dispatch: push: tags: - - "v*" + - "*" pull_request_target: branches: - Alpha @@ -25,4 +25,4 @@ jobs: -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ -d '{"event_type": "core-updated"}' # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies - \ No newline at end of file + From 8ff476a3a1f2166d93bc0dda58b0350a970c3032 Mon Sep 17 00:00:00 2001 From: HolgerHuo Date: Tue, 31 Oct 2023 04:07:01 -0700 Subject: [PATCH 517/530] fix: remote logic rules cannot be parsed (#837) --- rules/provider/classical_strategy.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/rules/provider/classical_strategy.go b/rules/provider/classical_strategy.go index e187e213..032204e4 100644 --- a/rules/provider/classical_strategy.go +++ b/rules/provider/classical_strategy.go @@ -76,7 +76,11 @@ func ruleParse(ruleRaw string) (string, string, []string) { } else if len(item) == 2 { return item[0], item[1], nil } else if len(item) > 2 { - return item[0], item[1], item[2:] + if item[0] == "NOT" || item[0] == "OR" || item[0] == "AND" || item[0] == "SUB-RULE" { + return item[0], strings.Join(item[1:len(item)], ","), nil + } else { + return item[0], item[1], item[2:] + } } return "", "", nil From 96220aa8eaaf01a4117e23d6cdb79c86245350d2 Mon Sep 17 00:00:00 2001 From: Skyxim Date: Tue, 31 Oct 2023 11:10:38 +0000 Subject: [PATCH 518/530] feat: cancel RULE-SET nested SUB-RULE restrictions --- rules/provider/classical_strategy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rules/provider/classical_strategy.go b/rules/provider/classical_strategy.go index 032204e4..6561f12f 100644 --- a/rules/provider/classical_strategy.go +++ b/rules/provider/classical_strategy.go @@ -89,7 +89,7 @@ func ruleParse(ruleRaw string) (string, string, []string) { func NewClassicalStrategy(parse func(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error)) *classicalStrategy { return &classicalStrategy{rules: []C.Rule{}, parse: func(tp, payload, target string, params []string) (parsed C.Rule, parseErr error) { switch tp { - case "MATCH", "SUB-RULE": + case "MATCH": return nil, fmt.Errorf("unsupported rule type on rule-set") default: return parse(tp, payload, target, params, nil) From b0638cfc49500f63eef6c8ef27d48b559dac7f3b Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Nov 2023 10:31:58 +0800 Subject: [PATCH 519/530] chore: better bufio.Reader warp --- common/net/bufconn.go | 10 ++++++++++ transport/vmess/websocket.go | 23 ++++++++++++----------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/common/net/bufconn.go b/common/net/bufconn.go index 6da2d9d1..b840fefc 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -22,6 +22,16 @@ func NewBufferedConn(c net.Conn) *BufferedConn { return &BufferedConn{bufio.NewReader(c), NewExtendedConn(c), false} } +func WarpConnWithBioReader(c net.Conn, br *bufio.Reader) net.Conn { + if br != nil && br.Buffered() > 0 { + if bc, ok := c.(*BufferedConn); ok && bc.r == br { + return bc + } + return &BufferedConn{br, NewExtendedConn(c), true} + } + return c +} + // Reader returns the internal bufio.Reader. func (c *BufferedConn) Reader() *bufio.Reader { return c.r diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 83f5e3c2..1117edaf 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -1,7 +1,6 @@ package vmess import ( - "bufio" "bytes" "context" "crypto/tls" @@ -393,7 +392,11 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, return nil, fmt.Errorf("dial %s error: %w", uri.Host, err) } - conn = newWebsocketConn(conn, reader, ws.StateClientSide) + // some bytes which could be written by the peer right after response and be caught by us during buffered read, + // so we need warp Conn with bio.Reader + conn = N.WarpConnWithBioReader(conn, reader) + + conn = newWebsocketConn(conn, ws.StateClientSide) // websocketConn can't correct handle ReadDeadline // so call N.NewDeadlineConn to add a safe wrapper return N.NewDeadlineConn(conn), nil @@ -419,19 +422,13 @@ func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig) return streamWebsocketConn(ctx, conn, c, nil) } -func newWebsocketConn(conn net.Conn, br *bufio.Reader, state ws.State) *websocketConn { +func newWebsocketConn(conn net.Conn, state ws.State) *websocketConn { controlHandler := wsutil.ControlFrameHandler(conn, state) - var reader io.Reader - if br != nil && br.Buffered() > 0 { - reader = br - } else { - reader = conn - } return &websocketConn{ Conn: conn, state: state, reader: &wsutil.Reader{ - Source: reader, + Source: conn, State: state, SkipHeaderCheck: true, CheckUTF8: false, @@ -463,7 +460,11 @@ func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Co if err != nil { return nil, err } - conn := newWebsocketConn(wsConn, rw.Reader, ws.StateServerSide) + + // gobwas/ws will flush rw.Writer, so we only need warp rw.Reader + wsConn = N.WarpConnWithBioReader(wsConn, rw.Reader) + + conn := newWebsocketConn(wsConn, ws.StateServerSide) if edBuf := decodeXray0rtt(r.Header); len(edBuf) > 0 { return N.NewDeadlineConn(&websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}), nil } From ceac5bfaa4971c2e8215c9796b3fa96fab6b2828 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Nov 2023 11:11:19 +0800 Subject: [PATCH 520/530] feat: add `v2ray-http-upgrade` support --- adapter/outbound/shadowsocks.go | 26 ++++++++++--------- adapter/outbound/trojan.go | 7 ++--- adapter/outbound/vless.go | 1 + adapter/outbound/vmess.go | 2 ++ docs/config.yaml | 40 ++++++++++++++++------------- transport/trojan/trojan.go | 10 +++++--- transport/v2ray-plugin/websocket.go | 26 ++++++++++--------- transport/vmess/websocket.go | 34 ++++++++++++++++++++++++ 8 files changed, 97 insertions(+), 49 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 40868d04..1ae16c43 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -58,14 +58,15 @@ type simpleObfsOption struct { } type v2rayObfsOption struct { - Mode string `obfs:"mode"` - Host string `obfs:"host,omitempty"` - Path string `obfs:"path,omitempty"` - TLS bool `obfs:"tls,omitempty"` - Fingerprint string `obfs:"fingerprint,omitempty"` - Headers map[string]string `obfs:"headers,omitempty"` - SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` - Mux bool `obfs:"mux,omitempty"` + Mode string `obfs:"mode"` + Host string `obfs:"host,omitempty"` + Path string `obfs:"path,omitempty"` + TLS bool `obfs:"tls,omitempty"` + Fingerprint string `obfs:"fingerprint,omitempty"` + Headers map[string]string `obfs:"headers,omitempty"` + SkipCertVerify bool `obfs:"skip-cert-verify,omitempty"` + Mux bool `obfs:"mux,omitempty"` + V2rayHttpUpgrade bool `obfs:"v2ray-http-upgrade,omitempty"` } type shadowTLSOption struct { @@ -259,10 +260,11 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { } obfsMode = opts.Mode v2rayOption = &v2rayObfs.Option{ - Host: opts.Host, - Path: opts.Path, - Headers: opts.Headers, - Mux: opts.Mux, + Host: opts.Host, + Path: opts.Path, + Headers: opts.Headers, + Mux: opts.Mux, + V2rayHttpUpgrade: opts.V2rayHttpUpgrade, } if opts.TLS { diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index 337f2a38..d3c14e8a 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -53,9 +53,10 @@ func (t *Trojan) plainStream(ctx context.Context, c net.Conn) (net.Conn, error) if t.option.Network == "ws" { host, port, _ := net.SplitHostPort(t.addr) wsOpts := &trojan.WebsocketOption{ - Host: host, - Port: port, - Path: t.option.WSOpts.Path, + Host: host, + Port: port, + Path: t.option.WSOpts.Path, + V2rayHttpUpgrade: t.option.WSOpts.V2rayHttpUpgrade, } if t.option.SNI != "" { diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 037f3367..5f54153b 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -93,6 +93,7 @@ func (v *Vless) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M Path: v.option.WSOpts.Path, MaxEarlyData: v.option.WSOpts.MaxEarlyData, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, + V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade, ClientFingerprint: v.option.ClientFingerprint, Headers: http.Header{}, } diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index 326f0c6f..aed61aa3 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -91,6 +91,7 @@ type WSOptions struct { Headers map[string]string `proxy:"headers,omitempty"` MaxEarlyData int `proxy:"max-early-data,omitempty"` EarlyDataHeaderName string `proxy:"early-data-header-name,omitempty"` + V2rayHttpUpgrade bool `proxy:"v2ray-http-upgrade,omitempty"` } // StreamConnContext implements C.ProxyAdapter @@ -110,6 +111,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M Path: v.option.WSOpts.Path, MaxEarlyData: v.option.WSOpts.MaxEarlyData, EarlyDataHeaderName: v.option.WSOpts.EarlyDataHeaderName, + V2rayHttpUpgrade: v.option.WSOpts.V2rayHttpUpgrade, ClientFingerprint: v.option.ClientFingerprint, Headers: http.Header{}, } diff --git a/docs/config.yaml b/docs/config.yaml index 80fc2995..61a2dee9 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -352,16 +352,17 @@ proxies: # socks5 plugin: v2ray-plugin plugin-opts: mode: websocket # no QUIC now - # tls: true # wss - # 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取 - # 配置指纹将实现 SSL Pining 效果 - # fingerprint: xxxx - # skip-cert-verify: true - # host: bing.com - # path: "/" - # mux: true - # headers: - # custom: value + # tls: true # wss + # 可使用 openssl x509 -noout -fingerprint -sha256 -inform pem -in yourcert.pem 获取 + # 配置指纹将实现 SSL Pining 效果 + # fingerprint: xxxx + # skip-cert-verify: true + # host: bing.com + # path: "/" + # mux: true + # headers: + # custom: value + # v2ray-http-upgrade: false - name: "ss4-shadow-tls" type: ss @@ -434,11 +435,12 @@ proxies: # socks5 # servername: example.com # priority over wss host # network: ws # ws-opts: - # path: /path - # headers: - # Host: v2ray.com - # max-early-data: 2048 - # early-data-header-name: Sec-WebSocket-Protocol + # path: /path + # headers: + # Host: v2ray.com + # max-early-data: 2048 + # early-data-header-name: Sec-WebSocket-Protocol + # v2ray-http-upgrade: false - name: "vmess-h2" type: vmess @@ -566,6 +568,7 @@ proxies: # socks5 path: "/" headers: Host: example.com + # v2ray-http-upgrade: false # Trojan - name: "trojan" @@ -606,9 +609,10 @@ proxies: # socks5 # fingerprint: xxxx udp: true # ws-opts: - # path: /path - # headers: - # Host: example.com + # path: /path + # headers: + # Host: example.com + # v2ray-http-upgrade: false - name: "trojan-xtls" type: trojan diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 6dfcfe11..20ba80b3 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -55,10 +55,11 @@ type Option struct { } type WebsocketOption struct { - Host string - Port string - Path string - Headers http.Header + Host string + Port string + Path string + Headers http.Header + V2rayHttpUpgrade bool } type Trojan struct { @@ -132,6 +133,7 @@ func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptio Port: wsOptions.Port, Path: wsOptions.Path, Headers: wsOptions.Headers, + V2rayHttpUpgrade: wsOptions.V2rayHttpUpgrade, TLS: true, TLSConfig: tlsConfig, ClientFingerprint: t.option.ClientFingerprint, diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 066a3e2a..9cb4420c 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -12,14 +12,15 @@ import ( // Option is options of websocket obfs type Option struct { - Host string - Port string - Path string - Headers map[string]string - TLS bool - SkipCertVerify bool - Fingerprint string - Mux bool + Host string + Port string + Path string + Headers map[string]string + TLS bool + SkipCertVerify bool + Fingerprint string + Mux bool + V2rayHttpUpgrade bool } // NewV2rayObfs return a HTTPObfs @@ -30,10 +31,11 @@ func NewV2rayObfs(ctx context.Context, conn net.Conn, option *Option) (net.Conn, } config := &vmess.WebsocketConfig{ - Host: option.Host, - Port: option.Port, - Path: option.Path, - Headers: header, + Host: option.Host, + Port: option.Port, + Path: option.Path, + V2rayHttpUpgrade: option.V2rayHttpUpgrade, + Headers: header, } if option.TLS { diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 1117edaf..9b325ee9 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -55,6 +55,7 @@ type WebsocketConfig struct { MaxEarlyData int EarlyDataHeaderName string ClientFingerprint string + V2rayHttpUpgrade bool } // Read implements net.Conn.Read() @@ -352,6 +353,39 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, RawQuery: u.RawQuery, } + if c.V2rayHttpUpgrade { + if c.TLS { + if dialer.TLSClient != nil { + conn = dialer.TLSClient(conn, uri.Host) + } else { + conn = tls.Client(conn, dialer.TLSConfig) + } + } + request := &http.Request{ + Method: http.MethodGet, + URL: &uri, + Header: c.Headers.Clone(), + Host: c.Host, + } + request.Header.Set("Connection", "Upgrade") + request.Header.Set("Upgrade", "websocket") + err = request.Write(conn) + if err != nil { + return nil, err + } + bufferedConn := N.NewBufferedConn(conn) + response, err := http.ReadResponse(bufferedConn.Reader(), request) + if err != nil { + return nil, err + } + if response.StatusCode != 101 || + !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || + !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { + return nil, fmt.Errorf("unexpected status: %s", response.Status) + } + return bufferedConn, nil + } + headers := http.Header{} headers.Set("User-Agent", "Go-http-client/1.1") // match golang's net/http if c.Headers != nil { From 5bfe7ba169d29fd99ef8e8d995d07c4d5de96f79 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Nov 2023 11:22:01 +0800 Subject: [PATCH 521/530] chore: better tls handshake --- component/tls/utls.go | 2 +- transport/gun/gun.go | 4 ++-- transport/vmess/websocket.go | 9 ++++++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/component/tls/utls.go b/component/tls/utls.go index e3d101dc..3aa030d3 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -21,7 +21,7 @@ type UClientHelloID struct { var initRandomFingerprint UClientHelloID var initUtlsClient string -func UClient(c net.Conn, config *tls.Config, fingerprint UClientHelloID) net.Conn { +func UClient(c net.Conn, config *tls.Config, fingerprint UClientHelloID) *UConn { utlsConn := utls.UClient(c, copyConfig(config), utls.ClientHelloID{ Client: fingerprint.Client, Version: fingerprint.Version, diff --git a/transport/gun/gun.go b/transport/gun/gun.go index cfe8aa3d..d6ef6317 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -209,11 +209,11 @@ func NewHTTP2Client(dialFn DialFn, tlsConfig *tls.Config, Fingerprint string, re if realityConfig == nil { if fingerprint, exists := tlsC.GetFingerprint(Fingerprint); exists { utlsConn := tlsC.UClient(pconn, cfg, fingerprint) - if err := utlsConn.(*tlsC.UConn).HandshakeContext(ctx); err != nil { + if err := utlsConn.HandshakeContext(ctx); err != nil { pconn.Close() return nil, err } - state := utlsConn.(*tlsC.UConn).ConnectionState() + state := utlsConn.ConnectionState() if p := state.NegotiatedProtocol; p != http2.NextProtoTLS { utlsConn.Close() return nil, fmt.Errorf("http2: unexpected ALPN protocol %s, want %s", p, http2.NextProtoTLS) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 9b325ee9..3f4c0a33 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -330,7 +330,7 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) - if err := utlsConn.(*tlsC.UConn).BuildWebsocketHandshakeState(); err != nil { + if err := utlsConn.BuildWebsocketHandshakeState(); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } @@ -360,6 +360,13 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, } else { conn = tls.Client(conn, dialer.TLSConfig) } + if tlsConn, ok := conn.(interface { + HandshakeContext(ctx context.Context) error + }); ok { + if err = tlsConn.HandshakeContext(ctx); err != nil { + return nil, err + } + } } request := &http.Request{ Method: http.MethodGet, From a82ce85707bf2077bb063a769bf02076af95fe9f Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Thu, 2 Nov 2023 11:37:40 +0800 Subject: [PATCH 522/530] chore: add route exclude support --- config/config.go | 64 ++++++++++++++------------- go.mod | 3 +- go.sum | 6 ++- hub/route/configs.go | 42 ++++++++++++------ listener/config/tun.go | 34 +++++++------- listener/inbound/tun.go | 88 +++++++++++++++++++++---------------- listener/listener.go | 10 +++++ listener/sing_tun/server.go | 34 +++++++------- 8 files changed, 164 insertions(+), 117 deletions(-) diff --git a/config/config.go b/config/config.go index 6b324286..11951aa1 100644 --- a/config/config.go +++ b/config/config.go @@ -229,20 +229,22 @@ type RawTun struct { MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` - Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` - Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"` - Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` - FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` + Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4_route_exclude_address,omitempty"` + Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6_route_exclude_address,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` } type RawTuicServer struct { @@ -1361,22 +1363,24 @@ func parseTun(rawTun RawTun, general *General) error { AutoDetectInterface: rawTun.AutoDetectInterface, RedirectToTun: rawTun.RedirectToTun, - MTU: rawTun.MTU, - Inet4Address: []netip.Prefix{tunAddressPrefix}, - Inet6Address: rawTun.Inet6Address, - StrictRoute: rawTun.StrictRoute, - Inet4RouteAddress: rawTun.Inet4RouteAddress, - Inet6RouteAddress: rawTun.Inet6RouteAddress, - IncludeUID: rawTun.IncludeUID, - IncludeUIDRange: rawTun.IncludeUIDRange, - ExcludeUID: rawTun.ExcludeUID, - ExcludeUIDRange: rawTun.ExcludeUIDRange, - IncludeAndroidUser: rawTun.IncludeAndroidUser, - IncludePackage: rawTun.IncludePackage, - ExcludePackage: rawTun.ExcludePackage, - EndpointIndependentNat: rawTun.EndpointIndependentNat, - UDPTimeout: rawTun.UDPTimeout, - FileDescriptor: rawTun.FileDescriptor, + MTU: rawTun.MTU, + Inet4Address: []netip.Prefix{tunAddressPrefix}, + Inet6Address: rawTun.Inet6Address, + StrictRoute: rawTun.StrictRoute, + Inet4RouteAddress: rawTun.Inet4RouteAddress, + Inet6RouteAddress: rawTun.Inet6RouteAddress, + Inet4RouteExcludeAddress: rawTun.Inet4RouteExcludeAddress, + Inet6RouteExcludeAddress: rawTun.Inet6RouteExcludeAddress, + IncludeUID: rawTun.IncludeUID, + IncludeUIDRange: rawTun.IncludeUIDRange, + ExcludeUID: rawTun.ExcludeUID, + ExcludeUIDRange: rawTun.ExcludeUIDRange, + IncludeAndroidUser: rawTun.IncludeAndroidUser, + IncludePackage: rawTun.IncludePackage, + ExcludePackage: rawTun.ExcludePackage, + EndpointIndependentNat: rawTun.EndpointIndependentNat, + UDPTimeout: rawTun.UDPTimeout, + FileDescriptor: rawTun.FileDescriptor, } return nil diff --git a/go.mod b/go.mod index f355a977..5211f3ce 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700 + github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56 github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 @@ -101,6 +101,7 @@ require ( github.com/yusufpapurcu/wmi v1.2.3 // indirect gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.3.0 // indirect + go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect golang.org/x/mod v0.13.0 // indirect golang.org/x/text v0.13.0 // indirect golang.org/x/time v0.3.0 // indirect diff --git a/go.sum b/go.sum index be89ca4d..d8a56527 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700 h1:JToLa8cxHrd6tOUHWCg9YM+o/4MXmjgagG909itmnyE= -github.com/metacubex/sing-tun v0.1.15-0.20231022153326-92d6e97f0700/go.mod h1:atkIOs6Y5NeUzstK5SBvnrFo4z1JLuORhEfQECEVUpI= +github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56 h1:ietLSuWRlYrNukGEEn/WXioB4OKPebqpZCc93MRKxEU= +github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= @@ -211,6 +211,8 @@ go.uber.org/automaxprocs v1.5.3 h1:kWazyxZUrS3Gs4qUpbwo5kEIMGe/DAvi5Z4tl2NW4j8= go.uber.org/automaxprocs v1.5.3/go.mod h1:eRbA25aqJrxAbsLO0xy5jVwPt7FQnRgjW+efnwa1WM0= go.uber.org/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= +go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= 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.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= diff --git a/hub/route/configs.go b/hub/route/configs.go index cb500157..e86bb2a8 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -70,20 +70,22 @@ type tunSchema struct { MTU *uint32 `yaml:"mtu" json:"mtu,omitempty"` //Inet4Address *[]netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` - Inet4RouteAddress *[]netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` - Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` - IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` - IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` - ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` - ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` - IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` - IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` - ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` - EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` - UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` - FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` + Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` + Inet4RouteAddress *[]netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress *[]netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + Inet4RouteExcludeAddress *[]netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` + Inet6RouteExcludeAddress *[]netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` + IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange *[]string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID *[]uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange *[]string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser *[]int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage *[]string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage *[]string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat *bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout *int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor *int `yaml:"file-descriptor" json:"file-descriptor"` } type tuicServerSchema struct { @@ -148,6 +150,18 @@ func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun { if p.Inet6Address != nil { def.Inet6Address = *p.Inet6Address } + if p.Inet4RouteAddress != nil { + def.Inet4RouteAddress = *p.Inet4RouteAddress + } + if p.Inet6RouteAddress != nil { + def.Inet6RouteAddress = *p.Inet6RouteAddress + } + if p.Inet4RouteExcludeAddress != nil { + def.Inet4RouteExcludeAddress = *p.Inet4RouteExcludeAddress + } + if p.Inet6RouteExcludeAddress != nil { + def.Inet6RouteExcludeAddress = *p.Inet6RouteExcludeAddress + } if p.IncludeUID != nil { def.IncludeUID = *p.IncludeUID } diff --git a/listener/config/tun.go b/listener/config/tun.go index 06e92188..3f151d1e 100644 --- a/listener/config/tun.go +++ b/listener/config/tun.go @@ -27,20 +27,22 @@ type Tun struct { AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"` RedirectToTun []string `yaml:"-" json:"-"` - MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` - Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` - Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` - Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` - Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include-android-user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include-package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` - FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` + MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` + Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` + Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` + FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` } diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index 9ba7ae87..472269d6 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -18,22 +18,24 @@ type TunOption struct { AutoRoute bool `inbound:"auto-route,omitempty"` AutoDetectInterface bool `inbound:"auto-detect-interface,omitempty"` - MTU uint32 `inbound:"mtu,omitempty"` - Inet4Address []string `inbound:"inet4_address,omitempty"` - Inet6Address []string `inbound:"inet6_address,omitempty"` - StrictRoute bool `inbound:"strict_route,omitempty"` - Inet4RouteAddress []string `inbound:"inet4_route_address,omitempty"` - Inet6RouteAddress []string `inbound:"inet6_route_address,omitempty"` - IncludeUID []uint32 `inbound:"include_uid,omitempty"` - IncludeUIDRange []string `inbound:"include_uid_range,omitempty"` - ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"` - ExcludeUIDRange []string `inbound:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `inbound:"include_android_user,omitempty"` - IncludePackage []string `inbound:"include_package,omitempty"` - ExcludePackage []string `inbound:"exclude_package,omitempty"` - EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `inbound:"udp_timeout,omitempty"` - FileDescriptor int `inbound:"file-descriptor,omitempty"` + MTU uint32 `inbound:"mtu,omitempty"` + Inet4Address []string `inbound:"inet4_address,omitempty"` + Inet6Address []string `inbound:"inet6_address,omitempty"` + StrictRoute bool `inbound:"strict_route,omitempty"` + Inet4RouteAddress []string `inbound:"inet4_route_address,omitempty"` + Inet6RouteAddress []string `inbound:"inet6_route_address,omitempty"` + Inet4RouteExcludeAddress []string `inbound:"inet4_route_exclude_address,omitempty"` + Inet6RouteExcludeAddress []string `inbound:"inet6_route_exclude_address,omitempty"` + IncludeUID []uint32 `inbound:"include_uid,omitempty"` + IncludeUIDRange []string `inbound:"include_uid_range,omitempty"` + ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"` + ExcludeUIDRange []string `inbound:"exclude_uid_range,omitempty"` + IncludeAndroidUser []int `inbound:"include_android_user,omitempty"` + IncludePackage []string `inbound:"include_package,omitempty"` + ExcludePackage []string `inbound:"exclude_package,omitempty"` + EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"` + UDPTimeout int64 `inbound:"udp_timeout,omitempty"` + FileDescriptor int `inbound:"file-descriptor,omitempty"` } func (o TunOption) Equal(config C.InboundConfig) bool { @@ -72,32 +74,42 @@ func NewTun(options *TunOption) (*Tun, error) { if err != nil { return nil, err } + inet4RouteExcludeAddress, err := LC.StringSliceToNetipPrefixSlice(options.Inet4RouteExcludeAddress) + if err != nil { + return nil, err + } + inet6RouteExcludeAddress, err := LC.StringSliceToNetipPrefixSlice(options.Inet6RouteExcludeAddress) + if err != nil { + return nil, err + } return &Tun{ Base: base, config: options, tun: LC.Tun{ - Enable: true, - Device: options.Device, - Stack: stack, - DNSHijack: options.DNSHijack, - AutoRoute: options.AutoRoute, - AutoDetectInterface: options.AutoDetectInterface, - MTU: options.MTU, - Inet4Address: inet4Address, - Inet6Address: inet6Address, - StrictRoute: options.StrictRoute, - Inet4RouteAddress: inet4RouteAddress, - Inet6RouteAddress: inet6RouteAddress, - IncludeUID: options.IncludeUID, - IncludeUIDRange: options.IncludeUIDRange, - ExcludeUID: options.ExcludeUID, - ExcludeUIDRange: options.ExcludeUIDRange, - IncludeAndroidUser: options.IncludeAndroidUser, - IncludePackage: options.IncludePackage, - ExcludePackage: options.ExcludePackage, - EndpointIndependentNat: options.EndpointIndependentNat, - UDPTimeout: options.UDPTimeout, - FileDescriptor: options.FileDescriptor, + Enable: true, + Device: options.Device, + Stack: stack, + DNSHijack: options.DNSHijack, + AutoRoute: options.AutoRoute, + AutoDetectInterface: options.AutoDetectInterface, + MTU: options.MTU, + Inet4Address: inet4Address, + Inet6Address: inet6Address, + StrictRoute: options.StrictRoute, + Inet4RouteAddress: inet4RouteAddress, + Inet6RouteAddress: inet6RouteAddress, + Inet4RouteExcludeAddress: inet4RouteExcludeAddress, + Inet6RouteExcludeAddress: inet6RouteExcludeAddress, + IncludeUID: options.IncludeUID, + IncludeUIDRange: options.IncludeUIDRange, + ExcludeUID: options.ExcludeUID, + ExcludeUIDRange: options.ExcludeUIDRange, + IncludeAndroidUser: options.IncludeAndroidUser, + IncludePackage: options.IncludePackage, + ExcludePackage: options.ExcludePackage, + EndpointIndependentNat: options.EndpointIndependentNat, + UDPTimeout: options.UDPTimeout, + FileDescriptor: options.FileDescriptor, }, }, nil } diff --git a/listener/listener.go b/listener/listener.go index ad3b2351..a6bbdbf5 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -849,6 +849,14 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { return tunConf.Inet6RouteAddress[i].String() < tunConf.Inet6RouteAddress[j].String() }) + sort.Slice(tunConf.Inet4RouteExcludeAddress, func(i, j int) bool { + return tunConf.Inet4RouteExcludeAddress[i].String() < tunConf.Inet4RouteExcludeAddress[j].String() + }) + + sort.Slice(tunConf.Inet6RouteExcludeAddress, func(i, j int) bool { + return tunConf.Inet6RouteExcludeAddress[i].String() < tunConf.Inet6RouteExcludeAddress[j].String() + }) + sort.Slice(tunConf.IncludeUID, func(i, j int) bool { return tunConf.IncludeUID[i] < tunConf.IncludeUID[j] }) @@ -882,6 +890,8 @@ func hasTunConfigChange(tunConf *LC.Tun) bool { !slices.Equal(tunConf.Inet6Address, LastTunConf.Inet6Address) || !slices.Equal(tunConf.Inet4RouteAddress, LastTunConf.Inet4RouteAddress) || !slices.Equal(tunConf.Inet6RouteAddress, LastTunConf.Inet6RouteAddress) || + !slices.Equal(tunConf.Inet4RouteExcludeAddress, LastTunConf.Inet4RouteExcludeAddress) || + !slices.Equal(tunConf.Inet6RouteExcludeAddress, LastTunConf.Inet6RouteExcludeAddress) || !slices.Equal(tunConf.IncludeUID, LastTunConf.IncludeUID) || !slices.Equal(tunConf.IncludeUIDRange, LastTunConf.IncludeUIDRange) || !slices.Equal(tunConf.ExcludeUID, LastTunConf.ExcludeUID) || diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 122e9af3..0548ac41 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -199,22 +199,24 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis } tunOptions := tun.Options{ - Name: tunName, - MTU: tunMTU, - Inet4Address: options.Inet4Address, - Inet6Address: options.Inet6Address, - AutoRoute: options.AutoRoute, - StrictRoute: options.StrictRoute, - Inet4RouteAddress: options.Inet4RouteAddress, - Inet6RouteAddress: options.Inet6RouteAddress, - IncludeUID: includeUID, - ExcludeUID: excludeUID, - IncludeAndroidUser: options.IncludeAndroidUser, - IncludePackage: options.IncludePackage, - ExcludePackage: options.ExcludePackage, - FileDescriptor: options.FileDescriptor, - InterfaceMonitor: defaultInterfaceMonitor, - TableIndex: 2022, + Name: tunName, + MTU: tunMTU, + Inet4Address: options.Inet4Address, + Inet6Address: options.Inet6Address, + AutoRoute: options.AutoRoute, + StrictRoute: options.StrictRoute, + Inet4RouteAddress: options.Inet4RouteAddress, + Inet6RouteAddress: options.Inet6RouteAddress, + Inet4RouteExcludeAddress: options.Inet4RouteExcludeAddress, + Inet6RouteExcludeAddress: options.Inet6RouteExcludeAddress, + IncludeUID: includeUID, + ExcludeUID: excludeUID, + IncludeAndroidUser: options.IncludeAndroidUser, + IncludePackage: options.IncludePackage, + ExcludePackage: options.ExcludePackage, + FileDescriptor: options.FileDescriptor, + InterfaceMonitor: defaultInterfaceMonitor, + TableIndex: 2022, } err = l.buildAndroidRules(&tunOptions) From ef303b11f21edb3716865a5b5f7c00faf152874b Mon Sep 17 00:00:00 2001 From: Steve Johnson Date: Thu, 2 Nov 2023 16:01:35 +0800 Subject: [PATCH 523/530] action: trigger CMFA PR update in every commit --- .../workflows/android-branch-auto-sync.yml | 20 ++++++++++++- .../workflows/cmfa-update-deps-trigger.yml | 28 ------------------- 2 files changed, 19 insertions(+), 29 deletions(-) delete mode 100644 .github/workflows/cmfa-update-deps-trigger.yml diff --git a/.github/workflows/android-branch-auto-sync.yml b/.github/workflows/android-branch-auto-sync.yml index 5dbbd5be..c7ee5eba 100644 --- a/.github/workflows/android-branch-auto-sync.yml +++ b/.github/workflows/android-branch-auto-sync.yml @@ -48,4 +48,22 @@ jobs: - name: Push changes run: | - git push origin android-real --force \ No newline at end of file + git push origin android-real --force + + # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies + trigger-CMFA-update: + needs: update-dependencies + runs-on: ubuntu-latest + steps: + - uses: tibdex/github-app-token@v1 + id: generate-token + with: + app_id: ${{ secrets.MAINTAINER_APPID }} + private_key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }} + + - name: Trigger update-dependencies + run: | + curl -X POST https://api.github.com/repos/MetaCubeX/ClashMetaForAndroid/dispatches \ + -H "Accept: application/vnd.github.everest-preview+json" \ + -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ + -d '{"event_type": "core-updated"}' \ No newline at end of file diff --git a/.github/workflows/cmfa-update-deps-trigger.yml b/.github/workflows/cmfa-update-deps-trigger.yml deleted file mode 100644 index 549b0098..00000000 --- a/.github/workflows/cmfa-update-deps-trigger.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: CMFA auto update-dependencies trigger -on: - workflow_dispatch: - push: - tags: - - "*" - pull_request_target: - branches: - - Alpha - -jobs: - update-dependencies: - runs-on: ubuntu-latest - steps: - - uses: tibdex/github-app-token@v1 - id: generate-token - with: - app_id: ${{ secrets.MAINTAINER_APPID }} - private_key: ${{ secrets.MAINTAINER_APP_PRIVATE_KEY }} - - - name: Trigger update-dependencies - run: | - curl -X POST https://api.github.com/repos/MetaCubeX/ClashMetaForAndroid/dispatches \ - -H "Accept: application/vnd.github.everest-preview+json" \ - -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ - -d '{"event_type": "core-updated"}' - # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies - From 885ee7a8208aa461b1e322fa9fe6470f8a637c34 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 09:32:22 +0800 Subject: [PATCH 524/530] fix: v2ray http upgrade `Hosts` header not working --- transport/vmess/websocket.go | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 3f4c0a33..ebafefa4 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -376,6 +376,10 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, } request.Header.Set("Connection", "Upgrade") request.Header.Set("Upgrade", "websocket") + if host := request.Header.Get("Host"); host != "" { + request.Header.Del("Host") + request.Host = host + } err = request.Write(conn) if err != nil { return nil, err @@ -415,16 +419,16 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if secProtocol := headers.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols // to avoid send repeatedly don't set it to headers - headers.Del("Sec-WebSocket-Protocol") dialer.Protocols = []string{secProtocol} } + headers.Del("Sec-WebSocket-Protocol") // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` // if headers has "Host" will send repeatedly if host := headers.Get("Host"); host != "" { - headers.Del("Host") uri.Host = host } + headers.Del("Host") dialer.Header = ws.HandshakeHeaderHTTP(headers) From ee3038d5e4e80fcc82cd849c30a5f6801af4607d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 11:00:40 +0800 Subject: [PATCH 525/530] chore: add SetupContextForConn for common/net --- common/net/context.go | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 common/net/context.go diff --git a/common/net/context.go b/common/net/context.go new file mode 100644 index 00000000..917028d1 --- /dev/null +++ b/common/net/context.go @@ -0,0 +1,31 @@ +package net + +import ( + "context" + "net" +) + +// SetupContextForConn is a helper function that starts connection I/O interrupter goroutine. +func SetupContextForConn(ctx context.Context, conn net.Conn) (done func(*error)) { + var ( + quit = make(chan struct{}) + interrupt = make(chan error, 1) + ) + go func() { + select { + case <-quit: + interrupt <- nil + case <-ctx.Done(): + // Close the connection, discarding the error + _ = conn.Close() + interrupt <- ctx.Err() + } + }() + return func(inputErr *error) { + close(quit) + if ctxErr := <-interrupt; ctxErr != nil && inputErr != nil { + // Return context error to user. + inputErr = &ctxErr + } + } +} From 665ba7f9f179a69e4da357ef2eae186fa32cdbd8 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 11:02:19 +0800 Subject: [PATCH 526/530] chore: do websocket client upgrade directly instead of gobwas/ws --- transport/vmess/websocket.go | 165 +++++++++++++++++------------------ 1 file changed, 81 insertions(+), 84 deletions(-) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index ebafefa4..60353d5a 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -3,6 +3,7 @@ package vmess import ( "bytes" "context" + "crypto/sha1" "crypto/tls" "encoding/base64" "encoding/binary" @@ -19,6 +20,7 @@ import ( "github.com/Dreamacro/clash/common/buf" N "github.com/Dreamacro/clash/common/net" tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/Dreamacro/clash/log" "github.com/gobwas/ws" "github.com/gobwas/ws/wsutil" @@ -317,35 +319,35 @@ func streamWebsocketWithEarlyDataConn(conn net.Conn, c *WebsocketConfig) (net.Co } func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, earlyData *bytes.Buffer) (net.Conn, error) { - dialer := ws.Dialer{ - NetDial: func(ctx context.Context, network, addr string) (net.Conn, error) { - return conn, nil - }, - TLSConfig: c.TLSConfig, + u, err := url.Parse(c.Path) + if err != nil { + return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } + scheme := "ws" if c.TLS { scheme = "wss" if len(c.ClientFingerprint) != 0 { if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) - - if err := utlsConn.BuildWebsocketHandshakeState(); err != nil { + if err = utlsConn.BuildWebsocketHandshakeState(); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } + conn = utlsConn + } + } else { + conn = tls.Client(conn, c.TLSConfig) + } - dialer.TLSClient = func(conn net.Conn, hostname string) net.Conn { - return utlsConn - } + if tlsConn, ok := conn.(interface { + HandshakeContext(ctx context.Context) error + }); ok { + if err = tlsConn.HandshakeContext(ctx); err != nil { + return nil, err } } } - u, err := url.Parse(c.Path) - if err != nil { - return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) - } - uri := url.URL{ Scheme: scheme, Host: net.JoinHostPort(c.Host, c.Port), @@ -353,56 +355,36 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, RawQuery: u.RawQuery, } - if c.V2rayHttpUpgrade { - if c.TLS { - if dialer.TLSClient != nil { - conn = dialer.TLSClient(conn, uri.Host) - } else { - conn = tls.Client(conn, dialer.TLSConfig) - } - if tlsConn, ok := conn.(interface { - HandshakeContext(ctx context.Context) error - }); ok { - if err = tlsConn.HandshakeContext(ctx); err != nil { - return nil, err - } - } - } - request := &http.Request{ - Method: http.MethodGet, - URL: &uri, - Header: c.Headers.Clone(), - Host: c.Host, - } - request.Header.Set("Connection", "Upgrade") - request.Header.Set("Upgrade", "websocket") - if host := request.Header.Get("Host"); host != "" { - request.Header.Del("Host") - request.Host = host - } - err = request.Write(conn) - if err != nil { - return nil, err - } - bufferedConn := N.NewBufferedConn(conn) - response, err := http.ReadResponse(bufferedConn.Reader(), request) - if err != nil { - return nil, err - } - if response.StatusCode != 101 || - !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || - !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { - return nil, fmt.Errorf("unexpected status: %s", response.Status) - } - return bufferedConn, nil + request := &http.Request{ + Method: http.MethodGet, + URL: &uri, + Header: c.Headers.Clone(), + Host: c.Host, } - headers := http.Header{} - headers.Set("User-Agent", "Go-http-client/1.1") // match golang's net/http - if c.Headers != nil { - for k := range c.Headers { - headers.Add(k, c.Headers.Get(k)) + request.Header.Set("Connection", "Upgrade") + request.Header.Set("Upgrade", "websocket") + + if host := request.Header.Get("Host"); host != "" { + // For client requests, Host optionally overrides the Host + // header to send. If empty, the Request.Write method uses + // the value of URL.Host. Host may contain an international + // domain name. + request.Host = host + } + request.Header.Del("Host") + + var nonce string + if !c.V2rayHttpUpgrade { + const nonceKeySize = 16 + // NOTE: bts does not escape. + bts := make([]byte, nonceKeySize) + if _, err = fastrand.Read(bts); err != nil { + return nil, fmt.Errorf("rand read error: %w", err) } + nonce = base64.StdEncoding.EncodeToString(bts) + request.Header.Set("Sec-WebSocket-Version", "13") + request.Header.Set("Sec-WebSocket-Key", nonce) } if earlyData != nil { @@ -410,36 +392,51 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if c.EarlyDataHeaderName == "" { uri.Path += earlyDataString } else { - headers.Set(c.EarlyDataHeaderName, earlyDataString) + request.Header.Set(c.EarlyDataHeaderName, earlyDataString) } } - // gobwas/ws will check server's response "Sec-Websocket-Protocol" so must add Protocols to ws.Dialer - // if not will cause ws.ErrHandshakeBadSubProtocol - if secProtocol := headers.Get("Sec-WebSocket-Protocol"); len(secProtocol) > 0 { - // gobwas/ws will set "Sec-Websocket-Protocol" according dialer.Protocols - // to avoid send repeatedly don't set it to headers - dialer.Protocols = []string{secProtocol} + if ctx.Done() != nil { + done := N.SetupContextForConn(ctx, conn) + defer done(&err) } - headers.Del("Sec-WebSocket-Protocol") - // gobwas/ws send "Host" directly in Upgrade() by `httpWriteHeader(bw, headerHost, u.Host)` - // if headers has "Host" will send repeatedly - if host := headers.Get("Host"); host != "" { - uri.Host = host - } - headers.Del("Host") - - dialer.Header = ws.HandshakeHeaderHTTP(headers) - - conn, reader, _, err := dialer.Dial(ctx, uri.String()) + err = request.Write(conn) if err != nil { - return nil, fmt.Errorf("dial %s error: %w", uri.Host, err) + return nil, err + } + bufferedConn := N.NewBufferedConn(conn) + response, err := http.ReadResponse(bufferedConn.Reader(), request) + if err != nil { + return nil, err + } + if response.StatusCode != http.StatusSwitchingProtocols || + !strings.EqualFold(response.Header.Get("Connection"), "upgrade") || + !strings.EqualFold(response.Header.Get("Upgrade"), "websocket") { + return nil, fmt.Errorf("unexpected status: %s", response.Status) } - // some bytes which could be written by the peer right after response and be caught by us during buffered read, - // so we need warp Conn with bio.Reader - conn = N.WarpConnWithBioReader(conn, reader) + if c.V2rayHttpUpgrade { + return bufferedConn, nil + } + + if log.Level() == log.DEBUG { // we might not check this for performance + secAccept := response.Header.Get("Sec-Websocket-Accept") + const acceptSize = 28 // base64.StdEncoding.EncodedLen(sha1.Size) + if lenSecAccept := len(secAccept); lenSecAccept != acceptSize { + return nil, fmt.Errorf("unexpected Sec-Websocket-Accept length: %d", lenSecAccept) + } + + const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + const nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize) + p := make([]byte, nonceSize+len(magic)) + copy(p[:nonceSize], nonce) + copy(p[nonceSize:], magic) + sum := sha1.Sum(p) + if accept := base64.StdEncoding.EncodeToString(sum[:]); accept != secAccept { + return nil, errors.New("unexpected Sec-Websocket-Accept") + } + } conn = newWebsocketConn(conn, ws.StateClientSide) // websocketConn can't correct handle ReadDeadline From 09e7866a5c696b965b8d13eecbdf9612cc4ecdfe Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 11:08:04 +0800 Subject: [PATCH 527/530] fix: gvisor panic --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5211f3ce..80ab477c 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 github.com/metacubex/sing-shadowsocks v0.2.5 github.com/metacubex/sing-shadowsocks2 v0.1.4 - github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56 + github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 github.com/miekg/dns v1.1.56 diff --git a/go.sum b/go.sum index d8a56527..6a6356c1 100644 --- a/go.sum +++ b/go.sum @@ -107,8 +107,8 @@ github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= github.com/metacubex/sing-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56 h1:ietLSuWRlYrNukGEEn/WXioB4OKPebqpZCc93MRKxEU= -github.com/metacubex/sing-tun v0.1.15-0.20231102032628-0f8a17217e56/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= +github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd h1:k0+92eARqyTAovGhg2AxdsMWHjUsdiGCnR5NuXF3CQY= +github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= From 228990472d8dd2856f7c4b6cac8d7dbe8f96fa3a Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 12:04:22 +0800 Subject: [PATCH 528/530] fix: avoid tls panic --- transport/vmess/websocket.go | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 60353d5a..0c2a3a16 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -324,19 +324,34 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } - scheme := "ws" + uri := url.URL{ + Scheme: "ws", + Host: net.JoinHostPort(c.Host, c.Port), + Path: u.Path, + RawQuery: u.RawQuery, + } + if c.TLS { - scheme = "wss" + uri.Scheme = "wss" + config := c.TLSConfig + if config == nil { // The config cannot be nil + config = &tls.Config{NextProtos: []string{"http/1.1"}} + } + if config.ServerName == "" && !config.InsecureSkipVerify { // users must set either ServerName or InsecureSkipVerify in the config. + config = config.Clone() + config.ServerName = uri.Host + } + if len(c.ClientFingerprint) != 0 { if fingerprint, exists := tlsC.GetFingerprint(c.ClientFingerprint); exists { - utlsConn := tlsC.UClient(conn, c.TLSConfig, fingerprint) + utlsConn := tlsC.UClient(conn, config, fingerprint) if err = utlsConn.BuildWebsocketHandshakeState(); err != nil { return nil, fmt.Errorf("parse url %s error: %w", c.Path, err) } conn = utlsConn } } else { - conn = tls.Client(conn, c.TLSConfig) + conn = tls.Client(conn, config) } if tlsConn, ok := conn.(interface { @@ -348,13 +363,6 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, } } - uri := url.URL{ - Scheme: scheme, - Host: net.JoinHostPort(c.Host, c.Port), - Path: u.Path, - RawQuery: u.RawQuery, - } - request := &http.Request{ Method: http.MethodGet, URL: &uri, From 8c3557e96be1acbccd318584c48b587b59b3e7fb Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 13:58:53 +0800 Subject: [PATCH 529/530] chore: support v2ray http upgrade server too --- common/net/cached.go | 49 +++++++++++++++++++++ transport/vmess/websocket.go | 82 ++++++++++++++++++++++++------------ 2 files changed, 105 insertions(+), 26 deletions(-) create mode 100644 common/net/cached.go diff --git a/common/net/cached.go b/common/net/cached.go new file mode 100644 index 00000000..3b7da44c --- /dev/null +++ b/common/net/cached.go @@ -0,0 +1,49 @@ +package net + +import ( + "net" + + "github.com/Dreamacro/clash/common/buf" +) + +var _ ExtendedConn = (*CachedConn)(nil) + +type CachedConn struct { + ExtendedConn + data []byte +} + +func NewCachedConn(c net.Conn, data []byte) *CachedConn { + return &CachedConn{NewExtendedConn(c), data} +} + +func (c *CachedConn) Read(b []byte) (n int, err error) { + if len(c.data) > 0 { + n = copy(b, c.data) + c.data = c.data[n:] + return + } + return c.ExtendedConn.Read(b) +} + +func (c *CachedConn) ReadCached() *buf.Buffer { // call in sing/common/bufio.Copy + if len(c.data) > 0 { + return buf.As(c.data) + } + return nil +} + +func (c *CachedConn) Upstream() any { + return c.ExtendedConn +} + +func (c *CachedConn) ReaderReplaceable() bool { + if len(c.data) > 0 { + return false + } + return true +} + +func (c *CachedConn) WriterReplaceable() bool { + return true +} diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 0c2a3a16..9f09185b 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -1,6 +1,7 @@ package vmess import ( + "bufio" "bytes" "context" "crypto/sha1" @@ -382,7 +383,7 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, } request.Header.Del("Host") - var nonce string + var secKey string if !c.V2rayHttpUpgrade { const nonceKeySize = 16 // NOTE: bts does not escape. @@ -390,9 +391,9 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if _, err = fastrand.Read(bts); err != nil { return nil, fmt.Errorf("rand read error: %w", err) } - nonce = base64.StdEncoding.EncodeToString(bts) + secKey = base64.StdEncoding.EncodeToString(bts) request.Header.Set("Sec-WebSocket-Version", "13") - request.Header.Set("Sec-WebSocket-Key", nonce) + request.Header.Set("Sec-WebSocket-Key", secKey) } if earlyData != nil { @@ -434,14 +435,7 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, if lenSecAccept := len(secAccept); lenSecAccept != acceptSize { return nil, fmt.Errorf("unexpected Sec-Websocket-Accept length: %d", lenSecAccept) } - - const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" - const nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize) - p := make([]byte, nonceSize+len(magic)) - copy(p[:nonceSize], nonce) - copy(p[nonceSize:], magic) - sum := sha1.Sum(p) - if accept := base64.StdEncoding.EncodeToString(sum[:]); accept != secAccept { + if getSecAccept(secKey) != secAccept { return nil, errors.New("unexpected Sec-Websocket-Accept") } } @@ -452,6 +446,16 @@ func streamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig, return N.NewDeadlineConn(conn), nil } +func getSecAccept(secKey string) string { + const magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" + const nonceSize = 24 // base64.StdEncoding.EncodedLen(nonceKeySize) + p := make([]byte, nonceSize+len(magic)) + copy(p[:nonceSize], secKey) + copy(p[nonceSize:], magic) + sum := sha1.Sum(p) + return base64.StdEncoding.EncodeToString(sum[:]) +} + func StreamWebsocketConn(ctx context.Context, conn net.Conn, c *WebsocketConfig) (net.Conn, error) { if u, err := url.Parse(c.Path); err == nil { if q := u.Query(); q.Get("ed") != "" { @@ -505,27 +509,53 @@ func decodeXray0rtt(requestHeader http.Header) []byte { return nil } +func IsWebSocketUpgrade(r *http.Request) bool { + return r.Header.Get("Upgrade") == "websocket" +} + +func IsV2rayHttpUpdate(r *http.Request) bool { + return IsWebSocketUpgrade(r) && r.Header.Get("Sec-WebSocket-Key") == "" +} + func StreamUpgradedWebsocketConn(w http.ResponseWriter, r *http.Request) (net.Conn, error) { - wsConn, rw, _, err := ws.UpgradeHTTP(r, w) + var conn net.Conn + var rw *bufio.ReadWriter + var err error + isRaw := IsV2rayHttpUpdate(r) + w.Header().Set("Connection", "upgrade") + w.Header().Set("Upgrade", "websocket") + if !isRaw { + w.Header().Set("Sec-Websocket-Accept", getSecAccept(r.Header.Get("Sec-WebSocket-Key"))) + } + w.WriteHeader(http.StatusSwitchingProtocols) + if flusher, isFlusher := w.(interface{ FlushError() error }); isFlusher { + err = flusher.FlushError() + if err != nil { + return nil, fmt.Errorf("flush response: %w", err) + } + } + hijacker, canHijack := w.(http.Hijacker) + if !canHijack { + return nil, errors.New("invalid connection, maybe HTTP/2") + } + conn, rw, err = hijacker.Hijack() if err != nil { - return nil, err + return nil, fmt.Errorf("hijack failed: %w", err) } - // gobwas/ws will flush rw.Writer, so we only need warp rw.Reader - wsConn = N.WarpConnWithBioReader(wsConn, rw.Reader) + // rw.Writer was flushed, so we only need warp rw.Reader + conn = N.WarpConnWithBioReader(conn, rw.Reader) + + if !isRaw { + conn = newWebsocketConn(conn, ws.StateServerSide) + // websocketConn can't correct handle ReadDeadline + // so call N.NewDeadlineConn to add a safe wrapper + conn = N.NewDeadlineConn(conn) + } - conn := newWebsocketConn(wsConn, ws.StateServerSide) if edBuf := decodeXray0rtt(r.Header); len(edBuf) > 0 { - return N.NewDeadlineConn(&websocketWithReaderConn{conn, io.MultiReader(bytes.NewReader(edBuf), conn)}), nil + conn = N.NewCachedConn(conn, edBuf) } - return N.NewDeadlineConn(conn), nil -} -type websocketWithReaderConn struct { - *websocketConn - reader io.Reader -} - -func (ws *websocketWithReaderConn) Read(b []byte) (n int, err error) { - return ws.reader.Read(b) + return conn, nil } From 17c9d507be0fec41ff2c4d7b1bb3019c82e091fc Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Fri, 3 Nov 2023 21:01:45 +0800 Subject: [PATCH 530/530] chore: hello mihomo --- .github/ISSUE_TEMPLATE/bug_report.yml | 24 ++-- .github/ISSUE_TEMPLATE/config.yml | 6 +- .github/ISSUE_TEMPLATE/feature_request.yml | 2 +- .github/rename-cgo.sh | 26 ++--- .../workflows/android-branch-auto-sync.yml | 6 +- .github/workflows/build.yml | 8 +- .golangci.yaml | 2 +- Dockerfile | 26 ++--- Makefile | 6 +- README.md | 28 ++--- adapter/adapter.go | 12 +- adapter/inbound/addition.go | 2 +- adapter/inbound/auth.go | 2 +- adapter/inbound/http.go | 4 +- adapter/inbound/https.go | 2 +- adapter/inbound/packet.go | 4 +- adapter/inbound/socket.go | 4 +- adapter/inbound/util.go | 6 +- adapter/outbound/base.go | 8 +- adapter/outbound/direct.go | 8 +- adapter/outbound/http.go | 10 +- adapter/outbound/hysteria.go | 22 ++-- adapter/outbound/hysteria2.go | 12 +- adapter/outbound/reality.go | 2 +- adapter/outbound/reject.go | 6 +- adapter/outbound/shadowsocks.go | 20 ++-- adapter/outbound/shadowsocksr.go | 22 ++-- adapter/outbound/singmux.go | 10 +- adapter/outbound/snell.go | 14 +-- adapter/outbound/socks5.go | 12 +- adapter/outbound/trojan.go | 16 +-- adapter/outbound/tuic.go | 12 +- adapter/outbound/util.go | 6 +- adapter/outbound/vless.go | 28 ++--- adapter/outbound/vmess.go | 46 ++++---- adapter/outbound/wireguard.go | 14 +-- adapter/outboundgroup/fallback.go | 14 +-- adapter/outboundgroup/groupbase.go | 16 +-- adapter/outboundgroup/loadbalance.go | 16 +-- adapter/outboundgroup/parser.go | 12 +- adapter/outboundgroup/relay.go | 10 +- adapter/outboundgroup/selector.go | 8 +- adapter/outboundgroup/urltest.go | 14 +-- adapter/parser.go | 8 +- adapter/provider/healthcheck.go | 12 +- adapter/provider/parser.go | 10 +- adapter/provider/provider.go | 24 ++-- common/cache/lrucache.go | 2 +- common/callback/callback.go | 6 +- common/convert/converter.go | 4 +- common/convert/util.go | 2 +- common/net/bufconn.go | 2 +- common/net/cached.go | 2 +- common/net/deadline/packet.go | 4 +- common/net/deadline/packet_enhance.go | 2 +- common/net/deadline/packet_sing.go | 2 +- common/net/packet.go | 4 +- common/net/packet/packet.go | 2 +- common/net/packet/packet_posix.go | 2 +- common/net/refconn.go | 2 +- common/net/relay.go | 2 +- common/observable/observable_test.go | 2 +- common/singledo/singledo_test.go | 2 +- component/dhcp/conn.go | 2 +- component/dhcp/dhcp.go | 4 +- component/dialer/bind.go | 2 +- component/dialer/bind_darwin.go | 2 +- component/dialer/bind_windows.go | 2 +- component/dialer/dialer.go | 2 +- component/dialer/mark_nonlinux.go | 2 +- component/dialer/options.go | 4 +- component/ebpf/bpf/redir.c | 10 +- component/ebpf/bpf/tc.c | 10 +- component/ebpf/ebpf.go | 4 +- component/ebpf/ebpf_linux.go | 12 +- component/ebpf/redir/auto_redirect.go | 10 +- component/ebpf/tc/redirect_to_tun.go | 6 +- component/fakeip/cachefile.go | 2 +- component/fakeip/memory.go | 2 +- component/fakeip/pool.go | 6 +- component/fakeip/pool_test.go | 6 +- component/geodata/attr.go | 2 +- component/geodata/geodata.go | 4 +- component/geodata/geodataproto.go | 2 +- component/geodata/init.go | 12 +- component/geodata/memconservative/cache.go | 6 +- component/geodata/memconservative/memc.go | 4 +- component/geodata/router/condition.go | 2 +- component/geodata/router/config.pb.go | 30 ++--- component/geodata/router/config.proto | 8 +- component/geodata/standard/standard.go | 6 +- .../strmatcher/ac_automaton_matcher.go | 2 +- component/geodata/utils.go | 6 +- component/http/http.go | 6 +- component/iface/iface.go | 2 +- component/mmdb/mmdb.go | 8 +- component/nat/proxy.go | 4 +- component/nat/table.go | 2 +- component/process/process_freebsd_amd64.go | 4 +- component/process/process_windows.go | 4 +- component/profile/cachefile/cache.go | 6 +- component/profile/profile.go | 2 +- component/proxydialer/proxydialer.go | 12 +- component/proxydialer/sing.go | 2 +- component/resolver/host.go | 4 +- component/resolver/resolver.go | 4 +- component/resource/fetcher.go | 4 +- component/resource/vehicle.go | 6 +- component/sniffer/base_sniffer.go | 6 +- component/sniffer/dispatcher.go | 12 +- component/sniffer/http_sniffer.go | 6 +- component/sniffer/quic_sniffer.go | 6 +- component/sniffer/tls_sniffer.go | 6 +- component/tls/reality.go | 6 +- component/tls/utls.go | 2 +- component/trie/domain_set.go | 2 +- component/trie/domain_set_test.go | 2 +- component/trie/domain_test.go | 2 +- component/trie/ipcidr_trie.go | 2 +- config/config.go | 58 +++++----- config/initial.go | 4 +- config/update_geo.go | 6 +- config/update_ui.go | 2 +- config/utils.go | 8 +- constant/adapters.go | 6 +- constant/context.go | 2 +- constant/ebpf.go | 8 +- constant/metadata.go | 4 +- constant/path.go | 8 +- constant/provider/interface.go | 4 +- constant/rule_extra.go | 2 +- constant/sniffer/sniffer.go | 2 +- constant/version.go | 8 +- context/conn.go | 6 +- context/dns.go | 2 +- context/packetconn.go | 4 +- dns/client.go | 8 +- dns/dhcp.go | 4 +- dns/doh.go | 6 +- dns/doq.go | 6 +- dns/enhancer.go | 6 +- dns/filters.go | 12 +- dns/middleware.go | 14 +-- dns/resolver.go | 16 +-- dns/server.go | 6 +- dns/system.go | 2 +- dns/util.go | 18 +-- docker/file-name.sh | 2 +- docs/config.yaml | 16 +-- flake.nix | 14 +-- go.mod | 2 +- hub/executor/executor.go | 52 ++++----- hub/hub.go | 10 +- hub/route/cache.go | 2 +- hub/route/configs.go | 22 ++-- hub/route/connections.go | 2 +- hub/route/ctxkeys.go | 2 +- hub/route/dns.go | 2 +- hub/route/groups.go | 10 +- hub/route/provider.go | 6 +- hub/route/proxies.go | 12 +- hub/route/restart.go | 4 +- hub/route/rules.go | 4 +- hub/route/server.go | 14 +-- hub/route/upgrade.go | 6 +- hub/updater/updater.go | 20 ++-- listener/auth/auth.go | 2 +- listener/autoredir/tcp.go | 10 +- listener/config/tun.go | 2 +- listener/http/client.go | 6 +- listener/http/proxy.go | 12 +- listener/http/server.go | 6 +- listener/http/upgrade.go | 8 +- listener/inbound/base.go | 4 +- listener/inbound/http.go | 6 +- listener/inbound/hysteria2.go | 8 +- listener/inbound/mixed.go | 8 +- listener/inbound/redir.go | 6 +- listener/inbound/shadowsocks.go | 8 +- listener/inbound/socks.go | 6 +- listener/inbound/tproxy.go | 6 +- listener/inbound/tuic.go | 8 +- listener/inbound/tun.go | 8 +- listener/inbound/tunnel.go | 6 +- listener/inbound/vmess.go | 8 +- listener/inner/tcp.go | 4 +- listener/listener.go | 32 +++--- listener/mixed/mixed.go | 16 +-- listener/parse.go | 6 +- listener/redir/tcp.go | 6 +- listener/redir/tcp_darwin.go | 2 +- listener/redir/tcp_freebsd.go | 2 +- listener/redir/tcp_linux.go | 2 +- listener/redir/tcp_other.go | 2 +- listener/shadowsocks/tcp.go | 12 +- listener/shadowsocks/udp.go | 14 +-- listener/shadowsocks/utils.go | 2 +- listener/sing/context.go | 2 +- listener/sing/sing.go | 8 +- listener/sing_hysteria2/server.go | 16 +-- listener/sing_shadowsocks/server.go | 18 +-- listener/sing_tun/dns.go | 8 +- listener/sing_tun/server.go | 14 +-- listener/sing_tun/server_android.go | 2 +- listener/sing_tun/server_windows.go | 2 +- listener/sing_vmess/server.go | 16 +-- listener/socks/tcp.go | 12 +- listener/socks/udp.go | 12 +- listener/socks/utils.go | 2 +- listener/tproxy/packet.go | 8 +- listener/tproxy/tproxy.go | 8 +- listener/tproxy/tproxy_iptables.go | 104 +++++++++--------- listener/tproxy/udp.go | 8 +- listener/tuic/server.go | 18 +-- listener/tunnel/packet.go | 2 +- listener/tunnel/tcp.go | 8 +- listener/tunnel/udp.go | 8 +- log/log.go | 2 +- main.go | 16 +-- ntp/service.go | 6 +- rules/common/domain.go | 2 +- rules/common/domain_keyword.go | 2 +- rules/common/domain_suffix.go | 2 +- rules/common/final.go | 2 +- rules/common/geoip.go | 12 +- rules/common/geosite.go | 12 +- rules/common/in_name.go | 2 +- rules/common/in_type.go | 2 +- rules/common/in_user.go | 2 +- rules/common/ipcidr.go | 2 +- rules/common/ipsuffix.go | 2 +- rules/common/network_type.go | 2 +- rules/common/port.go | 4 +- rules/common/process.go | 2 +- rules/common/uid.go | 6 +- rules/logic/logic.go | 6 +- rules/logic_test/logic_test.go | 6 +- rules/parser.go | 8 +- rules/provider/classical_strategy.go | 4 +- rules/provider/domain_strategy.go | 6 +- rules/provider/ipcidr_strategy.go | 6 +- rules/provider/parse.go | 8 +- rules/provider/provider.go | 8 +- rules/provider/rule_set.go | 6 +- test/.golangci.yaml | 2 +- test/README.md | 6 +- test/clash_test.go | 10 +- test/dns_test.go | 8 +- test/go.mod | 22 ++-- test/go.sum | 99 +++++++---------- test/hysteria_test.go | 6 +- test/snell_test.go | 12 +- test/ss_test.go | 28 ++--- test/trojan_test.go | 12 +- test/vless_test.go | 11 +- test/vmess_test.go | 26 ++--- transport/gun/gun.go | 8 +- transport/hysteria/conns/faketcp/obfs.go | 2 +- transport/hysteria/conns/faketcp/tcp_linux.go | 2 +- transport/hysteria/conns/udp/hop.go | 4 +- transport/hysteria/conns/udp/obfs.go | 2 +- transport/hysteria/conns/wechat/obfs.go | 4 +- transport/hysteria/core/client.go | 8 +- transport/hysteria/transport/client.go | 10 +- transport/shadowsocks/core/cipher.go | 6 +- transport/shadowsocks/shadowaead/packet.go | 4 +- transport/shadowsocks/shadowaead/stream.go | 2 +- transport/shadowsocks/shadowstream/packet.go | 4 +- transport/shadowtls/shadowtls.go | 4 +- transport/simple-obfs/http.go | 2 +- transport/simple-obfs/tls.go | 2 +- transport/sing-shadowtls/shadowtls.go | 6 +- transport/snell/cipher.go | 2 +- transport/snell/pool.go | 6 +- transport/snell/snell.go | 6 +- transport/socks4/socks4.go | 2 +- transport/socks5/socks5.go | 2 +- transport/ssr/obfs/http_simple.go | 2 +- transport/ssr/obfs/random_head.go | 2 +- transport/ssr/obfs/tls1.2_ticket_auth.go | 4 +- transport/ssr/protocol/auth_aes128_md5.go | 2 +- transport/ssr/protocol/auth_aes128_sha1.go | 8 +- transport/ssr/protocol/auth_chain_a.go | 14 +-- transport/ssr/protocol/auth_chain_b.go | 2 +- transport/ssr/protocol/auth_sha1_v4.go | 6 +- transport/ssr/protocol/base.go | 6 +- transport/ssr/protocol/origin.go | 2 +- transport/ssr/protocol/packet.go | 4 +- transport/ssr/protocol/protocol.go | 2 +- transport/ssr/protocol/stream.go | 2 +- transport/ssr/tools/random.go | 2 +- transport/trojan/trojan.go | 14 +-- transport/tuic/common/congestion.go | 4 +- transport/tuic/common/type.go | 4 +- transport/tuic/pool_client.go | 8 +- transport/tuic/server.go | 16 +-- transport/tuic/tuic.go | 8 +- transport/tuic/v4/client.go | 14 +-- transport/tuic/v4/packet.go | 8 +- transport/tuic/v4/protocol.go | 4 +- transport/tuic/v4/server.go | 14 +-- transport/tuic/v5/client.go | 12 +- transport/tuic/v5/frag.go | 2 +- transport/tuic/v5/packet.go | 8 +- transport/tuic/v5/protocol.go | 6 +- transport/tuic/v5/server.go | 12 +- transport/v2ray-plugin/websocket.go | 4 +- transport/vless/config.pb.go | 2 +- transport/vless/config.proto | 8 +- transport/vless/conn.go | 6 +- transport/vless/vision/conn.go | 6 +- transport/vless/vision/filter.go | 2 +- transport/vless/vision/padding.go | 4 +- transport/vless/vision/vision.go | 4 +- transport/vless/vless.go | 2 +- transport/vmess/aead.go | 2 +- transport/vmess/chunk.go | 2 +- transport/vmess/http.go | 2 +- transport/vmess/tls.go | 4 +- transport/vmess/vmess.go | 2 +- transport/vmess/websocket.go | 8 +- tunnel/connection.go | 6 +- tunnel/statistic/manager.go | 2 +- tunnel/statistic/tracker.go | 10 +- tunnel/tunnel.go | 20 ++-- 325 files changed, 1297 insertions(+), 1315 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index bd44d025..d68bd252 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -13,8 +13,8 @@ Please verify that you've followed these steps " options: - label: " -确保你使用的是**本仓库**最新的的 clash 或 clash Alpha 版本 -Ensure you are using the latest version of Clash or Clash Premium from **this repository**. +确保你使用的是**本仓库**最新的的 mihomo 或 mihomo Alpha 版本 +Ensure you are using the latest version of Mihomo or Mihomo Alpha from **this repository**. " required: true - label: " @@ -38,14 +38,14 @@ I have read the [documentation](https://wiki.metacubex.one/) and was unable to s " required: true - label: " -这是 Clash 核心的问题,并非我所使用的 Clash 衍生版本(如 OpenClash、KoolClash 等)的特定问题 -This is an issue of the Clash core *per se*, not to the derivatives of Clash, like OpenClash or KoolClash. +这是 Mihomo 核心的问题,并非我所使用的 Mihomo 衍生版本(如 OpenMihomo、KoolMihomo 等)的特定问题 +This is an issue of the Mihomo core *per se*, not to the derivatives of Mihomo, like OpenMihomo or KoolMihomo. " required: true - type: input attributes: - label: Clash version - description: "use `clash -v`" + label: Mihomo version + description: "use `mihomo -v`" validations: required: true - type: dropdown @@ -61,20 +61,20 @@ This is an issue of the Clash core *per se*, not to the derivatives of Clash, li - type: textarea attributes: render: yaml - label: "Clash config" + label: "Mihomo config" description: " -在下方附上 Clash core 配置文件,请确保配置文件中没有敏感信息(比如:服务器地址,密码,端口等) -Paste the Clash core configuration file below, please make sure that there is no sensitive information in the configuration file (e.g., server address/url, password, port) +在下方附上 Mihomo core 配置文件,请确保配置文件中没有敏感信息(比如:服务器地址,密码,端口等) +Paste the Mihomo core configuration file below, please make sure that there is no sensitive information in the configuration file (e.g., server address/url, password, port) " validations: required: true - type: textarea attributes: render: shell - label: Clash log + label: Mihomo log description: " -在下方附上 Clash Core 的日志,log level 使用 DEBUG -Paste the Clash core log below with the log level set to `DEBUG`. +在下方附上 Mihomo Core 的日志,log level 使用 DEBUG +Paste the Mihomo core log below with the log level set to `DEBUG`. " - type: textarea attributes: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0cf54628..75d37b63 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Clash.Meta Community Support - url: https://github.com/MetaCubeX/Clash.Meta/discussions - about: Please ask and answer questions about Clash.Meta here. + - name: mihomo Community Support + url: https://github.com/MetaCubeX/mihomo/discussions + about: Please ask and answer questions about mihomo here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index a32d313d..7987526c 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -25,7 +25,7 @@ I have read the [documentation](https://wiki.metacubex.one/) and was unable to s - type: textarea attributes: label: Description - description: 请详细、清晰地表达你要提出的论述,例如这个问题如何影响到你?你想实现什么功能?目前 Clash Core 的行为是什麽? + description: 请详细、清晰地表达你要提出的论述,例如这个问题如何影响到你?你想实现什么功能?目前 Mihomo Core 的行为是什麽? validations: required: true - type: textarea diff --git a/.github/rename-cgo.sh b/.github/rename-cgo.sh index a0d736de..2bfdb3c6 100644 --- a/.github/rename-cgo.sh +++ b/.github/rename-cgo.sh @@ -5,25 +5,25 @@ for FILENAME in $FILENAMES do if [[ $FILENAME =~ "darwin-10.16-arm64" ]];then echo "rename darwin-10.16-arm64 $FILENAME" - mv $FILENAME clash.meta-darwin-arm64-cgo + mv $FILENAME mihomo-darwin-arm64-cgo elif [[ $FILENAME =~ "darwin-10.16-amd64" ]];then echo "rename darwin-10.16-amd64 $FILENAME" - mv $FILENAME clash.meta-darwin-amd64-cgo + mv $FILENAME mihomo-darwin-amd64-cgo elif [[ $FILENAME =~ "windows-4.0-386" ]];then echo "rename windows 386 $FILENAME" - mv $FILENAME clash.meta-windows-386-cgo.exe + mv $FILENAME mihomo-windows-386-cgo.exe elif [[ $FILENAME =~ "windows-4.0-amd64" ]];then echo "rename windows amd64 $FILENAME" - mv $FILENAME clash.meta-windows-amd64-cgo.exe - elif [[ $FILENAME =~ "clash.meta-linux-arm-5" ]];then - echo "rename clash.meta-linux-arm-5 $FILENAME" - mv $FILENAME clash.meta-linux-armv5-cgo - elif [[ $FILENAME =~ "clash.meta-linux-arm-6" ]];then - echo "rename clash.meta-linux-arm-6 $FILENAME" - mv $FILENAME clash.meta-linux-armv6-cgo - elif [[ $FILENAME =~ "clash.meta-linux-arm-7" ]];then - echo "rename clash.meta-linux-arm-7 $FILENAME" - mv $FILENAME clash.meta-linux-armv7-cgo + mv $FILENAME mihomo-windows-amd64-cgo.exe + elif [[ $FILENAME =~ "mihomo-linux-arm-5" ]];then + echo "rename mihomo-linux-arm-5 $FILENAME" + mv $FILENAME mihomo-linux-armv5-cgo + elif [[ $FILENAME =~ "mihomo-linux-arm-6" ]];then + echo "rename mihomo-linux-arm-6 $FILENAME" + mv $FILENAME mihomo-linux-armv6-cgo + elif [[ $FILENAME =~ "mihomo-linux-arm-7" ]];then + echo "rename mihomo-linux-arm-7 $FILENAME" + mv $FILENAME mihomo-linux-armv7-cgo elif [[ $FILENAME =~ "linux" ]];then echo "rename linux $FILENAME" mv $FILENAME $FILENAME-cgo diff --git a/.github/workflows/android-branch-auto-sync.yml b/.github/workflows/android-branch-auto-sync.yml index c7ee5eba..fd7c9d66 100644 --- a/.github/workflows/android-branch-auto-sync.yml +++ b/.github/workflows/android-branch-auto-sync.yml @@ -50,8 +50,8 @@ jobs: run: | git push origin android-real --force - # Send "core-updated" to MetaCubeX/ClashMetaForAndroid to trigger update-dependencies - trigger-CMFA-update: + # Send "core-updated" to MetaCubeX/MihomoForAndroid to trigger update-dependencies + trigger-MFA-update: needs: update-dependencies runs-on: ubuntu-latest steps: @@ -63,7 +63,7 @@ jobs: - name: Trigger update-dependencies run: | - curl -X POST https://api.github.com/repos/MetaCubeX/ClashMetaForAndroid/dispatches \ + curl -X POST https://api.github.com/repos/MetaCubeX/MihomoForAndroid/dispatches \ -H "Accept: application/vnd.github.everest-preview+json" \ -H "Authorization: token ${{ steps.generate-token.outputs.token }}" \ -d '{"event_type": "core-updated"}' \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 57a00f3e..a644f97a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -118,7 +118,7 @@ jobs: - name: Set ENV run: | sudo timedatectl set-timezone "Asia/Shanghai" - echo "NAME=clash.meta" >> $GITHUB_ENV + echo "NAME=mihomo" >> $GITHUB_ENV echo "REPO=${{ github.repository }}" >> $GITHUB_ENV echo "ShortSHA=$(git rev-parse --short ${{ github.sha }})" >> $GITHUB_ENV echo "BUILDTIME=$(date)" >> $GITHUB_ENV @@ -128,7 +128,7 @@ jobs: - name: Set ENV run: | echo "TAGS=with_gvisor,with_lwip" >> $GITHUB_ENV - echo "LDFLAGS=-X 'github.com/Dreamacro/clash/constant.Version=${VERSION}' -X 'github.com/Dreamacro/clash/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" >> $GITHUB_ENV + echo "LDFLAGS=-X 'github.com/metacubex/mihomo/constant.Version=${VERSION}' -X 'github.com/metacubex/mihomo/constant.BuildTime=${BUILDTIME}' -w -s -buildid=" >> $GITHUB_ENV shell: bash - name: Setup Go @@ -153,7 +153,7 @@ jobs: - name: Build WithoutCGO if: ${{ matrix.job.type!='WithCGO' }} env: - NAME: Clash.Meta + NAME: mihomo BINDIR: bin run: make -j$(($(nproc) + 1)) ${{ matrix.job.target }} @@ -271,7 +271,7 @@ jobs: Release created at ${{ env.BUILDTIME }} Synchronize ${{ github.ref_name }} branch code updates, keeping only the latest version
- [我应该下载哪个文件? / Which file should I download?](https://github.com/MetaCubeX/Clash.Meta/wiki/FAQ) + [我应该下载哪个文件? / Which file should I download?](https://github.com/MetaCubeX/mihomo/wiki/FAQ) [查看文档 / Docs](https://metacubex.github.io/Meta-Docs/) EOF diff --git a/.golangci.yaml b/.golangci.yaml index f5b67397..1de71ad8 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -11,7 +11,7 @@ linters-settings: custom-order: true sections: - standard - - prefix(github.com/Dreamacro/clash) + - prefix(github.com/metacubex/mihomo) - default staticcheck: go: '1.19' diff --git a/Dockerfile b/Dockerfile index 6c5a91f9..c9cd56b7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,25 +3,25 @@ ARG TARGETPLATFORM RUN echo "I'm building for $TARGETPLATFORM" RUN apk add --no-cache gzip && \ - mkdir /clash-config && \ - 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 + mkdir /mihomo-config && \ + wget -O /mihomo-config/geoip.metadb https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geoip.metadb && \ + wget -O /mihomo-config/geosite.dat https://fastly.jsdelivr.net/gh/MetaCubeX/meta-rules-dat@release/geosite.dat && \ + wget -O /mihomo-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 +COPY docker/file-name.sh /mihomo/file-name.sh +WORKDIR /mihomo COPY bin/ bin/ RUN FILE_NAME=`sh file-name.sh` && echo $FILE_NAME && \ FILE_NAME=`ls bin/ | egrep "$FILE_NAME.*"|awk NR==1` && echo $FILE_NAME && \ - mv bin/$FILE_NAME clash.gz && gzip -d clash.gz && echo "$FILE_NAME" > /clash-config/test + mv bin/$FILE_NAME mihomo.gz && gzip -d mihomo.gz && echo "$FILE_NAME" > /mihomo-config/test FROM alpine:latest -LABEL org.opencontainers.image.source="https://github.com/MetaCubeX/Clash.Meta" +LABEL org.opencontainers.image.source="https://github.com/MetaCubeX/mihomo" RUN apk add --no-cache ca-certificates tzdata iptables -VOLUME ["/root/.config/clash/"] +VOLUME ["/root/.config/mihomo/"] -COPY --from=builder /clash-config/ /root/.config/clash/ -COPY --from=builder /clash/clash /clash -RUN chmod +x /clash -ENTRYPOINT [ "/clash" ] +COPY --from=builder /mihomo-config/ /root/.config/mihomo/ +COPY --from=builder /mihomo/mihomo /mihomo +RUN chmod +x /mihomo +ENTRYPOINT [ "/mihomo" ] diff --git a/Makefile b/Makefile index 028b986c..f6ffcae5 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -NAME=clash.meta +NAME=mihomo BINDIR=bin BRANCH=$(shell git branch --show-current) ifeq ($(BRANCH),Alpha) @@ -12,8 +12,8 @@ VERSION=$(shell git rev-parse --short HEAD) endif BUILDTIME=$(shell date -u) -GOBUILD=CGO_ENABLED=0 go build -tags with_gvisor -trimpath -ldflags '-X "github.com/Dreamacro/clash/constant.Version=$(VERSION)" \ - -X "github.com/Dreamacro/clash/constant.BuildTime=$(BUILDTIME)" \ +GOBUILD=CGO_ENABLED=0 go build -tags with_gvisor -trimpath -ldflags '-X "github.com/metacubex/mihomo/constant.Version=$(VERSION)" \ + -X "github.com/metacubex/mihomo/constant.BuildTime=$(BUILDTIME)" \ -w -s -buildid=' PLATFORM_LIST = \ diff --git a/README.md b/README.md index d5022dfb..8c82536c 100644 --- a/README.md +++ b/README.md @@ -3,17 +3,17 @@
Meta Kernel
-

Another Clash Kernel.

+

Another Mihomo Kernel.

- - + + - - - + + + - +

@@ -27,7 +27,7 @@ - Remote groups allow users to implement powerful rules. Supports automatic fallback, load balancing or auto select node based off latency - Remote providers, allowing users to get node lists remotely instead of hard-coding in config -- Netfilter TCP redirecting. Deploy Clash on your Internet gateway with `iptables`. +- Netfilter TCP redirecting. Deploy Mihomo on your Internet gateway with `iptables`. - Comprehensive HTTP RESTful API controller ## Dashboard @@ -36,22 +36,22 @@ A web dashboard with first-class support for this project has been created; it c ## Configration example -Configuration example is located at [/docs/config.yaml](https://github.com/MetaCubeX/Clash.Meta/blob/Alpha/docs/config.yaml). +Configuration example is located at [/docs/config.yaml](https://github.com/MetaCubeX/mihomo/blob/Alpha/docs/config.yaml). ## Docs -Documentation can be found in [Clash.Meta Docs](https://clash-meta.wiki). +Documentation can be found in [mihomo Docs](https://wiki.metacubex.one/). ## For development Requirements: [Go 1.20 or newer](https://go.dev/dl/) -Build Clash.Meta: +Build mihomo: ```shell -git clone https://github.com/MetaCubeX/Clash.Meta.git -cd Clash.Meta && go mod download +git clone https://github.com/MetaCubeX/mihomo.git +cd mihomo && go mod download go build ``` @@ -98,4 +98,4 @@ API. This software is released under the GPL-3.0 license. -[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FDreamacro%2Fclash.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FDreamacro%2Fclash?ref=badge_large) +[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2FMetaCubeX%2Fmihomo.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2FMetaCubeX%2Fmihomo?ref=badge_large) diff --git a/adapter/adapter.go b/adapter/adapter.go index 62941e6d..74b11bd9 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -12,12 +12,12 @@ import ( "strconv" "time" - "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" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/queue" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/puzpuzpuz/xsync/v2" ) diff --git a/adapter/inbound/addition.go b/adapter/inbound/addition.go index df03b84a..a9896c8c 100644 --- a/adapter/inbound/addition.go +++ b/adapter/inbound/addition.go @@ -3,7 +3,7 @@ package inbound import ( "net" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type Addition func(metadata *C.Metadata) diff --git a/adapter/inbound/auth.go b/adapter/inbound/auth.go index 4022659f..984c9bd6 100644 --- a/adapter/inbound/auth.go +++ b/adapter/inbound/auth.go @@ -4,7 +4,7 @@ import ( "net" "net/netip" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) var skipAuthPrefixes []netip.Prefix diff --git a/adapter/inbound/http.go b/adapter/inbound/http.go index 7f3b143f..137e17d3 100644 --- a/adapter/inbound/http.go +++ b/adapter/inbound/http.go @@ -3,8 +3,8 @@ package inbound import ( "net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) // NewHTTP receive normal http request and return HTTPContext diff --git a/adapter/inbound/https.go b/adapter/inbound/https.go index 891ac9e7..55f6731a 100644 --- a/adapter/inbound/https.go +++ b/adapter/inbound/https.go @@ -4,7 +4,7 @@ import ( "net" "net/http" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) // NewHTTPS receive CONNECT request and return ConnContext diff --git a/adapter/inbound/packet.go b/adapter/inbound/packet.go index 0e3f6c48..7e245f98 100644 --- a/adapter/inbound/packet.go +++ b/adapter/inbound/packet.go @@ -1,8 +1,8 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) // NewPacket is PacketAdapter generator diff --git a/adapter/inbound/socket.go b/adapter/inbound/socket.go index 21cb490b..8cd301f7 100644 --- a/adapter/inbound/socket.go +++ b/adapter/inbound/socket.go @@ -3,8 +3,8 @@ package inbound import ( "net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) // NewSocket receive TCP inbound and return ConnContext diff --git a/adapter/inbound/util.go b/adapter/inbound/util.go index acae7c3e..743337fc 100644 --- a/adapter/inbound/util.go +++ b/adapter/inbound/util.go @@ -7,9 +7,9 @@ import ( "strconv" "strings" - "github.com/Dreamacro/clash/common/nnip" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/common/nnip" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) func parseSocksAddr(target socks5.Addr) *C.Metadata { diff --git a/adapter/outbound/base.go b/adapter/outbound/base.go index ba991bfc..ae8c4651 100644 --- a/adapter/outbound/base.go +++ b/adapter/outbound/base.go @@ -7,10 +7,10 @@ import ( "strings" "syscall" - 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" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" ) type Base struct { diff --git a/adapter/outbound/direct.go b/adapter/outbound/direct.go index 75e999a6..b9b9fefc 100644 --- a/adapter/outbound/direct.go +++ b/adapter/outbound/direct.go @@ -5,10 +5,10 @@ import ( "errors" "net/netip" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" ) type Direct struct { diff --git a/adapter/outbound/http.go b/adapter/outbound/http.go index 19074bb3..b837e49a 100644 --- a/adapter/outbound/http.go +++ b/adapter/outbound/http.go @@ -13,11 +13,11 @@ import ( "net/http" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" ) type Http struct { diff --git a/adapter/outbound/hysteria.go b/adapter/outbound/hysteria.go index 5a41274c..dacffd10 100644 --- a/adapter/outbound/hysteria.go +++ b/adapter/outbound/hysteria.go @@ -14,17 +14,17 @@ import ( "github.com/metacubex/quic-go/congestion" M "github.com/sagernet/sing/common/metadata" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - hyCongestion "github.com/Dreamacro/clash/transport/hysteria/congestion" - "github.com/Dreamacro/clash/transport/hysteria/core" - "github.com/Dreamacro/clash/transport/hysteria/obfs" - "github.com/Dreamacro/clash/transport/hysteria/pmtud_fix" - "github.com/Dreamacro/clash/transport/hysteria/transport" - "github.com/Dreamacro/clash/transport/hysteria/utils" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + hyCongestion "github.com/metacubex/mihomo/transport/hysteria/congestion" + "github.com/metacubex/mihomo/transport/hysteria/core" + "github.com/metacubex/mihomo/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/pmtud_fix" + "github.com/metacubex/mihomo/transport/hysteria/transport" + "github.com/metacubex/mihomo/transport/hysteria/utils" ) const ( diff --git a/adapter/outbound/hysteria2.go b/adapter/outbound/hysteria2.go index 6ed4cd8c..ddd5ccea 100644 --- a/adapter/outbound/hysteria2.go +++ b/adapter/outbound/hysteria2.go @@ -9,12 +9,12 @@ import ( "runtime" "strconv" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - tuicCommon "github.com/Dreamacro/clash/transport/tuic/common" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + tuicCommon "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/sing-quic/hysteria2" diff --git a/adapter/outbound/reality.go b/adapter/outbound/reality.go index 23314e5f..766138da 100644 --- a/adapter/outbound/reality.go +++ b/adapter/outbound/reality.go @@ -5,7 +5,7 @@ import ( "encoding/hex" "errors" - tlsC "github.com/Dreamacro/clash/component/tls" + tlsC "github.com/metacubex/mihomo/component/tls" "golang.org/x/crypto/curve25519" ) diff --git a/adapter/outbound/reject.go b/adapter/outbound/reject.go index f1de3981..5625f932 100644 --- a/adapter/outbound/reject.go +++ b/adapter/outbound/reject.go @@ -6,9 +6,9 @@ import ( "net" "time" - "github.com/Dreamacro/clash/common/buf" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/buf" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" ) type Reject struct { diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 1ae16c43..ffc72abb 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -7,16 +7,16 @@ import ( "net" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/structure" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/restls" - obfs "github.com/Dreamacro/clash/transport/simple-obfs" - shadowtls "github.com/Dreamacro/clash/transport/sing-shadowtls" - v2rayObfs "github.com/Dreamacro/clash/transport/v2ray-plugin" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/restls" + obfs "github.com/metacubex/mihomo/transport/simple-obfs" + shadowtls "github.com/metacubex/mihomo/transport/sing-shadowtls" + v2rayObfs "github.com/metacubex/mihomo/transport/v2ray-plugin" restlsC "github.com/3andne/restls-client-go" shadowsocks "github.com/metacubex/sing-shadowsocks2" diff --git a/adapter/outbound/shadowsocksr.go b/adapter/outbound/shadowsocksr.go index 0f03f86d..07d78047 100644 --- a/adapter/outbound/shadowsocksr.go +++ b/adapter/outbound/shadowsocksr.go @@ -7,16 +7,16 @@ import ( "net" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/ssr/obfs" - "github.com/Dreamacro/clash/transport/ssr/protocol" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/shadowsocks/core" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowstream" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/ssr/obfs" + "github.com/metacubex/mihomo/transport/ssr/protocol" ) type ShadowSocksR struct { @@ -125,7 +125,7 @@ func (ssr *ShadowSocksR) SupportWithDialer() C.NetWork { func NewShadowSocksR(option ShadowSocksROption) (*ShadowSocksR, error) { // SSR protocol compatibility - // https://github.com/Dreamacro/clash/pull/2056 + // https://github.com/metacubex/mihomo/pull/2056 if option.Cipher == "none" { option.Cipher = "dummy" } diff --git a/adapter/outbound/singmux.go b/adapter/outbound/singmux.go index fb6b1c29..dff1e8eb 100644 --- a/adapter/outbound/singmux.go +++ b/adapter/outbound/singmux.go @@ -5,11 +5,11 @@ import ( "errors" "runtime" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" mux "github.com/sagernet/sing-mux" E "github.com/sagernet/sing/common/exceptions" diff --git a/adapter/outbound/snell.go b/adapter/outbound/snell.go index 16405fcf..76ed4be9 100644 --- a/adapter/outbound/snell.go +++ b/adapter/outbound/snell.go @@ -6,13 +6,13 @@ import ( "net" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/structure" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - obfs "github.com/Dreamacro/clash/transport/simple-obfs" - "github.com/Dreamacro/clash/transport/snell" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + obfs "github.com/metacubex/mihomo/transport/simple-obfs" + "github.com/metacubex/mihomo/transport/snell" ) type Snell struct { diff --git a/adapter/outbound/socks5.go b/adapter/outbound/socks5.go index 43dfe8ef..c17ee6a7 100644 --- a/adapter/outbound/socks5.go +++ b/adapter/outbound/socks5.go @@ -10,12 +10,12 @@ import ( "net/netip" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type Socks5 struct { diff --git a/adapter/outbound/trojan.go b/adapter/outbound/trojan.go index d3c14e8a..cd1dd28c 100644 --- a/adapter/outbound/trojan.go +++ b/adapter/outbound/trojan.go @@ -8,14 +8,14 @@ import ( "net/http" "strconv" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/ca" - "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/gun" - "github.com/Dreamacro/clash/transport/trojan" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + tlsC "github.com/metacubex/mihomo/component/tls" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/gun" + "github.com/metacubex/mihomo/transport/trojan" ) type Trojan struct { diff --git a/adapter/outbound/tuic.go b/adapter/outbound/tuic.go index 93e49dc7..666e72fa 100644 --- a/adapter/outbound/tuic.go +++ b/adapter/outbound/tuic.go @@ -10,12 +10,12 @@ import ( "strconv" "time" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/tuic" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/tuic" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/adapter/outbound/util.go b/adapter/outbound/util.go index b048cd8b..ce9e5f65 100644 --- a/adapter/outbound/util.go +++ b/adapter/outbound/util.go @@ -11,9 +11,9 @@ import ( "strconv" "sync" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) var ( diff --git a/adapter/outbound/vless.go b/adapter/outbound/vless.go index 5f54153b..dbe8b1a4 100644 --- a/adapter/outbound/vless.go +++ b/adapter/outbound/vless.go @@ -12,20 +12,20 @@ import ( "strconv" "sync" - "github.com/Dreamacro/clash/common/convert" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/gun" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/vless" - "github.com/Dreamacro/clash/transport/vmess" + "github.com/metacubex/mihomo/common/convert" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + tlsC "github.com/metacubex/mihomo/component/tls" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/gun" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/vless" + "github.com/metacubex/mihomo/transport/vmess" vmessSing "github.com/metacubex/sing-vmess" "github.com/metacubex/sing-vmess/packetaddr" diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index aed61aa3..8811fb0d 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -11,17 +11,17 @@ import ( "strings" "sync" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/ntp" - "github.com/Dreamacro/clash/transport/gun" - clashVMess "github.com/Dreamacro/clash/transport/vmess" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + tlsC "github.com/metacubex/mihomo/component/tls" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/ntp" + "github.com/metacubex/mihomo/transport/gun" + mihomoVMess "github.com/metacubex/mihomo/transport/vmess" vmess "github.com/metacubex/sing-vmess" "github.com/metacubex/sing-vmess/packetaddr" @@ -105,7 +105,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M switch v.option.Network { case "ws": host, port, _ := net.SplitHostPort(v.addr) - wsOpts := &clashVMess.WebsocketConfig{ + wsOpts := &mihomoVMess.WebsocketConfig{ Host: host, Port: port, Path: v.option.WSOpts.Path, @@ -141,12 +141,12 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M wsOpts.TLSConfig.ServerName = host } } - c, err = clashVMess.StreamWebsocketConn(ctx, c, wsOpts) + c, err = mihomoVMess.StreamWebsocketConn(ctx, c, wsOpts) case "http": // readability first, so just copy default TLS logic if v.option.TLS { host, _, _ := net.SplitHostPort(v.addr) - tlsOpts := &clashVMess.TLSConfig{ + tlsOpts := &mihomoVMess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, ClientFingerprint: v.option.ClientFingerprint, @@ -157,24 +157,24 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M if v.option.ServerName != "" { tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts) + c, err = mihomoVMess.StreamTLSConn(ctx, c, tlsOpts) if err != nil { return nil, err } } host, _, _ := net.SplitHostPort(v.addr) - httpOpts := &clashVMess.HTTPConfig{ + httpOpts := &mihomoVMess.HTTPConfig{ Host: host, Method: v.option.HTTPOpts.Method, Path: v.option.HTTPOpts.Path, Headers: v.option.HTTPOpts.Headers, } - c = clashVMess.StreamHTTPConn(c, httpOpts) + c = mihomoVMess.StreamHTTPConn(c, httpOpts) case "h2": host, _, _ := net.SplitHostPort(v.addr) - tlsOpts := clashVMess.TLSConfig{ + tlsOpts := mihomoVMess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, NextProtos: []string{"h2"}, @@ -186,24 +186,24 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(ctx, c, &tlsOpts) + c, err = mihomoVMess.StreamTLSConn(ctx, c, &tlsOpts) if err != nil { return nil, err } - h2Opts := &clashVMess.H2Config{ + h2Opts := &mihomoVMess.H2Config{ Hosts: v.option.HTTP2Opts.Host, Path: v.option.HTTP2Opts.Path, } - c, err = clashVMess.StreamH2Conn(c, h2Opts) + c, err = mihomoVMess.StreamH2Conn(c, h2Opts) case "grpc": c, err = gun.StreamGunWithConn(c, v.gunTLSConfig, v.gunConfig, v.realityConfig) default: // handle TLS if v.option.TLS { host, _, _ := net.SplitHostPort(v.addr) - tlsOpts := &clashVMess.TLSConfig{ + tlsOpts := &mihomoVMess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, ClientFingerprint: v.option.ClientFingerprint, @@ -215,7 +215,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M tlsOpts.Host = v.option.ServerName } - c, err = clashVMess.StreamTLSConn(ctx, c, tlsOpts) + c, err = mihomoVMess.StreamTLSConn(ctx, c, tlsOpts) } } diff --git a/adapter/outbound/wireguard.go b/adapter/outbound/wireguard.go index 6a11a234..9af1751b 100644 --- a/adapter/outbound/wireguard.go +++ b/adapter/outbound/wireguard.go @@ -13,13 +13,13 @@ import ( "strings" "sync" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/dns" - "github.com/Dreamacro/clash/log" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/dns" + "github.com/metacubex/mihomo/log" wireguard "github.com/metacubex/sing-wireguard" diff --git a/adapter/outboundgroup/fallback.go b/adapter/outboundgroup/fallback.go index 899b9a9b..d0dd98b1 100644 --- a/adapter/outboundgroup/fallback.go +++ b/adapter/outboundgroup/fallback.go @@ -6,13 +6,13 @@ import ( "errors" "time" - "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" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/callback" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" ) type Fallback struct { diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index 22dd407b..d4a812f6 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -7,14 +7,14 @@ import ( "sync" "time" - "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" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + types "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel" "github.com/dlclark/regexp2" ) diff --git a/adapter/outboundgroup/loadbalance.go b/adapter/outboundgroup/loadbalance.go index e336c5f0..885aeaee 100644 --- a/adapter/outboundgroup/loadbalance.go +++ b/adapter/outboundgroup/loadbalance.go @@ -9,14 +9,14 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/common/cache" - "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" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/callback" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" "golang.org/x/net/publicsuffix" ) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index a8bdc557..8f3335d8 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -5,12 +5,12 @@ import ( "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" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/adapter/provider" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + types "github.com/metacubex/mihomo/constant/provider" ) var ( diff --git a/adapter/outboundgroup/relay.go b/adapter/outboundgroup/relay.go index ba733616..2b1be8a5 100644 --- a/adapter/outboundgroup/relay.go +++ b/adapter/outboundgroup/relay.go @@ -3,11 +3,11 @@ package outboundgroup import ( "context" "encoding/json" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" ) type Relay struct { diff --git a/adapter/outboundgroup/selector.go b/adapter/outboundgroup/selector.go index 96934f0c..4d06c544 100644 --- a/adapter/outboundgroup/selector.go +++ b/adapter/outboundgroup/selector.go @@ -5,10 +5,10 @@ import ( "encoding/json" "errors" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" ) type Selector struct { diff --git a/adapter/outboundgroup/urltest.go b/adapter/outboundgroup/urltest.go index 3f6c6ab0..8c861768 100644 --- a/adapter/outboundgroup/urltest.go +++ b/adapter/outboundgroup/urltest.go @@ -6,13 +6,13 @@ import ( "errors" "time" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/common/callback" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/singledo" - "github.com/Dreamacro/clash/component/dialer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/callback" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/singledo" + "github.com/metacubex/mihomo/component/dialer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" ) type urlTestOption func(*URLTest) diff --git a/adapter/parser.go b/adapter/parser.go index 43ebfe5f..1d363c1f 100644 --- a/adapter/parser.go +++ b/adapter/parser.go @@ -3,11 +3,11 @@ package adapter import ( "fmt" - tlsC "github.com/Dreamacro/clash/component/tls" + tlsC "github.com/metacubex/mihomo/component/tls" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/common/structure" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/common/structure" + C "github.com/metacubex/mihomo/constant" ) func ParseProxy(mapping map[string]any) (C.Proxy, error) { diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index feb972ab..e7f021e1 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -6,12 +6,12 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/batch" - "github.com/Dreamacro/clash/common/singledo" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/batch" + "github.com/metacubex/mihomo/common/singledo" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/dlclark/regexp2" ) diff --git a/adapter/provider/parser.go b/adapter/provider/parser.go index d885a546..321380ed 100644 --- a/adapter/provider/parser.go +++ b/adapter/provider/parser.go @@ -5,11 +5,11 @@ import ( "fmt" "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" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/resource" + C "github.com/metacubex/mihomo/constant" + types "github.com/metacubex/mihomo/constant/provider" ) var ( diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index d547dcb7..ffaec91b 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -10,15 +10,15 @@ import ( "strings" "time" - "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" - types "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel/statistic" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/common/convert" + "github.com/metacubex/mihomo/common/utils" + mihomoHttp "github.com/metacubex/mihomo/component/http" + "github.com/metacubex/mihomo/component/resource" + C "github.com/metacubex/mihomo/constant" + types "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel/statistic" "github.com/dlclark/regexp2" "gopkg.in/yaml.v3" @@ -119,8 +119,8 @@ func (pp *proxySetProvider) getSubscriptionInfo() { go func() { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), - http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), + http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return } @@ -128,7 +128,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() { userInfoStr := strings.TrimSpace(resp.Header.Get("subscription-userinfo")) if userInfoStr == "" { - resp2, err := clashHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), + resp2, err := mihomoHttp.HttpRequest(ctx, pp.Vehicle().(*resource.HTTPVehicle).Url(), http.MethodGet, http.Header{"User-Agent": {"Quantumultx"}}, nil) if err != nil { return diff --git a/common/cache/lrucache.go b/common/cache/lrucache.go index 2f9d3e79..d71cc3b9 100644 --- a/common/cache/lrucache.go +++ b/common/cache/lrucache.go @@ -6,7 +6,7 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/generics/list" + "github.com/metacubex/mihomo/common/generics/list" "github.com/samber/lo" ) diff --git a/common/callback/callback.go b/common/callback/callback.go index fe76dc67..9ae0f94a 100644 --- a/common/callback/callback.go +++ b/common/callback/callback.go @@ -1,9 +1,9 @@ package callback import ( - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" ) type firstWriteCallBackConn struct { diff --git a/common/convert/converter.go b/common/convert/converter.go index 5a618f42..55035bbe 100644 --- a/common/convert/converter.go +++ b/common/convert/converter.go @@ -9,10 +9,10 @@ import ( "strconv" "strings" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" ) -// ConvertsV2Ray convert V2Ray subscribe proxies data to clash proxies config +// ConvertsV2Ray convert V2Ray subscribe proxies data to mihomo proxies config func ConvertsV2Ray(buf []byte) ([]map[string]any, error) { data := DecodeBase64(buf) diff --git a/common/convert/util.go b/common/convert/util.go index 0ec35acd..a715b556 100644 --- a/common/convert/util.go +++ b/common/convert/util.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/sing-shadowsocks/shadowimpl" "github.com/zhangyunhao116/fastrand" diff --git a/common/net/bufconn.go b/common/net/bufconn.go index b840fefc..37c8ba25 100644 --- a/common/net/bufconn.go +++ b/common/net/bufconn.go @@ -4,7 +4,7 @@ import ( "bufio" "net" - "github.com/Dreamacro/clash/common/buf" + "github.com/metacubex/mihomo/common/buf" ) var _ ExtendedConn = (*BufferedConn)(nil) diff --git a/common/net/cached.go b/common/net/cached.go index 3b7da44c..fb605b74 100644 --- a/common/net/cached.go +++ b/common/net/cached.go @@ -3,7 +3,7 @@ package net import ( "net" - "github.com/Dreamacro/clash/common/buf" + "github.com/metacubex/mihomo/common/buf" ) var _ ExtendedConn = (*CachedConn)(nil) diff --git a/common/net/deadline/packet.go b/common/net/deadline/packet.go index bcf2db9d..67043198 100644 --- a/common/net/deadline/packet.go +++ b/common/net/deadline/packet.go @@ -6,8 +6,8 @@ import ( "runtime" "time" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/net/packet" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/net/packet" ) type readResult struct { diff --git a/common/net/deadline/packet_enhance.go b/common/net/deadline/packet_enhance.go index 5b7d767f..3e314fb8 100644 --- a/common/net/deadline/packet_enhance.go +++ b/common/net/deadline/packet_enhance.go @@ -5,7 +5,7 @@ import ( "os" "runtime" - "github.com/Dreamacro/clash/common/net/packet" + "github.com/metacubex/mihomo/common/net/packet" ) type EnhancePacketConn struct { diff --git a/common/net/deadline/packet_sing.go b/common/net/deadline/packet_sing.go index f41f3f5b..65db1b8f 100644 --- a/common/net/deadline/packet_sing.go +++ b/common/net/deadline/packet_sing.go @@ -4,7 +4,7 @@ import ( "os" "runtime" - "github.com/Dreamacro/clash/common/net/packet" + "github.com/metacubex/mihomo/common/net/packet" "github.com/sagernet/sing/common/buf" "github.com/sagernet/sing/common/bufio" M "github.com/sagernet/sing/common/metadata" diff --git a/common/net/packet.go b/common/net/packet.go index fc562c42..fd03b4f8 100644 --- a/common/net/packet.go +++ b/common/net/packet.go @@ -1,8 +1,8 @@ package net import ( - "github.com/Dreamacro/clash/common/net/deadline" - "github.com/Dreamacro/clash/common/net/packet" + "github.com/metacubex/mihomo/common/net/deadline" + "github.com/metacubex/mihomo/common/net/packet" ) type EnhancePacketConn = packet.EnhancePacketConn diff --git a/common/net/packet/packet.go b/common/net/packet/packet.go index 6c9542c1..0cdbccae 100644 --- a/common/net/packet/packet.go +++ b/common/net/packet/packet.go @@ -3,7 +3,7 @@ package packet import ( "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type WaitReadFrom interface { diff --git a/common/net/packet/packet_posix.go b/common/net/packet/packet_posix.go index 2861482f..2073e35d 100644 --- a/common/net/packet/packet_posix.go +++ b/common/net/packet/packet_posix.go @@ -7,7 +7,7 @@ import ( "strconv" "syscall" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type enhanceUDPConn struct { diff --git a/common/net/refconn.go b/common/net/refconn.go index 5caaebc8..6d0dde98 100644 --- a/common/net/refconn.go +++ b/common/net/refconn.go @@ -5,7 +5,7 @@ import ( "runtime" "time" - "github.com/Dreamacro/clash/common/buf" + "github.com/metacubex/mihomo/common/buf" ) type refConn struct { diff --git a/common/net/relay.go b/common/net/relay.go index 6191e76b..f2a1b146 100644 --- a/common/net/relay.go +++ b/common/net/relay.go @@ -12,7 +12,7 @@ package net // // go func() { // // Wrapping to avoid using *net.TCPConn.(ReadFrom) -// // See also https://github.com/Dreamacro/clash/pull/1209 +// // See also https://github.com/metacubex/mihomo/pull/1209 // _, err := io.Copy(WriteOnlyWriter{Writer: leftConn}, ReadOnlyReader{Reader: rightConn}) // leftConn.SetReadDeadline(time.Now()) // ch <- err diff --git a/common/observable/observable_test.go b/common/observable/observable_test.go index 5a02273d..d263cb94 100644 --- a/common/observable/observable_test.go +++ b/common/observable/observable_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/common/atomic" + "github.com/metacubex/mihomo/common/atomic" "github.com/stretchr/testify/assert" ) diff --git a/common/singledo/singledo_test.go b/common/singledo/singledo_test.go index 9e114fb7..2f92f0ae 100644 --- a/common/singledo/singledo_test.go +++ b/common/singledo/singledo_test.go @@ -5,7 +5,7 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/common/atomic" + "github.com/metacubex/mihomo/common/atomic" "github.com/stretchr/testify/assert" ) diff --git a/component/dhcp/conn.go b/component/dhcp/conn.go index 5b71d3cd..ff26275b 100644 --- a/component/dhcp/conn.go +++ b/component/dhcp/conn.go @@ -5,7 +5,7 @@ import ( "net" "runtime" - "github.com/Dreamacro/clash/component/dialer" + "github.com/metacubex/mihomo/component/dialer" ) func ListenDHCPClient(ctx context.Context, ifaceName string) (net.PacketConn, error) { diff --git a/component/dhcp/dhcp.go b/component/dhcp/dhcp.go index be2c578a..04ad2eda 100644 --- a/component/dhcp/dhcp.go +++ b/component/dhcp/dhcp.go @@ -6,8 +6,8 @@ import ( "net" "net/netip" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/component/iface" "github.com/insomniacslk/dhcp/dhcpv4" ) diff --git a/component/dialer/bind.go b/component/dialer/bind.go index c90212ef..72df8c72 100644 --- a/component/dialer/bind.go +++ b/component/dialer/bind.go @@ -6,7 +6,7 @@ import ( "strconv" "strings" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/component/iface" ) func LookupLocalAddrFromIfaceName(ifaceName string, network string, destination netip.Addr, port int) (net.Addr, error) { diff --git a/component/dialer/bind_darwin.go b/component/dialer/bind_darwin.go index 8705a708..f83b86f8 100644 --- a/component/dialer/bind_darwin.go +++ b/component/dialer/bind_darwin.go @@ -6,7 +6,7 @@ import ( "net/netip" "syscall" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/component/iface" "golang.org/x/sys/unix" ) diff --git a/component/dialer/bind_windows.go b/component/dialer/bind_windows.go index 0d38d1c5..120f1657 100644 --- a/component/dialer/bind_windows.go +++ b/component/dialer/bind_windows.go @@ -9,7 +9,7 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/component/iface" ) const ( diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 3cb8bba9..0e0e3cef 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -11,7 +11,7 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/resolver" + "github.com/metacubex/mihomo/component/resolver" ) type dialFunc func(ctx context.Context, network string, ips []netip.Addr, port string, opt *option) (net.Conn, error) diff --git a/component/dialer/mark_nonlinux.go b/component/dialer/mark_nonlinux.go index ea448276..64e58784 100644 --- a/component/dialer/mark_nonlinux.go +++ b/component/dialer/mark_nonlinux.go @@ -7,7 +7,7 @@ import ( "net/netip" "sync" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" ) var printMarkWarnOnce sync.Once diff --git a/component/dialer/options.go b/component/dialer/options.go index 781d7164..c0c21891 100644 --- a/component/dialer/options.go +++ b/component/dialer/options.go @@ -4,8 +4,8 @@ import ( "context" "net" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/component/resolver" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/component/resolver" ) var ( diff --git a/component/ebpf/bpf/redir.c b/component/ebpf/bpf/redir.c index a24afec8..6ef5ee0c 100644 --- a/component/ebpf/bpf/redir.c +++ b/component/ebpf/bpf/redir.c @@ -173,7 +173,7 @@ static __always_inline bool is_lan_ip(__be32 addr) { return false; } -SEC("tc_clash_auto_redir_ingress") +SEC("tc_mihomo_auto_redir_ingress") int tc_redir_ingress_func(struct __sk_buff *skb) { void *data = (void *)(long)skb->data; void *data_end = (void *)(long)skb->data_end; @@ -264,7 +264,7 @@ int tc_redir_ingress_func(struct __sk_buff *skb) { return TC_ACT_OK; } -SEC("tc_clash_auto_redir_egress") +SEC("tc_mihomo_auto_redir_egress") int tc_redir_egress_func(struct __sk_buff *skb) { void *data = (void *)(long)skb->data; void *data_end = (void *)(long)skb->data_end; @@ -276,10 +276,10 @@ int tc_redir_egress_func(struct __sk_buff *skb) { if (eth->h_proto != bpf_htons(ETH_P_IP)) return TC_ACT_OK; - __u32 key = 0, *redir_ip, *redir_port; // *clash_mark + __u32 key = 0, *redir_ip, *redir_port; // *mihomo_mark -// clash_mark = bpf_map_lookup_elem(&redir_params_map, &key); -// if (clash_mark && *clash_mark != 0 && *clash_mark == skb->mark) +// mihomo_mark = bpf_map_lookup_elem(&redir_params_map, &key); +// if (mihomo_mark && *mihomo_mark != 0 && *mihomo_mark == skb->mark) // return TC_ACT_OK; struct iphdr *iph = (struct iphdr *)(eth + 1); diff --git a/component/ebpf/bpf/tc.c b/component/ebpf/bpf/tc.c index 4eebf41c..3513bf04 100644 --- a/component/ebpf/bpf/tc.c +++ b/component/ebpf/bpf/tc.c @@ -38,7 +38,7 @@ static __always_inline bool is_lan_ip(__be32 addr) { return false; } -SEC("tc_clash_redirect_to_tun") +SEC("tc_mihomo_redirect_to_tun") int tc_tun_func(struct __sk_buff *skb) { void *data = (void *)(long)skb->data; void *data_end = (void *)(long)skb->data_end; @@ -50,13 +50,13 @@ int tc_tun_func(struct __sk_buff *skb) { if (eth->h_proto == bpf_htons(ETH_P_ARP)) return TC_ACT_OK; - __u32 key = 0, *clash_mark, *tun_ifindex; + __u32 key = 0, *mihomo_mark, *tun_ifindex; - clash_mark = bpf_map_lookup_elem(&tc_params_map, &key); - if (!clash_mark) + mihomo_mark = bpf_map_lookup_elem(&tc_params_map, &key); + if (!mihomo_mark) return TC_ACT_OK; - if (skb->mark == *clash_mark) + if (skb->mark == *mihomo_mark) return TC_ACT_OK; if (eth->h_proto == bpf_htons(ETH_P_IP)) { diff --git a/component/ebpf/ebpf.go b/component/ebpf/ebpf.go index 6257675c..b0f5a65f 100644 --- a/component/ebpf/ebpf.go +++ b/component/ebpf/ebpf.go @@ -3,8 +3,8 @@ package ebpf import ( "net/netip" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type TcEBpfProgram struct { diff --git a/component/ebpf/ebpf_linux.go b/component/ebpf/ebpf_linux.go index 2ffd4bd5..304f32fe 100644 --- a/component/ebpf/ebpf_linux.go +++ b/component/ebpf/ebpf_linux.go @@ -6,11 +6,11 @@ import ( "fmt" "net/netip" - "github.com/Dreamacro/clash/common/cmd" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/ebpf/redir" - "github.com/Dreamacro/clash/component/ebpf/tc" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/cmd" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/ebpf/redir" + "github.com/metacubex/mihomo/component/ebpf/tc" + C "github.com/metacubex/mihomo/constant" "github.com/sagernet/netlink" ) @@ -47,7 +47,7 @@ func NewTcEBpfProgram(ifaceNames []string, tunName string) (*TcEBpfProgram, erro tunIndex := uint32(tunIface.Attrs().Index) - dialer.DefaultRoutingMark.Store(C.ClashTrafficMark) + dialer.DefaultRoutingMark.Store(C.MihomoTrafficMark) ifMark := uint32(dialer.DefaultRoutingMark.Load()) diff --git a/component/ebpf/redir/auto_redirect.go b/component/ebpf/redir/auto_redirect.go index 4fd8b785..57c99616 100644 --- a/component/ebpf/redir/auto_redirect.go +++ b/component/ebpf/redir/auto_redirect.go @@ -16,9 +16,9 @@ import ( "github.com/sagernet/netlink" "golang.org/x/sys/unix" - "github.com/Dreamacro/clash/component/ebpf/byteorder" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/component/ebpf/byteorder" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf ../bpf/redir.c @@ -131,7 +131,7 @@ func (e *EBpfRedirect) Start() error { filter := &netlink.BpfFilter{ FilterAttrs: filterAttrs, Fd: objs.bpfPrograms.TcRedirIngressFunc.FD(), - Name: "clash-redir-ingress-" + e.ifName, + Name: "mihomo-redir-ingress-" + e.ifName, DirectAction: true, } @@ -153,7 +153,7 @@ func (e *EBpfRedirect) Start() error { filterEgress := &netlink.BpfFilter{ FilterAttrs: filterAttrsEgress, Fd: objs.bpfPrograms.TcRedirEgressFunc.FD(), - Name: "clash-redir-egress-" + e.ifName, + Name: "mihomo-redir-egress-" + e.ifName, DirectAction: true, } diff --git a/component/ebpf/tc/redirect_to_tun.go b/component/ebpf/tc/redirect_to_tun.go index 1edc1781..d7be64af 100644 --- a/component/ebpf/tc/redirect_to_tun.go +++ b/component/ebpf/tc/redirect_to_tun.go @@ -14,8 +14,8 @@ import ( "github.com/sagernet/netlink" "golang.org/x/sys/unix" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) //go:generate go run github.com/cilium/ebpf/cmd/bpf2go -cc $BPF_CLANG -cflags $BPF_CFLAGS bpf ../bpf/tc.c @@ -115,7 +115,7 @@ func (e *EBpfTC) Start() error { filter := &netlink.BpfFilter{ FilterAttrs: filterAttrs, Fd: objs.bpfPrograms.TcTunFunc.FD(), - Name: "clash-tc-" + e.ifName, + Name: "mihomo-tc-" + e.ifName, DirectAction: true, } diff --git a/component/fakeip/cachefile.go b/component/fakeip/cachefile.go index c31d751f..6f0cc48b 100644 --- a/component/fakeip/cachefile.go +++ b/component/fakeip/cachefile.go @@ -3,7 +3,7 @@ package fakeip import ( "net/netip" - "github.com/Dreamacro/clash/component/profile/cachefile" + "github.com/metacubex/mihomo/component/profile/cachefile" ) type cachefileStore struct { diff --git a/component/fakeip/memory.go b/component/fakeip/memory.go index 249c5e2a..f36bbb55 100644 --- a/component/fakeip/memory.go +++ b/component/fakeip/memory.go @@ -3,7 +3,7 @@ package fakeip import ( "net/netip" - "github.com/Dreamacro/clash/common/cache" + "github.com/metacubex/mihomo/common/cache" ) type memoryStore struct { diff --git a/component/fakeip/pool.go b/component/fakeip/pool.go index 9b51929e..2b06fc0b 100644 --- a/component/fakeip/pool.go +++ b/component/fakeip/pool.go @@ -6,9 +6,9 @@ import ( "strings" "sync" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/component/profile/cachefile" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/component/profile/cachefile" + "github.com/metacubex/mihomo/component/trie" ) const ( diff --git a/component/fakeip/pool_test.go b/component/fakeip/pool_test.go index 183a7185..a7569ab0 100644 --- a/component/fakeip/pool_test.go +++ b/component/fakeip/pool_test.go @@ -7,8 +7,8 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/component/profile/cachefile" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/component/profile/cachefile" + "github.com/metacubex/mihomo/component/trie" "github.com/stretchr/testify/assert" "go.etcd.io/bbolt" @@ -32,7 +32,7 @@ func createCachefileStore(options Options) (*Pool, string, error) { if err != nil { return nil, "", err } - f, err := os.CreateTemp("", "clash") + f, err := os.CreateTemp("", "mihomo") if err != nil { return nil, "", err } diff --git a/component/geodata/attr.go b/component/geodata/attr.go index e35a25ca..a9742aca 100644 --- a/component/geodata/attr.go +++ b/component/geodata/attr.go @@ -3,7 +3,7 @@ package geodata import ( "strings" - "github.com/Dreamacro/clash/component/geodata/router" + "github.com/metacubex/mihomo/component/geodata/router" ) type AttributeList struct { diff --git a/component/geodata/geodata.go b/component/geodata/geodata.go index 9d0b0df0..a6ef146a 100644 --- a/component/geodata/geodata.go +++ b/component/geodata/geodata.go @@ -3,8 +3,8 @@ package geodata import ( "fmt" - "github.com/Dreamacro/clash/component/geodata/router" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/component/geodata/router" + C "github.com/metacubex/mihomo/constant" ) type loader struct { diff --git a/component/geodata/geodataproto.go b/component/geodata/geodataproto.go index 34bdad70..0f1ce4d2 100644 --- a/component/geodata/geodataproto.go +++ b/component/geodata/geodataproto.go @@ -1,7 +1,7 @@ package geodata import ( - "github.com/Dreamacro/clash/component/geodata/router" + "github.com/metacubex/mihomo/component/geodata/router" ) type LoaderImplementation interface { diff --git a/component/geodata/init.go b/component/geodata/init.go index acae1a34..0b193c94 100644 --- a/component/geodata/init.go +++ b/component/geodata/init.go @@ -8,10 +8,10 @@ import ( "os" "time" - clashHttp "github.com/Dreamacro/clash/component/http" - "github.com/Dreamacro/clash/component/mmdb" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + mihomoHttp "github.com/metacubex/mihomo/component/http" + "github.com/metacubex/mihomo/component/mmdb" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) var initGeoSite bool @@ -44,7 +44,7 @@ func InitGeoSite() error { func downloadGeoSite(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoSiteUrl, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return } @@ -63,7 +63,7 @@ func downloadGeoSite(path string) (err error) { func downloadGeoIP(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.GeoIpUrl, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return } diff --git a/component/geodata/memconservative/cache.go b/component/geodata/memconservative/cache.go index ca78d19d..ef76a42c 100644 --- a/component/geodata/memconservative/cache.go +++ b/component/geodata/memconservative/cache.go @@ -5,9 +5,9 @@ import ( "os" "strings" - "github.com/Dreamacro/clash/component/geodata/router" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata/router" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "google.golang.org/protobuf/proto" ) diff --git a/component/geodata/memconservative/memc.go b/component/geodata/memconservative/memc.go index 88d3b4e5..30d89f10 100644 --- a/component/geodata/memconservative/memc.go +++ b/component/geodata/memconservative/memc.go @@ -5,8 +5,8 @@ import ( "fmt" "runtime" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" ) type memConservativeLoader struct { diff --git a/component/geodata/router/condition.go b/component/geodata/router/condition.go index 4e0ad46c..156614ae 100644 --- a/component/geodata/router/condition.go +++ b/component/geodata/router/condition.go @@ -7,7 +7,7 @@ import ( "sort" "strings" - "github.com/Dreamacro/clash/component/geodata/strmatcher" + "github.com/metacubex/mihomo/component/geodata/strmatcher" ) var matcherTypeMap = map[Domain_Type]strmatcher.Type{ diff --git a/component/geodata/router/config.pb.go b/component/geodata/router/config.pb.go index 7c3af22a..59d90c7a 100644 --- a/component/geodata/router/config.pb.go +++ b/component/geodata/router/config.pb.go @@ -84,7 +84,7 @@ type Domain struct { unknownFields protoimpl.UnknownFields // Domain matching type. - Type Domain_Type `protobuf:"varint,1,opt,name=type,proto3,enum=clash.component.geodata.router.Domain_Type" json:"type,omitempty"` + Type Domain_Type `protobuf:"varint,1,opt,name=type,proto3,enum=mihomo.component.geodata.router.Domain_Type" json:"type,omitempty"` // Domain value. Value string `protobuf:"bytes,2,opt,name=value,proto3" json:"value,omitempty"` // Attributes of this domain. May be used for filtering. @@ -585,22 +585,22 @@ func file_component_geodata_router_config_proto_rawDescGZIP() []byte { var file_component_geodata_router_config_proto_enumTypes = make([]protoimpl.EnumInfo, 1) var file_component_geodata_router_config_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_component_geodata_router_config_proto_goTypes = []interface{}{ - (Domain_Type)(0), // 0: clash.component.geodata.router.Domain.Type - (*Domain)(nil), // 1: clash.component.geodata.router.Domain - (*CIDR)(nil), // 2: clash.component.geodata.router.CIDR - (*GeoIP)(nil), // 3: clash.component.geodata.router.GeoIP - (*GeoIPList)(nil), // 4: clash.component.geodata.router.GeoIPList - (*GeoSite)(nil), // 5: clash.component.geodata.router.GeoSite - (*GeoSiteList)(nil), // 6: clash.component.geodata.router.GeoSiteList - (*Domain_Attribute)(nil), // 7: clash.component.geodata.router.Domain.Attribute + (Domain_Type)(0), // 0: mihomo.component.geodata.router.Domain.Type + (*Domain)(nil), // 1: mihomo.component.geodata.router.Domain + (*CIDR)(nil), // 2: mihomo.component.geodata.router.CIDR + (*GeoIP)(nil), // 3: mihomo.component.geodata.router.GeoIP + (*GeoIPList)(nil), // 4: mihomo.component.geodata.router.GeoIPList + (*GeoSite)(nil), // 5: mihomo.component.geodata.router.GeoSite + (*GeoSiteList)(nil), // 6: mihomo.component.geodata.router.GeoSiteList + (*Domain_Attribute)(nil), // 7: mihomo.component.geodata.router.Domain.Attribute } var file_component_geodata_router_config_proto_depIdxs = []int32{ - 0, // 0: clash.component.geodata.router.Domain.type:type_name -> clash.component.geodata.router.Domain.Type - 7, // 1: clash.component.geodata.router.Domain.attribute:type_name -> clash.component.geodata.router.Domain.Attribute - 2, // 2: clash.component.geodata.router.GeoIP.cidr:type_name -> clash.component.geodata.router.CIDR - 3, // 3: clash.component.geodata.router.GeoIPList.entry:type_name -> clash.component.geodata.router.GeoIP - 1, // 4: clash.component.geodata.router.GeoSite.domain:type_name -> clash.component.geodata.router.Domain - 5, // 5: clash.component.geodata.router.GeoSiteList.entry:type_name -> clash.component.geodata.router.GeoSite + 0, // 0: mihomo.component.geodata.router.Domain.type:type_name -> mihomo.component.geodata.router.Domain.Type + 7, // 1: mihomo.component.geodata.router.Domain.attribute:type_name -> mihomo.component.geodata.router.Domain.Attribute + 2, // 2: mihomo.component.geodata.router.GeoIP.cidr:type_name -> mihomo.component.geodata.router.CIDR + 3, // 3: mihomo.component.geodata.router.GeoIPList.entry:type_name -> mihomo.component.geodata.router.GeoIP + 1, // 4: mihomo.component.geodata.router.GeoSite.domain:type_name -> mihomo.component.geodata.router.Domain + 5, // 5: mihomo.component.geodata.router.GeoSiteList.entry:type_name -> mihomo.component.geodata.router.GeoSite 6, // [6:6] is the sub-list for method output_type 6, // [6:6] is the sub-list for method input_type 6, // [6:6] is the sub-list for extension type_name diff --git a/component/geodata/router/config.proto b/component/geodata/router/config.proto index 245faadf..98795740 100644 --- a/component/geodata/router/config.proto +++ b/component/geodata/router/config.proto @@ -1,9 +1,9 @@ syntax = "proto3"; -package clash.component.geodata.router; -option csharp_namespace = "Clash.Component.Geodata.Router"; -option go_package = "github.com/Dreamacro/clash/component/geodata/router"; -option java_package = "com.clash.component.geodata.router"; +package mihomo.component.geodata.router; +option csharp_namespace = "Mihomo.Component.Geodata.Router"; +option go_package = "github.com/metacubex/mihomo/component/geodata/router"; +option java_package = "com.mihomo.component.geodata.router"; option java_multiple_files = true; // Domain for routing decision. diff --git a/component/geodata/standard/standard.go b/component/geodata/standard/standard.go index 355cbf34..bfaae5ec 100644 --- a/component/geodata/standard/standard.go +++ b/component/geodata/standard/standard.go @@ -6,9 +6,9 @@ import ( "os" "strings" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" + C "github.com/metacubex/mihomo/constant" "google.golang.org/protobuf/proto" ) diff --git a/component/geodata/strmatcher/ac_automaton_matcher.go b/component/geodata/strmatcher/ac_automaton_matcher.go index d134c68a..ca7dc48b 100644 --- a/component/geodata/strmatcher/ac_automaton_matcher.go +++ b/component/geodata/strmatcher/ac_automaton_matcher.go @@ -1,7 +1,7 @@ package strmatcher import ( - "github.com/Dreamacro/clash/common/generics/list" + "github.com/metacubex/mihomo/common/generics/list" ) const validCharCount = 53 diff --git a/component/geodata/utils.go b/component/geodata/utils.go index 04ccfa51..4716ccbd 100644 --- a/component/geodata/utils.go +++ b/component/geodata/utils.go @@ -6,9 +6,9 @@ import ( "golang.org/x/sync/singleflight" "strings" - "github.com/Dreamacro/clash/component/geodata/router" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata/router" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) var geoLoaderName = "memconservative" diff --git a/component/http/http.go b/component/http/http.go index 073f0237..455db681 100644 --- a/component/http/http.go +++ b/component/http/http.go @@ -11,9 +11,9 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/component/ca" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/inner" + "github.com/metacubex/mihomo/component/ca" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/inner" ) func HttpRequest(ctx context.Context, url, method string, header map[string][]string, body io.Reader) (*http.Response, error) { diff --git a/component/iface/iface.go b/component/iface/iface.go index 03051cb3..bf186165 100644 --- a/component/iface/iface.go +++ b/component/iface/iface.go @@ -7,7 +7,7 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/singledo" + "github.com/metacubex/mihomo/common/singledo" ) type Interface struct { diff --git a/component/mmdb/mmdb.go b/component/mmdb/mmdb.go index 5db8bee9..f83b9922 100644 --- a/component/mmdb/mmdb.go +++ b/component/mmdb/mmdb.go @@ -8,9 +8,9 @@ import ( "sync" "time" - clashHttp "github.com/Dreamacro/clash/component/http" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + mihomoHttp "github.com/metacubex/mihomo/component/http" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/oschwald/maxminddb-golang" ) @@ -79,7 +79,7 @@ func Instance() Reader { func DownloadMMDB(path string) (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, C.MmdbUrl, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return } diff --git a/component/nat/proxy.go b/component/nat/proxy.go index 29ff3c81..66af3be2 100644 --- a/component/nat/proxy.go +++ b/component/nat/proxy.go @@ -3,8 +3,8 @@ package nat import ( "net" - "github.com/Dreamacro/clash/common/atomic" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/atomic" + C "github.com/metacubex/mihomo/constant" ) type writeBackProxy struct { diff --git a/component/nat/table.go b/component/nat/table.go index df258dc2..b2908c94 100644 --- a/component/nat/table.go +++ b/component/nat/table.go @@ -4,7 +4,7 @@ import ( "net" "sync" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "github.com/puzpuzpuz/xsync/v2" ) diff --git a/component/process/process_freebsd_amd64.go b/component/process/process_freebsd_amd64.go index 709ade3b..1884afcc 100644 --- a/component/process/process_freebsd_amd64.go +++ b/component/process/process_freebsd_amd64.go @@ -10,8 +10,8 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/log" ) // store process name for when dealing with multiple PROCESS-NAME rules diff --git a/component/process/process_windows.go b/component/process/process_windows.go index 21878bf6..d43c78c6 100644 --- a/component/process/process_windows.go +++ b/component/process/process_windows.go @@ -7,8 +7,8 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/log" "golang.org/x/sys/windows" ) diff --git a/component/profile/cachefile/cache.go b/component/profile/cachefile/cache.go index 3d2dd1de..68812824 100644 --- a/component/profile/cachefile/cache.go +++ b/component/profile/cachefile/cache.go @@ -5,9 +5,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/profile" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/profile" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "go.etcd.io/bbolt" ) diff --git a/component/profile/profile.go b/component/profile/profile.go index aa6df2f7..36db8cc3 100644 --- a/component/profile/profile.go +++ b/component/profile/profile.go @@ -1,7 +1,7 @@ package profile import ( - "github.com/Dreamacro/clash/common/atomic" + "github.com/metacubex/mihomo/common/atomic" ) // StoreSelected is a global switch for storing selected proxy to cache diff --git a/component/proxydialer/proxydialer.go b/component/proxydialer/proxydialer.go index 2d14abae..71a658b8 100644 --- a/component/proxydialer/proxydialer.go +++ b/component/proxydialer/proxydialer.go @@ -8,12 +8,12 @@ import ( "net/netip" "strings" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/tunnel" - "github.com/Dreamacro/clash/tunnel/statistic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/tunnel" + "github.com/metacubex/mihomo/tunnel/statistic" ) type proxyDialer struct { diff --git a/component/proxydialer/sing.go b/component/proxydialer/sing.go index 9b116527..71180c01 100644 --- a/component/proxydialer/sing.go +++ b/component/proxydialer/sing.go @@ -4,7 +4,7 @@ import ( "context" "net" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" M "github.com/sagernet/sing/common/metadata" N "github.com/sagernet/sing/common/network" diff --git a/component/resolver/host.go b/component/resolver/host.go index d6eb5873..69c29a3c 100644 --- a/component/resolver/host.go +++ b/component/resolver/host.go @@ -6,8 +6,8 @@ import ( "strings" _ "unsafe" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/trie" "github.com/zhangyunhao116/fastrand" ) diff --git a/component/resolver/resolver.go b/component/resolver/resolver.go index 6be6a95f..8cbc62fa 100644 --- a/component/resolver/resolver.go +++ b/component/resolver/resolver.go @@ -9,8 +9,8 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/trie" "github.com/miekg/dns" "github.com/zhangyunhao116/fastrand" diff --git a/component/resource/fetcher.go b/component/resource/fetcher.go index c92687b1..31dc5c08 100644 --- a/component/resource/fetcher.go +++ b/component/resource/fetcher.go @@ -7,8 +7,8 @@ import ( "path/filepath" "time" - types "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/log" + types "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/log" "github.com/samber/lo" ) diff --git a/component/resource/vehicle.go b/component/resource/vehicle.go index 2f4bfbc8..b2e29418 100644 --- a/component/resource/vehicle.go +++ b/component/resource/vehicle.go @@ -8,8 +8,8 @@ import ( "os" "time" - clashHttp "github.com/Dreamacro/clash/component/http" - types "github.com/Dreamacro/clash/constant/provider" + mihomoHttp "github.com/metacubex/mihomo/component/http" + types "github.com/metacubex/mihomo/constant/provider" ) type FileVehicle struct { @@ -52,7 +52,7 @@ func (h *HTTPVehicle) Path() string { func (h *HTTPVehicle) Read() ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*20) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil) + resp, err := mihomoHttp.HttpRequest(ctx, h.url, http.MethodGet, nil, nil) if err != nil { return nil, err } diff --git a/component/sniffer/base_sniffer.go b/component/sniffer/base_sniffer.go index 6d869aa0..55f51c50 100644 --- a/component/sniffer/base_sniffer.go +++ b/component/sniffer/base_sniffer.go @@ -3,9 +3,9 @@ package sniffer import ( "errors" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/sniffer" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/sniffer" ) type SnifferConfig struct { diff --git a/component/sniffer/dispatcher.go b/component/sniffer/dispatcher.go index 11deb1ed..29bea088 100644 --- a/component/sniffer/dispatcher.go +++ b/component/sniffer/dispatcher.go @@ -8,12 +8,12 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/cache" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/sniffer" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/cache" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/sniffer" + "github.com/metacubex/mihomo/log" ) var ( diff --git a/component/sniffer/http_sniffer.go b/component/sniffer/http_sniffer.go index ee958a1c..76bf1559 100644 --- a/component/sniffer/http_sniffer.go +++ b/component/sniffer/http_sniffer.go @@ -7,9 +7,9 @@ import ( "net" "strings" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/sniffer" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/sniffer" ) var ( diff --git a/component/sniffer/quic_sniffer.go b/component/sniffer/quic_sniffer.go index ef49e5ad..0e3994f0 100644 --- a/component/sniffer/quic_sniffer.go +++ b/component/sniffer/quic_sniffer.go @@ -8,9 +8,9 @@ import ( "errors" "io" - "github.com/Dreamacro/clash/common/buf" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/buf" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/quic-go/quicvarint" "golang.org/x/crypto/hkdf" diff --git a/component/sniffer/tls_sniffer.go b/component/sniffer/tls_sniffer.go index b695c76f..974df79a 100644 --- a/component/sniffer/tls_sniffer.go +++ b/component/sniffer/tls_sniffer.go @@ -5,9 +5,9 @@ import ( "errors" "strings" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/sniffer" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/sniffer" ) var ( diff --git a/component/tls/reality.go b/component/tls/reality.go index 2902aa4b..250dc4d0 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -20,9 +20,9 @@ import ( "time" "unsafe" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/ntp" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/ntp" utls "github.com/sagernet/utls" "github.com/zhangyunhao116/fastrand" diff --git a/component/tls/utls.go b/component/tls/utls.go index 3aa030d3..787f6fad 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -4,7 +4,7 @@ import ( "crypto/tls" "net" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" "github.com/mroth/weightedrand/v2" utls "github.com/sagernet/utls" diff --git a/component/trie/domain_set.go b/component/trie/domain_set.go index e1ad6559..860d1235 100644 --- a/component/trie/domain_set.go +++ b/component/trie/domain_set.go @@ -7,7 +7,7 @@ import ( "sort" "strings" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/openacid/low/bitmap" ) diff --git a/component/trie/domain_set_test.go b/component/trie/domain_set_test.go index 9e0e0b70..77106d5f 100644 --- a/component/trie/domain_set_test.go +++ b/component/trie/domain_set_test.go @@ -3,7 +3,7 @@ package trie_test import ( "testing" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/component/trie" "github.com/stretchr/testify/assert" ) diff --git a/component/trie/domain_test.go b/component/trie/domain_test.go index 976055a9..4c5d8002 100644 --- a/component/trie/domain_test.go +++ b/component/trie/domain_test.go @@ -4,7 +4,7 @@ import ( "net/netip" "testing" - "github.com/Dreamacro/clash/component/trie" + "github.com/metacubex/mihomo/component/trie" "github.com/stretchr/testify/assert" ) diff --git a/component/trie/ipcidr_trie.go b/component/trie/ipcidr_trie.go index 08edbbeb..a2ccfa16 100644 --- a/component/trie/ipcidr_trie.go +++ b/component/trie/ipcidr_trie.go @@ -3,7 +3,7 @@ package trie import ( "net" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" ) type IPV6 bool diff --git a/config/config.go b/config/config.go index 11951aa1..76ff9d68 100644 --- a/config/config.go +++ b/config/config.go @@ -13,31 +13,31 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter" - "github.com/Dreamacro/clash/adapter/outbound" - "github.com/Dreamacro/clash/adapter/outboundgroup" - "github.com/Dreamacro/clash/adapter/provider" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/auth" - "github.com/Dreamacro/clash/component/fakeip" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" - P "github.com/Dreamacro/clash/component/process" - "github.com/Dreamacro/clash/component/resolver" - SNIFF "github.com/Dreamacro/clash/component/sniffer" - tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - providerTypes "github.com/Dreamacro/clash/constant/provider" - snifferTypes "github.com/Dreamacro/clash/constant/sniffer" - "github.com/Dreamacro/clash/dns" - L "github.com/Dreamacro/clash/listener" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/log" - R "github.com/Dreamacro/clash/rules" - RP "github.com/Dreamacro/clash/rules/provider" - T "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/adapter/outbound" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/adapter/provider" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/auth" + "github.com/metacubex/mihomo/component/fakeip" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" + P "github.com/metacubex/mihomo/component/process" + "github.com/metacubex/mihomo/component/resolver" + SNIFF "github.com/metacubex/mihomo/component/sniffer" + tlsC "github.com/metacubex/mihomo/component/tls" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + providerTypes "github.com/metacubex/mihomo/constant/provider" + snifferTypes "github.com/metacubex/mihomo/constant/sniffer" + "github.com/metacubex/mihomo/dns" + L "github.com/metacubex/mihomo/listener" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/log" + R "github.com/metacubex/mihomo/rules" + RP "github.com/metacubex/mihomo/rules/provider" + T "github.com/metacubex/mihomo/tunnel" "gopkg.in/yaml.v3" ) @@ -162,7 +162,7 @@ type Experimental struct { QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"` } -// Config is clash config manager +// Config is mihomo config manager type Config struct { General *General IPTables *IPTables @@ -381,7 +381,7 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { ProxyGroup: []map[string]any{}, TCPConcurrent: false, FindProcessMode: P.FindProcessStrict, - GlobalUA: "clash.meta", + GlobalUA: "mihomo", Tun: RawTun{ Enable: false, Device: "", @@ -917,9 +917,9 @@ func parseHosts(cfg *RawConfig) (*trie.DomainTrie[resolver.HostValue], error) { if len(cfg.Hosts) != 0 { for domain, anyValue := range cfg.Hosts { - if str, ok := anyValue.(string); ok && str == "clash" { + if str, ok := anyValue.(string); ok && str == "mihomo" { if addrs, err := net.InterfaceAddrs(); err != nil { - log.Errorln("insert clash to host error: %s", err) + log.Errorln("insert mihomo to host error: %s", err) } else { ips := make([]netip.Addr, 0) for _, addr := range addrs { diff --git a/config/initial.go b/config/initial.go index 6d6429ab..61d12895 100644 --- a/config/initial.go +++ b/config/initial.go @@ -4,8 +4,8 @@ import ( "fmt" "os" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) // Init prepare necessary files diff --git a/config/update_geo.go b/config/update_geo.go index 07f211e4..718c2d07 100644 --- a/config/update_geo.go +++ b/config/update_geo.go @@ -4,9 +4,9 @@ import ( "fmt" "runtime" - "github.com/Dreamacro/clash/component/geodata" - _ "github.com/Dreamacro/clash/component/geodata/standard" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/component/geodata" + _ "github.com/metacubex/mihomo/component/geodata/standard" + C "github.com/metacubex/mihomo/constant" "github.com/oschwald/maxminddb-golang" ) diff --git a/config/update_ui.go b/config/update_ui.go index 27e0f382..e5596597 100644 --- a/config/update_ui.go +++ b/config/update_ui.go @@ -11,7 +11,7 @@ import ( "strings" "sync" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) var ( diff --git a/config/utils.go b/config/utils.go index 1fa54634..5a4fecbf 100644 --- a/config/utils.go +++ b/config/utils.go @@ -11,15 +11,15 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter/outboundgroup" - "github.com/Dreamacro/clash/common/structure" - clashHttp "github.com/Dreamacro/clash/component/http" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/common/structure" + mihomoHttp "github.com/metacubex/mihomo/component/http" ) func downloadForBytes(url string) ([]byte, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return nil, err } diff --git a/constant/adapters.go b/constant/adapters.go index ad50a8ab..5cf6e07c 100644 --- a/constant/adapters.go +++ b/constant/adapters.go @@ -9,9 +9,9 @@ import ( "sync" "time" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/component/dialer" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/dialer" ) // Adapter Type diff --git a/constant/context.go b/constant/context.go index 1c70124b..11ad7011 100644 --- a/constant/context.go +++ b/constant/context.go @@ -3,7 +3,7 @@ package constant import ( "net" - N "github.com/Dreamacro/clash/common/net" + N "github.com/metacubex/mihomo/common/net" "github.com/gofrs/uuid/v5" ) diff --git a/constant/ebpf.go b/constant/ebpf.go index b722dce1..e3bb62fe 100644 --- a/constant/ebpf.go +++ b/constant/ebpf.go @@ -3,14 +3,14 @@ package constant import ( "net/netip" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) const ( - BpfFSPath = "/sys/fs/bpf/clash" + BpfFSPath = "/sys/fs/bpf/mihomo" - TcpAutoRedirPort = 't'<<8 | 'r'<<0 - ClashTrafficMark = 'c'<<24 | 'l'<<16 | 't'<<8 | 'm'<<0 + TcpAutoRedirPort = 't'<<8 | 'r'<<0 + MihomoTrafficMark = 'c'<<24 | 'l'<<16 | 't'<<8 | 'm'<<0 ) type EBpf interface { diff --git a/constant/metadata.go b/constant/metadata.go index 5f472205..4b547a81 100644 --- a/constant/metadata.go +++ b/constant/metadata.go @@ -7,7 +7,7 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) // Socks addr type @@ -161,7 +161,7 @@ func (m *Metadata) SourceAddress() string { func (m *Metadata) SourceDetail() string { if m.Type == INNER { - return fmt.Sprintf("%s", ClashName) + return fmt.Sprintf("%s", MihomoName) } switch { diff --git a/constant/path.go b/constant/path.go index 0d82f549..a920fbbc 100644 --- a/constant/path.go +++ b/constant/path.go @@ -10,7 +10,7 @@ import ( "strings" ) -const Name = "clash" +const Name = "mihomo" var ( GeositeName = "GeoSite.dat" @@ -19,8 +19,8 @@ var ( // Path is used to get the configuration path // -// on Unix systems, `$HOME/.config/clash`. -// on Windows, `%USERPROFILE%/.config/clash`. +// on Unix systems, `$HOME/.config/mihomo`. +// on Windows, `%USERPROFILE%/.config/mihomo`. var Path = func() *path { homeDir, err := os.UserHomeDir() if err != nil { @@ -165,7 +165,7 @@ func (p *path) GetAssetLocation(file string) string { func (p *path) GetExecutableFullPath() string { exePath, err := os.Executable() if err != nil { - return "clash" + return "mihomo" } res, _ := filepath.EvalSymlinks(exePath) return res diff --git a/constant/provider/interface.go b/constant/provider/interface.go index 34590a48..809db9c5 100644 --- a/constant/provider/interface.go +++ b/constant/provider/interface.go @@ -1,8 +1,8 @@ package provider import ( - "github.com/Dreamacro/clash/common/utils" - "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/constant" ) // Vehicle Type diff --git a/constant/rule_extra.go b/constant/rule_extra.go index 3c5de5d5..62dc1cc3 100644 --- a/constant/rule_extra.go +++ b/constant/rule_extra.go @@ -1,7 +1,7 @@ package constant import ( - "github.com/Dreamacro/clash/component/geodata/router" + "github.com/metacubex/mihomo/component/geodata/router" ) type RuleGeoSite interface { diff --git a/constant/sniffer/sniffer.go b/constant/sniffer/sniffer.go index 47dbd069..36da69a3 100644 --- a/constant/sniffer/sniffer.go +++ b/constant/sniffer/sniffer.go @@ -1,6 +1,6 @@ package sniffer -import "github.com/Dreamacro/clash/constant" +import "github.com/metacubex/mihomo/constant" type Sniffer interface { SupportNetwork() constant.NetWork diff --git a/constant/version.go b/constant/version.go index cbb7ab61..c71024c2 100644 --- a/constant/version.go +++ b/constant/version.go @@ -1,8 +1,8 @@ package constant var ( - Meta = true - Version = "1.10.0" - BuildTime = "unknown time" - ClashName = "clash.meta" + Meta = true + Version = "1.10.0" + BuildTime = "unknown time" + MihomoName = "mihomo" ) diff --git a/context/conn.go b/context/conn.go index afeed852..bae07c23 100644 --- a/context/conn.go +++ b/context/conn.go @@ -1,11 +1,11 @@ package context import ( - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "net" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" "github.com/gofrs/uuid/v5" ) diff --git a/context/dns.go b/context/dns.go index ae29154f..1cc2067d 100644 --- a/context/dns.go +++ b/context/dns.go @@ -2,7 +2,7 @@ package context import ( "context" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/gofrs/uuid/v5" "github.com/miekg/dns" diff --git a/context/packetconn.go b/context/packetconn.go index d695bae5..feab7666 100644 --- a/context/packetconn.go +++ b/context/packetconn.go @@ -3,8 +3,8 @@ package context import ( "net" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" "github.com/gofrs/uuid/v5" ) diff --git a/dns/client.go b/dns/client.go index 5cdd1ec0..95f0f29b 100644 --- a/dns/client.go +++ b/dns/client.go @@ -8,10 +8,10 @@ import ( "net/netip" "strings" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" D "github.com/miekg/dns" "github.com/zhangyunhao116/fastrand" diff --git a/dns/dhcp.go b/dns/dhcp.go index 70f9aeeb..dc1344f5 100644 --- a/dns/dhcp.go +++ b/dns/dhcp.go @@ -8,8 +8,8 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/dhcp" - "github.com/Dreamacro/clash/component/iface" + "github.com/metacubex/mihomo/component/dhcp" + "github.com/metacubex/mihomo/component/iface" D "github.com/miekg/dns" ) diff --git a/dns/doh.go b/dns/doh.go index 488e9025..9e173c84 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -15,9 +15,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/ca" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/ca" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/metacubex/quic-go" "github.com/metacubex/quic-go/http3" D "github.com/miekg/dns" diff --git a/dns/doq.go b/dns/doq.go index 76da913f..70b67c2a 100644 --- a/dns/doq.go +++ b/dns/doq.go @@ -12,9 +12,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/ca" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/ca" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/metacubex/quic-go" D "github.com/miekg/dns" diff --git a/dns/enhancer.go b/dns/enhancer.go index ab144fd3..82fdd35a 100644 --- a/dns/enhancer.go +++ b/dns/enhancer.go @@ -3,9 +3,9 @@ package dns import ( "net/netip" - "github.com/Dreamacro/clash/common/cache" - "github.com/Dreamacro/clash/component/fakeip" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/component/fakeip" + C "github.com/metacubex/mihomo/constant" ) type ResolverEnhancer struct { diff --git a/dns/filters.go b/dns/filters.go index f7e953e8..8eb1e48e 100644 --- a/dns/filters.go +++ b/dns/filters.go @@ -4,12 +4,12 @@ import ( "net/netip" "strings" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" - "github.com/Dreamacro/clash/component/mmdb" - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" + "github.com/metacubex/mihomo/component/mmdb" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type fallbackIPFilter interface { diff --git a/dns/middleware.go b/dns/middleware.go index 695432da..f8e051a0 100644 --- a/dns/middleware.go +++ b/dns/middleware.go @@ -5,13 +5,13 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/cache" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/component/fakeip" - R "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/context" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/component/fakeip" + R "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/context" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" ) diff --git a/dns/resolver.go b/dns/resolver.go index d27f7bcc..610a06f0 100644 --- a/dns/resolver.go +++ b/dns/resolver.go @@ -7,14 +7,14 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/cache" - "github.com/Dreamacro/clash/component/fakeip" - "github.com/Dreamacro/clash/component/geodata/router" - "github.com/Dreamacro/clash/component/resolver" - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/cache" + "github.com/metacubex/mihomo/component/fakeip" + "github.com/metacubex/mihomo/component/geodata/router" + "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" "github.com/samber/lo" diff --git a/dns/server.go b/dns/server.go index 5c5970db..1cf58d4d 100644 --- a/dns/server.go +++ b/dns/server.go @@ -5,9 +5,9 @@ import ( "errors" "net" - "github.com/Dreamacro/clash/common/sockopt" - "github.com/Dreamacro/clash/context" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/sockopt" + "github.com/metacubex/mihomo/context" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" ) diff --git a/dns/system.go b/dns/system.go index 20282929..37607a60 100644 --- a/dns/system.go +++ b/dns/system.go @@ -8,7 +8,7 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" "golang.org/x/exp/slices" diff --git a/dns/util.go b/dns/util.go index 34f7aa94..c354a73d 100644 --- a/dns/util.go +++ b/dns/util.go @@ -11,15 +11,15 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/cache" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/nnip" - "github.com/Dreamacro/clash/common/picker" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/common/cache" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/nnip" + "github.com/metacubex/mihomo/common/picker" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel" D "github.com/miekg/dns" "github.com/samber/lo" diff --git a/docker/file-name.sh b/docker/file-name.sh index 1ac2cee0..3b2d61f9 100644 --- a/docker/file-name.sh +++ b/docker/file-name.sh @@ -1,5 +1,5 @@ #!/bin/sh -os="clash.meta-linux-" +os="mihomo-linux-" case $TARGETPLATFORM in "linux/amd64") arch="amd64-compatible" diff --git a/docs/config.yaml b/docs/config.yaml index 61a2dee9..d5e1174a 100644 --- a/docs/config.yaml +++ b/docs/config.yaml @@ -16,7 +16,7 @@ skip-auth-prefixes: # 设置跳过验证的IP段 # find-process-mode has 3 values:always, strict, off # - always, 开启,强制匹配所有进程 -# - strict, 默认,由 clash 判断是否开启 +# - strict, 默认,由 mihomo 判断是否开启 # - off, 不匹配进程,推荐在路由器上使用此模式 find-process-mode: strict @@ -74,11 +74,11 @@ experimental: # 类似于 /etc/hosts, 仅支持配置单个 IP hosts: -# '*.clash.dev': 127.0.0.1 +# '*.mihomo.dev': 127.0.0.1 # '.dev': 127.0.0.1 -# 'alpha.clash.dev': '::1' +# 'alpha.mihomo.dev': '::1' # test.com: [1.1.1.1, 2.2.2.2] -# clash.lan: clash # clash 为特别字段,将加入本地所有网卡的地址 +# mihomo.lan: mihomo # mihomo 为特别字段,将加入本地所有网卡的地址 # baidu.com: google.com # 只允许配置一个别名 profile: # 存储 select 选择记录 @@ -754,7 +754,7 @@ proxies: # socks5 proxy-groups: # 代理链,目前relay可以支持udp的只有vmess/vless/trojan/ss/ssr/tuic # wireguard目前不支持在relay中使用,请使用proxy中的dialer-proxy配置项 - # Traffic: clash <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet + # Traffic: mihomo <-> http <-> vmess <-> ss1 <-> ss2 <-> Internet - name: "relay" type: relay proxies: @@ -823,13 +823,13 @@ proxy-groups: - Proxy - DIRECT -# Clash 格式的节点或支持 *ray 的分享格式 +# Mihomo 格式的节点或支持 *ray 的分享格式 proxy-providers: provider1: type: http # http 的 path 可空置,默认储存路径为 homedir的proxies文件夹,文件名为url的md5 url: "url" interval: 3600 - path: ./provider1.yaml # 默认只允许存储在 clash 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 + path: ./provider1.yaml # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 health-check: enable: true interval: 600 @@ -846,7 +846,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 # 默认只允许存储在 mihomo 的 Home Dir,如果想存储到任意位置,添加环境变量 SKIP_SAFE_PATH_CHECK=1 type: http # http 的 path 可空置,默认储存路径为 homedir的rules文件夹,文件名为url的md5 url: "url" rule2: diff --git a/flake.nix b/flake.nix index ffd18629..afe6e1c1 100644 --- a/flake.nix +++ b/flake.nix @@ -1,5 +1,5 @@ { - description = "Another Clash Kernel"; + description = "Another Mihomo Kernel"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/master"; @@ -15,7 +15,7 @@ }; in rec { - packages.default = pkgs.clash-meta; + packages.default = pkgs.mihomo-meta; } ) // ( @@ -23,8 +23,8 @@ { overlay = final: prev: { - clash-meta = final.buildGo119Module { - pname = "clash-meta"; + mihomo-meta = final.buildGo119Module { + pname = "mihomo-meta"; inherit version; src = ./.; @@ -38,8 +38,8 @@ ldflags = [ "-s" "-w" - "-X github.com/Dreamacro/clash/constant.Version=dev-${version}" - "-X github.com/Dreamacro/clash/constant.BuildTime=${version}" + "-X github.com/metacubex/mihomo/constant.Version=dev-${version}" + "-X github.com/metacubex/mihomo/constant.BuildTime=${version}" ]; tags = [ @@ -50,7 +50,7 @@ doCheck = false; postInstall = '' - mv $out/bin/clash $out/bin/clash-meta + mv $out/bin/mihomo $out/bin/mihomo-meta ''; }; diff --git a/go.mod b/go.mod index 80ab477c..da45cd28 100644 --- a/go.mod +++ b/go.mod @@ -1,4 +1,4 @@ -module github.com/Dreamacro/clash +module github.com/metacubex/mihomo go 1.20 diff --git a/hub/executor/executor.go b/hub/executor/executor.go index 87e0e0b1..6ea02989 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -11,32 +11,32 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/ntp" + "github.com/metacubex/mihomo/ntp" - "github.com/Dreamacro/clash/adapter" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/adapter/outboundgroup" - "github.com/Dreamacro/clash/component/auth" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/component/dialer" - G "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/iface" - "github.com/Dreamacro/clash/component/profile" - "github.com/Dreamacro/clash/component/profile/cachefile" - "github.com/Dreamacro/clash/component/resolver" - SNI "github.com/Dreamacro/clash/component/sniffer" - "github.com/Dreamacro/clash/component/trie" - "github.com/Dreamacro/clash/config" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/dns" - "github.com/Dreamacro/clash/listener" - authStore "github.com/Dreamacro/clash/listener/auth" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/inner" - "github.com/Dreamacro/clash/listener/tproxy" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/component/auth" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/component/dialer" + G "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/iface" + "github.com/metacubex/mihomo/component/profile" + "github.com/metacubex/mihomo/component/profile/cachefile" + "github.com/metacubex/mihomo/component/resolver" + SNI "github.com/metacubex/mihomo/component/sniffer" + "github.com/metacubex/mihomo/component/trie" + "github.com/metacubex/mihomo/config" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/dns" + "github.com/metacubex/mihomo/listener" + authStore "github.com/metacubex/mihomo/listener/auth" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/inner" + "github.com/metacubex/mihomo/listener/tproxy" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel" ) var mux sync.Mutex @@ -505,5 +505,5 @@ func Shutdown() { tproxy.CleanupTProxyIPTables() resolver.StoreFakePoolState() - log.Warnln("Clash shutting down") + log.Warnln("Mihomo shutting down") } diff --git a/hub/hub.go b/hub/hub.go index bd228fad..323f8749 100644 --- a/hub/hub.go +++ b/hub/hub.go @@ -1,10 +1,10 @@ package hub import ( - "github.com/Dreamacro/clash/config" - "github.com/Dreamacro/clash/hub/executor" - "github.com/Dreamacro/clash/hub/route" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/config" + "github.com/metacubex/mihomo/hub/executor" + "github.com/metacubex/mihomo/hub/route" + "github.com/metacubex/mihomo/log" ) type Option func(*config.Config) @@ -27,7 +27,7 @@ func WithSecret(secret string) Option { } } -// Parse call at the beginning of clash +// Parse call at the beginning of mihomo func Parse(options ...Option) error { cfg, err := executor.Parse() if err != nil { diff --git a/hub/route/cache.go b/hub/route/cache.go index bdfd2e35..f07eb33a 100644 --- a/hub/route/cache.go +++ b/hub/route/cache.go @@ -3,7 +3,7 @@ package route import ( "net/http" - "github.com/Dreamacro/clash/component/resolver" + "github.com/metacubex/mihomo/component/resolver" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/configs.go b/hub/route/configs.go index e86bb2a8..3b5f62b3 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -6,17 +6,17 @@ import ( "path/filepath" "sync" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/resolver" - "github.com/Dreamacro/clash/config" - "github.com/Dreamacro/clash/constant" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/hub/executor" - P "github.com/Dreamacro/clash/listener" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/config" + "github.com/metacubex/mihomo/constant" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/hub/executor" + P "github.com/metacubex/mihomo/listener" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/connections.go b/hub/route/connections.go index 67d5afa3..e0ff2426 100644 --- a/hub/route/connections.go +++ b/hub/route/connections.go @@ -7,7 +7,7 @@ import ( "strconv" "time" - "github.com/Dreamacro/clash/tunnel/statistic" + "github.com/metacubex/mihomo/tunnel/statistic" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/ctxkeys.go b/hub/route/ctxkeys.go index 56370192..6883b208 100644 --- a/hub/route/ctxkeys.go +++ b/hub/route/ctxkeys.go @@ -10,5 +10,5 @@ var ( type contextKey string func (c contextKey) String() string { - return "clash context key " + string(c) + return "mihomo context key " + string(c) } diff --git a/hub/route/dns.go b/hub/route/dns.go index 2918b059..1762c947 100644 --- a/hub/route/dns.go +++ b/hub/route/dns.go @@ -5,7 +5,7 @@ import ( "math" "net/http" - "github.com/Dreamacro/clash/component/resolver" + "github.com/metacubex/mihomo/component/resolver" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/groups.go b/hub/route/groups.go index c82207f0..e36b8ab0 100644 --- a/hub/route/groups.go +++ b/hub/route/groups.go @@ -8,11 +8,11 @@ import ( "strconv" "time" - "github.com/Dreamacro/clash/adapter" - "github.com/Dreamacro/clash/adapter/outboundgroup" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/tunnel" ) func GroupRouter() http.Handler { diff --git a/hub/route/provider.go b/hub/route/provider.go index c050a9f1..a8611a79 100644 --- a/hub/route/provider.go +++ b/hub/route/provider.go @@ -4,9 +4,9 @@ import ( "context" "net/http" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/tunnel" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/proxies.go b/hub/route/proxies.go index c1e30b21..759e64d2 100644 --- a/hub/route/proxies.go +++ b/hub/route/proxies.go @@ -7,12 +7,12 @@ import ( "strconv" "time" - "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" + "github.com/metacubex/mihomo/adapter" + "github.com/metacubex/mihomo/adapter/outboundgroup" + "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/profile/cachefile" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/restart.go b/hub/route/restart.go index a907021f..49d7e517 100644 --- a/hub/route/restart.go +++ b/hub/route/restart.go @@ -8,8 +8,8 @@ import ( "runtime" "syscall" - "github.com/Dreamacro/clash/hub/executor" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/hub/executor" + "github.com/metacubex/mihomo/log" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/rules.go b/hub/route/rules.go index 51f8f01c..43d33299 100644 --- a/hub/route/rules.go +++ b/hub/route/rules.go @@ -1,10 +1,10 @@ package route import ( - "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/constant" "net/http" - "github.com/Dreamacro/clash/tunnel" + "github.com/metacubex/mihomo/tunnel" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/route/server.go b/hub/route/server.go index 93afd989..d510e986 100644 --- a/hub/route/server.go +++ b/hub/route/server.go @@ -11,12 +11,12 @@ import ( "strings" "time" - "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/metacubex/mihomo/adapter/inbound" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel/statistic" "github.com/go-chi/chi/v5" "github.com/go-chi/chi/v5/middleware" @@ -189,7 +189,7 @@ func authentication(next http.Handler) http.Handler { } func hello(w http.ResponseWriter, r *http.Request) { - render.JSON(w, r, render.M{"hello": "clash.meta"}) + render.JSON(w, r, render.M{"hello": "mihomo"}) } func traffic(w http.ResponseWriter, r *http.Request) { diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index 7b486ee3..ea371798 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -6,9 +6,9 @@ import ( "net/http" "os" - "github.com/Dreamacro/clash/config" - "github.com/Dreamacro/clash/hub/updater" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/config" + "github.com/metacubex/mihomo/hub/updater" + "github.com/metacubex/mihomo/log" "github.com/go-chi/chi/v5" "github.com/go-chi/render" diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 1a930c03..a3bc9a42 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -15,15 +15,15 @@ import ( "sync" "time" - clashHttp "github.com/Dreamacro/clash/component/http" - "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + mihomoHttp "github.com/metacubex/mihomo/component/http" + "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/klauspost/cpuid/v2" ) // modify from https://github.com/AdguardTeam/AdGuardHome/blob/595484e0b3fb4c457f9bb727a6b94faa78a66c5f/internal/updater/updater.go -// Updater is the Clash.Meta updater. +// Updater is the mihomo updater. var ( goarm string gomips string @@ -41,8 +41,8 @@ var ( backupExeName string // 备份文件名 updateExeName string // 更新后的可执行文件 - baseURL string = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/clash.meta" - versionURL string = "https://github.com/MetaCubeX/Clash.Meta/releases/download/Prerelease-Alpha/version.txt" + baseURL string = "https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/mihomo" + versionURL string = "https://github.com/MetaCubeX/mihomo/releases/download/Prerelease-Alpha/version.txt" packageURL string latestVersion string ) @@ -135,9 +135,9 @@ func prepare(exePath string) (err error) { backupDir = filepath.Join(workDir, "meta-backup") if runtime.GOOS == "windows" { - updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible + ".exe" + updateExeName = "mihomo" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible + ".exe" } else { - updateExeName = "clash.meta" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible + updateExeName = "mihomo" + "-" + runtime.GOOS + "-" + runtime.GOARCH + amd64Compatible } log.Infoln("updateExeName: %s ", updateExeName) @@ -231,7 +231,7 @@ const MaxPackageFileSize = 32 * 1024 * 1024 func downloadPackageFile() (err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, packageURL, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return fmt.Errorf("http request failed: %w", err) } @@ -412,7 +412,7 @@ func copyFile(src, dst string) error { func getLatestVersion() (version string, err error) { ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() - resp, err := clashHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {"clash"}}, nil) + resp, err := mihomoHttp.HttpRequest(ctx, versionURL, http.MethodGet, http.Header{"User-Agent": {"mihomo"}}, nil) if err != nil { return "", fmt.Errorf("get Latest Version fail: %w", err) } diff --git a/listener/auth/auth.go b/listener/auth/auth.go index 70473114..46f552b8 100644 --- a/listener/auth/auth.go +++ b/listener/auth/auth.go @@ -1,7 +1,7 @@ package auth import ( - "github.com/Dreamacro/clash/component/auth" + "github.com/metacubex/mihomo/component/auth" ) var authenticator auth.Authenticator diff --git a/listener/autoredir/tcp.go b/listener/autoredir/tcp.go index 57df45f3..2b21b087 100644 --- a/listener/autoredir/tcp.go +++ b/listener/autoredir/tcp.go @@ -4,11 +4,11 @@ import ( "net" "net/netip" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/config/tun.go b/listener/config/tun.go index 3f151d1e..6db1fd66 100644 --- a/listener/config/tun.go +++ b/listener/config/tun.go @@ -3,7 +3,7 @@ package config import ( "net/netip" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) func StringSliceToNetipPrefixSlice(ss []string) ([]netip.Prefix, error) { diff --git a/listener/http/client.go b/listener/http/client.go index 84c284ff..c35cadad 100644 --- a/listener/http/client.go +++ b/listener/http/client.go @@ -7,9 +7,9 @@ import ( "net/http" "time" - "github.com/Dreamacro/clash/adapter/inbound" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) func newClient(srcConn net.Conn, tunnel C.Tunnel, additions ...inbound.Addition) *http.Client { diff --git a/listener/http/proxy.go b/listener/http/proxy.go index fa1d8f88..76da4d95 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -6,12 +6,12 @@ import ( "net/http" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/cache" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - authStore "github.com/Dreamacro/clash/listener/auth" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/cache" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + authStore "github.com/metacubex/mihomo/listener/auth" + "github.com/metacubex/mihomo/log" ) func HandleConn(c net.Conn, tunnel C.Tunnel, cache *cache.LruCache[string, bool], additions ...inbound.Addition) { diff --git a/listener/http/server.go b/listener/http/server.go index 0377d3b6..a75e2092 100644 --- a/listener/http/server.go +++ b/listener/http/server.go @@ -3,9 +3,9 @@ package http import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/cache" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/cache" + C "github.com/metacubex/mihomo/constant" ) type Listener struct { diff --git a/listener/http/upgrade.go b/listener/http/upgrade.go index 6e4f063d..8a6291d1 100644 --- a/listener/http/upgrade.go +++ b/listener/http/upgrade.go @@ -7,10 +7,10 @@ import ( "net/http" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) func isUpgradeRequest(req *http.Request) bool { diff --git a/listener/inbound/base.go b/listener/inbound/base.go index 83695bb1..e8f860a0 100644 --- a/listener/inbound/base.go +++ b/listener/inbound/base.go @@ -6,8 +6,8 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/adapter/inbound" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/adapter/inbound" + C "github.com/metacubex/mihomo/constant" ) type Base struct { diff --git a/listener/inbound/http.go b/listener/inbound/http.go index 99577177..f5301f46 100644 --- a/listener/inbound/http.go +++ b/listener/inbound/http.go @@ -1,9 +1,9 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/http" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/http" + "github.com/metacubex/mihomo/log" ) type HTTPOption struct { diff --git a/listener/inbound/hysteria2.go b/listener/inbound/hysteria2.go index df537a41..112d03f8 100644 --- a/listener/inbound/hysteria2.go +++ b/listener/inbound/hysteria2.go @@ -1,10 +1,10 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing_hysteria2" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing_hysteria2" + "github.com/metacubex/mihomo/log" ) type Hysteria2Option struct { diff --git a/listener/inbound/mixed.go b/listener/inbound/mixed.go index ce445bda..fc643821 100644 --- a/listener/inbound/mixed.go +++ b/listener/inbound/mixed.go @@ -3,11 +3,11 @@ package inbound import ( "fmt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" - "github.com/Dreamacro/clash/listener/mixed" - "github.com/Dreamacro/clash/listener/socks" + "github.com/metacubex/mihomo/listener/mixed" + "github.com/metacubex/mihomo/listener/socks" ) type MixedOption struct { diff --git a/listener/inbound/redir.go b/listener/inbound/redir.go index 085bf3a8..ee090ade 100644 --- a/listener/inbound/redir.go +++ b/listener/inbound/redir.go @@ -1,9 +1,9 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/redir" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/redir" + "github.com/metacubex/mihomo/log" ) type RedirOption struct { diff --git a/listener/inbound/shadowsocks.go b/listener/inbound/shadowsocks.go index fa5b3082..cb32dcfb 100644 --- a/listener/inbound/shadowsocks.go +++ b/listener/inbound/shadowsocks.go @@ -1,10 +1,10 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing_shadowsocks" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing_shadowsocks" + "github.com/metacubex/mihomo/log" ) type ShadowSocksOption struct { diff --git a/listener/inbound/socks.go b/listener/inbound/socks.go index 09580a57..7e10d93a 100644 --- a/listener/inbound/socks.go +++ b/listener/inbound/socks.go @@ -2,9 +2,9 @@ package inbound import ( "fmt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/socks" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/socks" + "github.com/metacubex/mihomo/log" ) type SocksOption struct { diff --git a/listener/inbound/tproxy.go b/listener/inbound/tproxy.go index 682188f5..acc8cb5e 100644 --- a/listener/inbound/tproxy.go +++ b/listener/inbound/tproxy.go @@ -3,9 +3,9 @@ package inbound import ( "fmt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/tproxy" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/tproxy" + "github.com/metacubex/mihomo/log" ) type TProxyOption struct { diff --git a/listener/inbound/tuic.go b/listener/inbound/tuic.go index e7b51392..c2a73b84 100644 --- a/listener/inbound/tuic.go +++ b/listener/inbound/tuic.go @@ -1,10 +1,10 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/tuic" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/tuic" + "github.com/metacubex/mihomo/log" ) type TuicOption struct { diff --git a/listener/inbound/tun.go b/listener/inbound/tun.go index 472269d6..d1044b8e 100644 --- a/listener/inbound/tun.go +++ b/listener/inbound/tun.go @@ -4,10 +4,10 @@ import ( "errors" "strings" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing_tun" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing_tun" + "github.com/metacubex/mihomo/log" ) type TunOption struct { diff --git a/listener/inbound/tunnel.go b/listener/inbound/tunnel.go index 2af663a5..2dfaac74 100644 --- a/listener/inbound/tunnel.go +++ b/listener/inbound/tunnel.go @@ -3,9 +3,9 @@ package inbound import ( "fmt" - C "github.com/Dreamacro/clash/constant" - LT "github.com/Dreamacro/clash/listener/tunnel" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LT "github.com/metacubex/mihomo/listener/tunnel" + "github.com/metacubex/mihomo/log" ) type TunnelOption struct { diff --git a/listener/inbound/vmess.go b/listener/inbound/vmess.go index 3f516198..3508aa3c 100644 --- a/listener/inbound/vmess.go +++ b/listener/inbound/vmess.go @@ -1,10 +1,10 @@ package inbound import ( - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing_vmess" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing_vmess" + "github.com/metacubex/mihomo/log" ) type VmessOption struct { diff --git a/listener/inner/tcp.go b/listener/inner/tcp.go index 8973c431..373fd2b4 100644 --- a/listener/inner/tcp.go +++ b/listener/inner/tcp.go @@ -6,7 +6,7 @@ import ( "net/netip" "strconv" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) var tunnel C.Tunnel @@ -26,7 +26,7 @@ func HandleTcp(address string) (conn net.Conn, err error) { metadata.NetWork = C.TCP metadata.Type = C.INNER metadata.DNSMode = C.DNSNormal - metadata.Process = C.ClashName + metadata.Process = C.MihomoName if h, port, err := net.SplitHostPort(address); err == nil { if port, err := strconv.ParseUint(port, 10, 16); err == nil { metadata.DstPort = uint16(port) diff --git a/listener/listener.go b/listener/listener.go index a6bbdbf5..903cb64b 100644 --- a/listener/listener.go +++ b/listener/listener.go @@ -9,22 +9,22 @@ import ( "strings" "sync" - "github.com/Dreamacro/clash/component/ebpf" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/autoredir" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/http" - "github.com/Dreamacro/clash/listener/mixed" - "github.com/Dreamacro/clash/listener/redir" - embedSS "github.com/Dreamacro/clash/listener/shadowsocks" - "github.com/Dreamacro/clash/listener/sing_shadowsocks" - "github.com/Dreamacro/clash/listener/sing_tun" - "github.com/Dreamacro/clash/listener/sing_vmess" - "github.com/Dreamacro/clash/listener/socks" - "github.com/Dreamacro/clash/listener/tproxy" - "github.com/Dreamacro/clash/listener/tuic" - LT "github.com/Dreamacro/clash/listener/tunnel" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/ebpf" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/autoredir" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/http" + "github.com/metacubex/mihomo/listener/mixed" + "github.com/metacubex/mihomo/listener/redir" + embedSS "github.com/metacubex/mihomo/listener/shadowsocks" + "github.com/metacubex/mihomo/listener/sing_shadowsocks" + "github.com/metacubex/mihomo/listener/sing_tun" + "github.com/metacubex/mihomo/listener/sing_vmess" + "github.com/metacubex/mihomo/listener/socks" + "github.com/metacubex/mihomo/listener/tproxy" + "github.com/metacubex/mihomo/listener/tuic" + LT "github.com/metacubex/mihomo/listener/tunnel" + "github.com/metacubex/mihomo/log" "github.com/samber/lo" ) diff --git a/listener/mixed/mixed.go b/listener/mixed/mixed.go index d2ede096..97d1407c 100644 --- a/listener/mixed/mixed.go +++ b/listener/mixed/mixed.go @@ -3,14 +3,14 @@ package mixed import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/cache" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/listener/http" - "github.com/Dreamacro/clash/listener/socks" - "github.com/Dreamacro/clash/transport/socks4" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/cache" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/listener/http" + "github.com/metacubex/mihomo/listener/socks" + "github.com/metacubex/mihomo/transport/socks4" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/parse.go b/listener/parse.go index b0fac86a..1c8b6463 100644 --- a/listener/parse.go +++ b/listener/parse.go @@ -3,9 +3,9 @@ package listener import ( "fmt" - "github.com/Dreamacro/clash/common/structure" - C "github.com/Dreamacro/clash/constant" - IN "github.com/Dreamacro/clash/listener/inbound" + "github.com/metacubex/mihomo/common/structure" + C "github.com/metacubex/mihomo/constant" + IN "github.com/metacubex/mihomo/listener/inbound" ) func ParseListener(mapping map[string]any) (C.InboundListener, error) { diff --git a/listener/redir/tcp.go b/listener/redir/tcp.go index 6419760f..8474a8e2 100644 --- a/listener/redir/tcp.go +++ b/listener/redir/tcp.go @@ -3,9 +3,9 @@ package redir import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" ) type Listener struct { diff --git a/listener/redir/tcp_darwin.go b/listener/redir/tcp_darwin.go index 5a2f331c..6e1821bb 100644 --- a/listener/redir/tcp_darwin.go +++ b/listener/redir/tcp_darwin.go @@ -5,7 +5,7 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) func parserPacket(c net.Conn) (socks5.Addr, error) { diff --git a/listener/redir/tcp_freebsd.go b/listener/redir/tcp_freebsd.go index 6ecb2496..9eb199f0 100644 --- a/listener/redir/tcp_freebsd.go +++ b/listener/redir/tcp_freebsd.go @@ -8,7 +8,7 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" "golang.org/x/sys/unix" ) diff --git a/listener/redir/tcp_linux.go b/listener/redir/tcp_linux.go index b65c34ee..fce74678 100644 --- a/listener/redir/tcp_linux.go +++ b/listener/redir/tcp_linux.go @@ -8,7 +8,7 @@ import ( "syscall" "unsafe" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" "golang.org/x/sys/unix" ) diff --git a/listener/redir/tcp_other.go b/listener/redir/tcp_other.go index a01550c7..ae3bebfd 100644 --- a/listener/redir/tcp_other.go +++ b/listener/redir/tcp_other.go @@ -6,7 +6,7 @@ import ( "errors" "net" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) func parserPacket(conn net.Conn) (socks5.Addr, error) { diff --git a/listener/shadowsocks/tcp.go b/listener/shadowsocks/tcp.go index 8959e6ba..c08667de 100644 --- a/listener/shadowsocks/tcp.go +++ b/listener/shadowsocks/tcp.go @@ -4,12 +4,12 @@ import ( "net" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/transport/shadowsocks/core" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/shadowsocks/udp.go b/listener/shadowsocks/udp.go index 53f5549a..4336db22 100644 --- a/listener/shadowsocks/udp.go +++ b/listener/shadowsocks/udp.go @@ -3,13 +3,13 @@ package shadowsocks import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/shadowsocks/core" + "github.com/metacubex/mihomo/transport/socks5" ) type UDPListener struct { diff --git a/listener/shadowsocks/utils.go b/listener/shadowsocks/utils.go index a732cbbe..5d6a2977 100644 --- a/listener/shadowsocks/utils.go +++ b/listener/shadowsocks/utils.go @@ -6,7 +6,7 @@ import ( "net" "net/url" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) type packet struct { diff --git a/listener/sing/context.go b/listener/sing/context.go index 4204757a..e1e8b452 100644 --- a/listener/sing/context.go +++ b/listener/sing/context.go @@ -4,7 +4,7 @@ import ( "context" "golang.org/x/exp/slices" - "github.com/Dreamacro/clash/adapter/inbound" + "github.com/metacubex/mihomo/adapter/inbound" "github.com/sagernet/sing/common/auth" ) diff --git a/listener/sing/sing.go b/listener/sing/sing.go index ff72f67d..306bd705 100644 --- a/listener/sing/sing.go +++ b/listener/sing/sing.go @@ -8,10 +8,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" vmess "github.com/metacubex/sing-vmess" mux "github.com/sagernet/sing-mux" diff --git a/listener/sing_hysteria2/server.go b/listener/sing_hysteria2/server.go index bc25ec2a..96553995 100644 --- a/listener/sing_hysteria2/server.go +++ b/listener/sing_hysteria2/server.go @@ -11,14 +11,14 @@ import ( "net/url" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/adapter/outbound" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/adapter/outbound" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" "github.com/metacubex/sing-quic/hysteria2" diff --git a/listener/sing_shadowsocks/server.go b/listener/sing_shadowsocks/server.go index 51baeaa1..5a4896af 100644 --- a/listener/sing_shadowsocks/server.go +++ b/listener/sing_shadowsocks/server.go @@ -6,15 +6,15 @@ import ( "net" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - embedSS "github.com/Dreamacro/clash/listener/shadowsocks" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/ntp" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + embedSS "github.com/metacubex/mihomo/listener/shadowsocks" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/ntp" shadowsocks "github.com/metacubex/sing-shadowsocks" "github.com/metacubex/sing-shadowsocks/shadowaead" diff --git a/listener/sing_tun/dns.go b/listener/sing_tun/dns.go index 88e3f6d6..62a15c6c 100644 --- a/listener/sing_tun/dns.go +++ b/listener/sing_tun/dns.go @@ -9,10 +9,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/component/resolver" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" D "github.com/miekg/dns" diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 0548ac41..212c3d90 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -10,13 +10,13 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/iface" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/iface" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" tun "github.com/metacubex/sing-tun" "github.com/sagernet/sing/common" diff --git a/listener/sing_tun/server_android.go b/listener/sing_tun/server_android.go index 4f85c418..ac41282d 100644 --- a/listener/sing_tun/server_android.go +++ b/listener/sing_tun/server_android.go @@ -1,7 +1,7 @@ package sing_tun import ( - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" tun "github.com/metacubex/sing-tun" "github.com/sagernet/netlink" "golang.org/x/sys/unix" diff --git a/listener/sing_tun/server_windows.go b/listener/sing_tun/server_windows.go index 9584f32f..8da21287 100644 --- a/listener/sing_tun/server_windows.go +++ b/listener/sing_tun/server_windows.go @@ -3,7 +3,7 @@ package sing_tun import ( "time" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" tun "github.com/metacubex/sing-tun" ) diff --git a/listener/sing_vmess/server.go b/listener/sing_vmess/server.go index 014e86f9..e790e3bc 100644 --- a/listener/sing_vmess/server.go +++ b/listener/sing_vmess/server.go @@ -8,13 +8,13 @@ import ( "net/url" "strings" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/ntp" - clashVMess "github.com/Dreamacro/clash/transport/vmess" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/ntp" + mihomoVMess "github.com/metacubex/mihomo/transport/vmess" vmess "github.com/metacubex/sing-vmess" "github.com/sagernet/sing/common" @@ -81,7 +81,7 @@ func New(config LC.VmessServer, tunnel C.Tunnel, additions ...inbound.Addition) if config.WsPath != "" { httpMux = http.NewServeMux() httpMux.HandleFunc(config.WsPath, func(w http.ResponseWriter, r *http.Request) { - conn, err := clashVMess.StreamUpgradedWebsocketConn(w, r) + conn, err := mihomoVMess.StreamUpgradedWebsocketConn(w, r) if err != nil { http.Error(w, err.Error(), 500) return diff --git a/listener/socks/tcp.go b/listener/socks/tcp.go index 9448f269..c8c33e7b 100644 --- a/listener/socks/tcp.go +++ b/listener/socks/tcp.go @@ -4,12 +4,12 @@ import ( "io" "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - authStore "github.com/Dreamacro/clash/listener/auth" - "github.com/Dreamacro/clash/transport/socks4" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + authStore "github.com/metacubex/mihomo/listener/auth" + "github.com/metacubex/mihomo/transport/socks4" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/socks/udp.go b/listener/socks/udp.go index 2f786e95..ef31b20e 100644 --- a/listener/socks/udp.go +++ b/listener/socks/udp.go @@ -3,12 +3,12 @@ package socks import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/socks5" ) type UDPListener struct { diff --git a/listener/socks/utils.go b/listener/socks/utils.go index 3456b595..d113d45c 100644 --- a/listener/socks/utils.go +++ b/listener/socks/utils.go @@ -3,7 +3,7 @@ package socks import ( "net" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/transport/socks5" ) type packet struct { diff --git a/listener/tproxy/packet.go b/listener/tproxy/packet.go index 24fff09a..e4852665 100644 --- a/listener/tproxy/packet.go +++ b/listener/tproxy/packet.go @@ -6,10 +6,10 @@ import ( "net" "net/netip" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type packet struct { diff --git a/listener/tproxy/tproxy.go b/listener/tproxy/tproxy.go index 319d5c30..efb144a9 100644 --- a/listener/tproxy/tproxy.go +++ b/listener/tproxy/tproxy.go @@ -3,10 +3,10 @@ package tproxy import ( "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/tproxy/tproxy_iptables.go b/listener/tproxy/tproxy_iptables.go index 31ac24e5..5ddd7b4c 100644 --- a/listener/tproxy/tproxy_iptables.go +++ b/listener/tproxy/tproxy_iptables.go @@ -6,9 +6,9 @@ import ( "net" "runtime" - "github.com/Dreamacro/clash/common/cmd" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/cmd" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/log" ) var ( @@ -48,25 +48,25 @@ func SetTProxyIPTables(ifname string, bypass []string, tport uint16, dport uint1 execCmd(fmt.Sprintf("iptables -t filter -A FORWARD -i %s -o %s -j ACCEPT", interfaceName, interfaceName)) } - // set clash divert - execCmd("iptables -t mangle -N clash_divert") - execCmd("iptables -t mangle -F clash_divert") - execCmd(fmt.Sprintf("iptables -t mangle -A clash_divert -j MARK --set-mark %s", PROXY_FWMARK)) - execCmd("iptables -t mangle -A clash_divert -j ACCEPT") + // set mihomo divert + execCmd("iptables -t mangle -N mihomo_divert") + execCmd("iptables -t mangle -F mihomo_divert") + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_divert -j MARK --set-mark %s", PROXY_FWMARK)) + execCmd("iptables -t mangle -A mihomo_divert -j ACCEPT") // set pre routing - execCmd("iptables -t mangle -N clash_prerouting") - execCmd("iptables -t mangle -F clash_prerouting") - execCmd("iptables -t mangle -A clash_prerouting -s 172.17.0.0/16 -j RETURN") - execCmd("iptables -t mangle -A clash_prerouting -p udp --dport 53 -j ACCEPT") - execCmd("iptables -t mangle -A clash_prerouting -p tcp --dport 53 -j ACCEPT") - execCmd("iptables -t mangle -A clash_prerouting -m addrtype --dst-type LOCAL -j RETURN") - addLocalnetworkToChain("clash_prerouting", bypass) - execCmd("iptables -t mangle -A clash_prerouting -p tcp -m socket -j clash_divert") - execCmd("iptables -t mangle -A clash_prerouting -p udp -m socket -j clash_divert") - execCmd(fmt.Sprintf("iptables -t mangle -A clash_prerouting -p tcp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) - execCmd(fmt.Sprintf("iptables -t mangle -A clash_prerouting -p udp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) - execCmd("iptables -t mangle -A PREROUTING -j clash_prerouting") + execCmd("iptables -t mangle -N mihomo_prerouting") + execCmd("iptables -t mangle -F mihomo_prerouting") + execCmd("iptables -t mangle -A mihomo_prerouting -s 172.17.0.0/16 -j RETURN") + execCmd("iptables -t mangle -A mihomo_prerouting -p udp --dport 53 -j ACCEPT") + execCmd("iptables -t mangle -A mihomo_prerouting -p tcp --dport 53 -j ACCEPT") + execCmd("iptables -t mangle -A mihomo_prerouting -m addrtype --dst-type LOCAL -j RETURN") + addLocalnetworkToChain("mihomo_prerouting", bypass) + execCmd("iptables -t mangle -A mihomo_prerouting -p tcp -m socket -j mihomo_divert") + execCmd("iptables -t mangle -A mihomo_prerouting -p udp -m socket -j mihomo_divert") + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_prerouting -p tcp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_prerouting -p udp -j TPROXY --on-port %d --tproxy-mark %s/%s", tProxyPort, PROXY_FWMARK, PROXY_FWMARK)) + execCmd("iptables -t mangle -A PREROUTING -j mihomo_prerouting") execCmd(fmt.Sprintf("iptables -t nat -I PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p tcp --dport 53 -j REDIRECT --to %d", dnsPort)) execCmd(fmt.Sprintf("iptables -t nat -I PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p udp --dport 53 -j REDIRECT --to %d", dnsPort)) @@ -77,27 +77,27 @@ func SetTProxyIPTables(ifname string, bypass []string, tport uint16, dport uint1 } // set output - execCmd("iptables -t mangle -N clash_output") - execCmd("iptables -t mangle -F clash_output") - execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) - execCmd("iptables -t mangle -A clash_output -p udp -m multiport --dports 53,123,137 -j ACCEPT") - execCmd("iptables -t mangle -A clash_output -p tcp --dport 53 -j ACCEPT") - execCmd("iptables -t mangle -A clash_output -m addrtype --dst-type LOCAL -j RETURN") - execCmd("iptables -t mangle -A clash_output -m addrtype --dst-type BROADCAST -j RETURN") - addLocalnetworkToChain("clash_output", bypass) - execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -p tcp -j MARK --set-mark %s", PROXY_FWMARK)) - execCmd(fmt.Sprintf("iptables -t mangle -A clash_output -p udp -j MARK --set-mark %s", PROXY_FWMARK)) - execCmd(fmt.Sprintf("iptables -t mangle -I OUTPUT -o %s -j clash_output", interfaceName)) + execCmd("iptables -t mangle -N mihomo_output") + execCmd("iptables -t mangle -F mihomo_output") + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) + execCmd("iptables -t mangle -A mihomo_output -p udp -m multiport --dports 53,123,137 -j ACCEPT") + execCmd("iptables -t mangle -A mihomo_output -p tcp --dport 53 -j ACCEPT") + execCmd("iptables -t mangle -A mihomo_output -m addrtype --dst-type LOCAL -j RETURN") + execCmd("iptables -t mangle -A mihomo_output -m addrtype --dst-type BROADCAST -j RETURN") + addLocalnetworkToChain("mihomo_output", bypass) + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_output -p tcp -j MARK --set-mark %s", PROXY_FWMARK)) + execCmd(fmt.Sprintf("iptables -t mangle -A mihomo_output -p udp -j MARK --set-mark %s", PROXY_FWMARK)) + execCmd(fmt.Sprintf("iptables -t mangle -I OUTPUT -o %s -j mihomo_output", interfaceName)) // set dns output - execCmd("iptables -t nat -N clash_dns_output") - execCmd("iptables -t nat -F clash_dns_output") - execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) - execCmd("iptables -t nat -A clash_dns_output -s 172.17.0.0/16 -j RETURN") - execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -p udp -j REDIRECT --to-ports %d", dnsPort)) - execCmd(fmt.Sprintf("iptables -t nat -A clash_dns_output -p tcp -j REDIRECT --to-ports %d", dnsPort)) - execCmd("iptables -t nat -I OUTPUT -p tcp --dport 53 -j clash_dns_output") - execCmd("iptables -t nat -I OUTPUT -p udp --dport 53 -j clash_dns_output") + execCmd("iptables -t nat -N mihomo_dns_output") + execCmd("iptables -t nat -F mihomo_dns_output") + execCmd(fmt.Sprintf("iptables -t nat -A mihomo_dns_output -m mark --mark %#x -j RETURN", dialer.DefaultRoutingMark.Load())) + execCmd("iptables -t nat -A mihomo_dns_output -s 172.17.0.0/16 -j RETURN") + execCmd(fmt.Sprintf("iptables -t nat -A mihomo_dns_output -p udp -j REDIRECT --to-ports %d", dnsPort)) + execCmd(fmt.Sprintf("iptables -t nat -A mihomo_dns_output -p tcp -j REDIRECT --to-ports %d", dnsPort)) + execCmd("iptables -t nat -I OUTPUT -p tcp --dport 53 -j mihomo_dns_output") + execCmd("iptables -t nat -I OUTPUT -p udp --dport 53 -j mihomo_dns_output") return nil } @@ -113,7 +113,7 @@ func CleanupTProxyIPTables() { dialer.DefaultRoutingMark.Store(0) } - if _, err := cmd.ExecCmd("iptables -t mangle -L clash_divert"); err != nil { + if _, err := cmd.ExecCmd("iptables -t mangle -L mihomo_divert"); err != nil { return } @@ -132,7 +132,7 @@ func CleanupTProxyIPTables() { // clean PREROUTING execCmd(fmt.Sprintf("iptables -t nat -D PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p tcp --dport 53 -j REDIRECT --to %d", dnsPort)) execCmd(fmt.Sprintf("iptables -t nat -D PREROUTING ! -s 172.17.0.0/16 ! -d 127.0.0.0/8 -p udp --dport 53 -j REDIRECT --to %d", dnsPort)) - execCmd("iptables -t mangle -D PREROUTING -j clash_prerouting") + execCmd("iptables -t mangle -D PREROUTING -j mihomo_prerouting") // clean POSTROUTING if interfaceName != "lo" { @@ -140,19 +140,19 @@ func CleanupTProxyIPTables() { } // clean OUTPUT - execCmd(fmt.Sprintf("iptables -t mangle -D OUTPUT -o %s -j clash_output", interfaceName)) - execCmd("iptables -t nat -D OUTPUT -p tcp --dport 53 -j clash_dns_output") - execCmd("iptables -t nat -D OUTPUT -p udp --dport 53 -j clash_dns_output") + execCmd(fmt.Sprintf("iptables -t mangle -D OUTPUT -o %s -j mihomo_output", interfaceName)) + execCmd("iptables -t nat -D OUTPUT -p tcp --dport 53 -j mihomo_dns_output") + execCmd("iptables -t nat -D OUTPUT -p udp --dport 53 -j mihomo_dns_output") // clean chain - execCmd("iptables -t mangle -F clash_prerouting") - execCmd("iptables -t mangle -X clash_prerouting") - execCmd("iptables -t mangle -F clash_divert") - execCmd("iptables -t mangle -X clash_divert") - execCmd("iptables -t mangle -F clash_output") - execCmd("iptables -t mangle -X clash_output") - execCmd("iptables -t nat -F clash_dns_output") - execCmd("iptables -t nat -X clash_dns_output") + execCmd("iptables -t mangle -F mihomo_prerouting") + execCmd("iptables -t mangle -X mihomo_prerouting") + execCmd("iptables -t mangle -F mihomo_divert") + execCmd("iptables -t mangle -X mihomo_divert") + execCmd("iptables -t mangle -F mihomo_output") + execCmd("iptables -t mangle -X mihomo_output") + execCmd("iptables -t nat -F mihomo_dns_output") + execCmd("iptables -t nat -X mihomo_dns_output") interfaceName = "" tProxyPort = 0 diff --git a/listener/tproxy/udp.go b/listener/tproxy/udp.go index c8460def..aa0fee19 100644 --- a/listener/tproxy/udp.go +++ b/listener/tproxy/udp.go @@ -4,10 +4,10 @@ import ( "net" "net/netip" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type UDPListener struct { diff --git a/listener/tuic/server.go b/listener/tuic/server.go index 544f1328..7fa7b18e 100644 --- a/listener/tuic/server.go +++ b/listener/tuic/server.go @@ -7,15 +7,15 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/adapter/inbound" - CN "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/sockopt" - C "github.com/Dreamacro/clash/constant" - LC "github.com/Dreamacro/clash/listener/config" - "github.com/Dreamacro/clash/listener/sing" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/tuic" + "github.com/metacubex/mihomo/adapter/inbound" + CN "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/sockopt" + C "github.com/metacubex/mihomo/constant" + LC "github.com/metacubex/mihomo/listener/config" + "github.com/metacubex/mihomo/listener/sing" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/tuic" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/listener/tunnel/packet.go b/listener/tunnel/packet.go index 35601e38..165004d6 100644 --- a/listener/tunnel/packet.go +++ b/listener/tunnel/packet.go @@ -3,7 +3,7 @@ package tunnel import ( "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type packet struct { diff --git a/listener/tunnel/tcp.go b/listener/tunnel/tcp.go index 9fca14dd..794dc8ac 100644 --- a/listener/tunnel/tcp.go +++ b/listener/tunnel/tcp.go @@ -4,10 +4,10 @@ import ( "fmt" "net" - "github.com/Dreamacro/clash/adapter/inbound" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type Listener struct { diff --git a/listener/tunnel/udp.go b/listener/tunnel/udp.go index 00d61663..f7d980ab 100644 --- a/listener/tunnel/udp.go +++ b/listener/tunnel/udp.go @@ -4,10 +4,10 @@ import ( "fmt" "net" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type PacketConn struct { diff --git a/log/log.go b/log/log.go index acddeaff..d431dcb1 100644 --- a/log/log.go +++ b/log/log.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/Dreamacro/clash/common/observable" + "github.com/metacubex/mihomo/common/observable" log "github.com/sirupsen/logrus" ) diff --git a/main.go b/main.go index d41450b6..fd1e065c 100644 --- a/main.go +++ b/main.go @@ -3,7 +3,7 @@ package main import ( "flag" "fmt" - "github.com/Dreamacro/clash/constant/features" + "github.com/metacubex/mihomo/constant/features" "os" "os/signal" "path/filepath" @@ -11,11 +11,11 @@ import ( "strings" "syscall" - "github.com/Dreamacro/clash/config" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/hub" - "github.com/Dreamacro/clash/hub/executor" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/config" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/hub" + "github.com/metacubex/mihomo/hub/executor" + "github.com/metacubex/mihomo/log" "go.uber.org/automaxprocs/maxprocs" ) @@ -38,7 +38,7 @@ func init() { flag.StringVar(&externalController, "ext-ctl", os.Getenv("CLASH_OVERRIDE_EXTERNAL_CONTROLLER"), "override external controller address") flag.StringVar(&secret, "secret", os.Getenv("CLASH_OVERRIDE_SECRET"), "override secret for RESTful API") flag.BoolVar(&geodataMode, "m", false, "set geodata mode") - flag.BoolVar(&version, "v", false, "show current version of clash") + flag.BoolVar(&version, "v", false, "show current version of mihomo") flag.BoolVar(&testConfig, "t", false, "test configuration and exit") flag.Parse() } @@ -46,7 +46,7 @@ func init() { func main() { _, _ = maxprocs.Set(maxprocs.Logger(func(string, ...any) {})) if version { - fmt.Printf("Clash Meta %s %s %s with %s %s\n", + fmt.Printf("Mihomo Meta %s %s %s with %s %s\n", C.Version, runtime.GOOS, runtime.GOARCH, runtime.Version(), C.BuildTime) if len(features.TAGS) != 0 { fmt.Printf("Use tags: %s\n", strings.Join(features.TAGS, ", ")) diff --git a/ntp/service.go b/ntp/service.go index c5506197..4c95045a 100644 --- a/ntp/service.go +++ b/ntp/service.go @@ -5,9 +5,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/component/dialer" - "github.com/Dreamacro/clash/component/proxydialer" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/dialer" + "github.com/metacubex/mihomo/component/proxydialer" + "github.com/metacubex/mihomo/log" M "github.com/sagernet/sing/common/metadata" "github.com/sagernet/sing/common/ntp" diff --git a/rules/common/domain.go b/rules/common/domain.go index 35a06a70..23f21185 100644 --- a/rules/common/domain.go +++ b/rules/common/domain.go @@ -3,7 +3,7 @@ package common import ( "strings" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type Domain struct { diff --git a/rules/common/domain_keyword.go b/rules/common/domain_keyword.go index d945f200..ec01293a 100644 --- a/rules/common/domain_keyword.go +++ b/rules/common/domain_keyword.go @@ -3,7 +3,7 @@ package common import ( "strings" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type DomainKeyword struct { diff --git a/rules/common/domain_suffix.go b/rules/common/domain_suffix.go index b13036a3..b7b1794d 100644 --- a/rules/common/domain_suffix.go +++ b/rules/common/domain_suffix.go @@ -3,7 +3,7 @@ package common import ( "strings" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type DomainSuffix struct { diff --git a/rules/common/final.go b/rules/common/final.go index 8aa5ed7b..d3a415a0 100644 --- a/rules/common/final.go +++ b/rules/common/final.go @@ -1,7 +1,7 @@ package common import ( - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type Match struct { diff --git a/rules/common/geoip.go b/rules/common/geoip.go index 2f96c2ef..3a29fae4 100644 --- a/rules/common/geoip.go +++ b/rules/common/geoip.go @@ -4,12 +4,12 @@ import ( "fmt" "strings" - "github.com/Dreamacro/clash/component/geodata" - "github.com/Dreamacro/clash/component/geodata/router" - "github.com/Dreamacro/clash/component/mmdb" - "github.com/Dreamacro/clash/component/resolver" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata" + "github.com/metacubex/mihomo/component/geodata/router" + "github.com/metacubex/mihomo/component/mmdb" + "github.com/metacubex/mihomo/component/resolver" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type GEOIP struct { diff --git a/rules/common/geosite.go b/rules/common/geosite.go index e89dc19b..e9b19d0e 100644 --- a/rules/common/geosite.go +++ b/rules/common/geosite.go @@ -3,12 +3,12 @@ package common import ( "fmt" - "github.com/Dreamacro/clash/component/geodata" - _ "github.com/Dreamacro/clash/component/geodata/memconservative" - "github.com/Dreamacro/clash/component/geodata/router" - _ "github.com/Dreamacro/clash/component/geodata/standard" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/geodata" + _ "github.com/metacubex/mihomo/component/geodata/memconservative" + "github.com/metacubex/mihomo/component/geodata/router" + _ "github.com/metacubex/mihomo/component/geodata/standard" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type GEOSITE struct { diff --git a/rules/common/in_name.go b/rules/common/in_name.go index 1e2abe15..9b14ef6a 100644 --- a/rules/common/in_name.go +++ b/rules/common/in_name.go @@ -2,7 +2,7 @@ package common import ( "fmt" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "strings" ) diff --git a/rules/common/in_type.go b/rules/common/in_type.go index 453045d8..fc73b208 100644 --- a/rules/common/in_type.go +++ b/rules/common/in_type.go @@ -2,7 +2,7 @@ package common import ( "fmt" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "strings" ) diff --git a/rules/common/in_user.go b/rules/common/in_user.go index 24f4b2e5..ebe881af 100644 --- a/rules/common/in_user.go +++ b/rules/common/in_user.go @@ -2,7 +2,7 @@ package common import ( "fmt" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "strings" ) diff --git a/rules/common/ipcidr.go b/rules/common/ipcidr.go index 4cdf9106..663c9397 100644 --- a/rules/common/ipcidr.go +++ b/rules/common/ipcidr.go @@ -3,7 +3,7 @@ package common import ( "net/netip" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type IPCIDROption func(*IPCIDR) diff --git a/rules/common/ipsuffix.go b/rules/common/ipsuffix.go index b01557dc..3251faf8 100644 --- a/rules/common/ipsuffix.go +++ b/rules/common/ipsuffix.go @@ -1,7 +1,7 @@ package common import ( - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "net/netip" ) diff --git a/rules/common/network_type.go b/rules/common/network_type.go index 1184ba89..83a332d8 100644 --- a/rules/common/network_type.go +++ b/rules/common/network_type.go @@ -2,7 +2,7 @@ package common import ( "fmt" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" "strings" ) diff --git a/rules/common/port.go b/rules/common/port.go index 334d083f..ec76cf30 100644 --- a/rules/common/port.go +++ b/rules/common/port.go @@ -3,8 +3,8 @@ package common import ( "fmt" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" ) type Port struct { diff --git a/rules/common/process.go b/rules/common/process.go index e972d2bc..ce643594 100644 --- a/rules/common/process.go +++ b/rules/common/process.go @@ -3,7 +3,7 @@ package common import ( "strings" - C "github.com/Dreamacro/clash/constant" + C "github.com/metacubex/mihomo/constant" ) type Process struct { diff --git a/rules/common/uid.go b/rules/common/uid.go index 3b20928f..de46c409 100644 --- a/rules/common/uid.go +++ b/rules/common/uid.go @@ -4,9 +4,9 @@ import ( "fmt" "runtime" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type Uid struct { diff --git a/rules/logic/logic.go b/rules/logic/logic.go index a53503df..4256a200 100644 --- a/rules/logic/logic.go +++ b/rules/logic/logic.go @@ -5,9 +5,9 @@ import ( "regexp" "strings" - "github.com/Dreamacro/clash/common/collections" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/rules/common" + "github.com/metacubex/mihomo/common/collections" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/rules/common" ) type Logic struct { diff --git a/rules/logic_test/logic_test.go b/rules/logic_test/logic_test.go index 52318b3f..e88c8578 100644 --- a/rules/logic_test/logic_test.go +++ b/rules/logic_test/logic_test.go @@ -2,10 +2,10 @@ package logic_test import ( // https://github.com/golang/go/wiki/CodeReviewComments#import-dot - . "github.com/Dreamacro/clash/rules/logic" + . "github.com/metacubex/mihomo/rules/logic" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/rules" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/rules" "github.com/stretchr/testify/assert" "testing" ) diff --git a/rules/parser.go b/rules/parser.go index df790bc3..b1baa758 100644 --- a/rules/parser.go +++ b/rules/parser.go @@ -2,10 +2,10 @@ package rules import ( "fmt" - C "github.com/Dreamacro/clash/constant" - RC "github.com/Dreamacro/clash/rules/common" - "github.com/Dreamacro/clash/rules/logic" - RP "github.com/Dreamacro/clash/rules/provider" + C "github.com/metacubex/mihomo/constant" + RC "github.com/metacubex/mihomo/rules/common" + "github.com/metacubex/mihomo/rules/logic" + RP "github.com/metacubex/mihomo/rules/provider" ) func ParseRule(tp, payload, target string, params []string, subRules map[string][]C.Rule) (parsed C.Rule, parseErr error) { diff --git a/rules/provider/classical_strategy.go b/rules/provider/classical_strategy.go index 6561f12f..f8042164 100644 --- a/rules/provider/classical_strategy.go +++ b/rules/provider/classical_strategy.go @@ -2,8 +2,8 @@ package provider import ( "fmt" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "strings" ) diff --git a/rules/provider/domain_strategy.go b/rules/provider/domain_strategy.go index d686d598..c0787d58 100644 --- a/rules/provider/domain_strategy.go +++ b/rules/provider/domain_strategy.go @@ -1,9 +1,9 @@ package provider import ( - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type domainStrategy struct { diff --git a/rules/provider/ipcidr_strategy.go b/rules/provider/ipcidr_strategy.go index f54302f1..321e901a 100644 --- a/rules/provider/ipcidr_strategy.go +++ b/rules/provider/ipcidr_strategy.go @@ -1,9 +1,9 @@ package provider import ( - "github.com/Dreamacro/clash/component/trie" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/trie" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) type ipcidrStrategy struct { diff --git a/rules/provider/parse.go b/rules/provider/parse.go index 0fbfb2cc..3a5c4fd7 100644 --- a/rules/provider/parse.go +++ b/rules/provider/parse.go @@ -5,10 +5,10 @@ import ( "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" + "github.com/metacubex/mihomo/common/structure" + "github.com/metacubex/mihomo/component/resource" + C "github.com/metacubex/mihomo/constant" + P "github.com/metacubex/mihomo/constant/provider" ) var ( diff --git a/rules/provider/provider.go b/rules/provider/provider.go index 65d21d2f..adc2e44a 100644 --- a/rules/provider/provider.go +++ b/rules/provider/provider.go @@ -9,10 +9,10 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/component/resource" - C "github.com/Dreamacro/clash/constant" - P "github.com/Dreamacro/clash/constant/provider" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/component/resource" + C "github.com/metacubex/mihomo/constant" + P "github.com/metacubex/mihomo/constant/provider" ) var ( diff --git a/rules/provider/rule_set.go b/rules/provider/rule_set.go index 45cddf6c..1d940188 100644 --- a/rules/provider/rule_set.go +++ b/rules/provider/rule_set.go @@ -2,9 +2,9 @@ package provider import ( "fmt" - C "github.com/Dreamacro/clash/constant" - P "github.com/Dreamacro/clash/constant/provider" - "github.com/Dreamacro/clash/rules/common" + C "github.com/metacubex/mihomo/constant" + P "github.com/metacubex/mihomo/constant/provider" + "github.com/metacubex/mihomo/rules/common" ) type RuleSet struct { diff --git a/test/.golangci.yaml b/test/.golangci.yaml index b65afc5e..e1fbbf76 100644 --- a/test/.golangci.yaml +++ b/test/.golangci.yaml @@ -10,7 +10,7 @@ linters-settings: gci: sections: - standard - - prefix(github.com/Dreamacro/clash) + - prefix(github.com/metacubex/mihomo) - default staticcheck: go: '1.19' diff --git a/test/README.md b/test/README.md index a95f3aea..e9fa5630 100644 --- a/test/README.md +++ b/test/README.md @@ -1,4 +1,4 @@ -## Clash testing suit +## Mihomo testing suit ### Protocol testing suit @@ -51,8 +51,8 @@ $ make test benchmark (Linux) > Cannot represent the throughput of the protocol on your machine -> but you can compare the corresponding throughput of the protocol on clash -> (change chunkSize to measure the maximum throughput of clash on your machine) +> but you can compare the corresponding throughput of the protocol on mihomo +> (change chunkSize to measure the maximum throughput of mihomo on your machine) ``` $ make benchmark diff --git a/test/clash_test.go b/test/clash_test.go index 60b99791..90ac9d22 100644 --- a/test/clash_test.go +++ b/test/clash_test.go @@ -16,13 +16,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/hub/executor" - "github.com/Dreamacro/clash/transport/socks5" "github.com/docker/docker/api/types" "github.com/docker/docker/client" "github.com/docker/go-connections/nat" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/hub/executor" + "github.com/metacubex/mihomo/transport/socks5" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -658,7 +658,7 @@ func benchmarkProxy(b *testing.B, proxy C.ProxyAdapter) { }) } -func TestClash_Basic(t *testing.T) { +func TestMihomo_Basic(t *testing.T) { basic := ` mixed-port: 10000 log-level: silent diff --git a/test/dns_test.go b/test/dns_test.go index 8e30ba98..f45ffbe0 100644 --- a/test/dns_test.go +++ b/test/dns_test.go @@ -21,7 +21,7 @@ func exchange(address, domain string, tp uint16) ([]dns.RR, error) { return r.Answer, nil } -func TestClash_DNS(t *testing.T) { +func TestMihomo_DNS(t *testing.T) { basic := ` log-level: silent dns: @@ -49,11 +49,11 @@ dns: assert.Empty(t, rr) } -func TestClash_DNSHostAndFakeIP(t *testing.T) { +func TestMihomo_DNSHostAndFakeIP(t *testing.T) { basic := ` log-level: silent hosts: - foo.clash.dev: 1.1.1.1 + foo.mihomo.dev: 1.1.1.1 dns: enable: true listen: 0.0.0.0:8553 @@ -81,7 +81,7 @@ dns: {"foo.org", "198.18.0.4"}, {"bar.org", "198.18.0.5"}, {"foo.org", "198.18.0.4"}, - {"foo.clash.dev", "1.1.1.1"}, + {"foo.mihomo.dev", "1.1.1.1"}, } for _, pair := range list { diff --git a/test/go.mod b/test/go.mod index 36fa7256..adb42a2c 100644 --- a/test/go.mod +++ b/test/go.mod @@ -1,17 +1,17 @@ -module clash-test +module mihomo-test -go 1.19 +go 1.20 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/metacubex/mihomo v0.0.0 github.com/miekg/dns v1.1.56 github.com/stretchr/testify v1.8.4 golang.org/x/net v0.17.0 ) -replace github.com/Dreamacro/clash => ../ +replace github.com/metacubex/mihomo => ../ require ( github.com/3andne/restls-client-go v0.1.6 // indirect @@ -30,17 +30,18 @@ require ( github.com/ericlagergren/polyval v0.0.0-20220411101811-e25bc10ba391 // indirect github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1 // indirect github.com/ericlagergren/subtle v0.0.0-20220507045147-890d697da010 // indirect - github.com/fsnotify/fsnotify v1.6.0 // indirect + github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/gaukas/godicttls v0.0.4 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect + github.com/gobwas/httphead v0.1.0 // indirect + github.com/gobwas/pool v0.2.1 // indirect + github.com/gobwas/ws v1.3.0 // 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.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-20230908212754-65c27093e38a // indirect github.com/josharian/native v1.1.0 // indirect @@ -54,9 +55,10 @@ require ( github.com/metacubex/gopacket v1.1.20-0.20230608035415-7e2f98a3e759 // indirect github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 // indirect github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b // indirect + github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966 // indirect github.com/metacubex/sing-shadowsocks v0.2.5 // indirect github.com/metacubex/sing-shadowsocks2 v0.1.4 // indirect - github.com/metacubex/sing-tun v0.1.15-0.20231003075803-dffa0200e64c // indirect + github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd // indirect github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 // indirect github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 // indirect github.com/moby/term v0.5.0 // indirect @@ -77,7 +79,7 @@ require ( github.com/quic-go/qtls-go1-20 v0.3.4 // 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.13 // indirect + github.com/sagernet/sing v0.2.14 // indirect github.com/sagernet/sing-mux v0.1.3 // indirect github.com/sagernet/sing-shadowtls v0.1.4 // indirect github.com/sagernet/smux v0.0.0-20230312102458-337ec2a5af37 // indirect @@ -100,6 +102,8 @@ require ( 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 + go.uber.org/mock v0.3.0 // indirect + go4.org/netipx v0.0.0-20230824141953-6213f710f925 // indirect golang.org/x/crypto v0.14.0 // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect golang.org/x/mod v0.13.0 // indirect diff --git a/test/go.sum b/test/go.sum index 10d016c9..c7524eff 100644 --- a/test/go.sum +++ b/test/go.sum @@ -15,8 +15,7 @@ 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.11.0 h1:V8gS/bTCCjX9uUnkUFUpPsksM8n1lXBAvHcpiFk1X2Y= -github.com/cilium/ebpf v0.11.0/go.mod h1:WE7CZAnqOL2RouJ4f1uyNhqr2P4CCvXFIqdRDUgWsVs= +github.com/cilium/ebpf v0.12.0 h1:oQEuIQIXgYhe1v7sYUG0P9vtJTYZLLdA6tiQmrOB1mo= github.com/cilium/ebpf v0.12.0/go.mod h1:u9H29/Iq+8cy70YqI6p5pfADkFl3vdnV2qXDg5JL0Zo= 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= @@ -43,22 +42,26 @@ github.com/ericlagergren/siv v0.0.0-20220507050439-0b757b3aa5f1/go.mod h1:4Rfsap 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.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/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= github.com/gaukas/godicttls v0.0.4 h1:NlRaXb3J6hAnTmWdsEKb9bcSBD6BvcIjdGdeb0zfXbk= github.com/gaukas/godicttls v0.0.4/go.mod h1:l6EenT4TLWgTdwslVb4sEMOCf7Bv0JAK67deKr9/NCI= 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-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= 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/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU= +github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM= +github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og= +github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= +github.com/gobwas/ws v1.3.0 h1:sbeU3Y4Qzlb+MOzIe6mQGf7QR4Hkv6ZD0qhGkBFL2O0= +github.com/gobwas/ws v1.3.0/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= 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= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -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.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= @@ -71,8 +74,6 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN 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= -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/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= @@ -101,29 +102,23 @@ 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-20230611153922-78842f086475 h1:qSEOvPPaMrWggFyFhFYGyMR8i1HKyhXjdi1QYUAa2ww= -github.com/metacubex/gvisor v0.0.0-20230611153922-78842f086475/go.mod h1:wehEpqiogdeyncfhckJP5gD2LtBgJW0wnDC24mJ+8Jg= +github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8 h1:npBvaPAT145UY8682AzpUMWpdIxJti/WPLjy7gCiYYs= github.com/metacubex/gvisor v0.0.0-20231001104248-0f672c3fb8d8/go.mod h1:ZR6Gas7P1GcADCVBc1uOrA0bLQqDDyp70+63fD/BE2c= -github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf h1:hflzPbb2M+3uUOZEVO72MKd2R62xEermoVaNhJOzBR8= -github.com/metacubex/quic-go v0.38.1-0.20230909013832-033f6a2115cf/go.mod h1:7RCcKJJk1DMeNQQNnYKS+7FqftqPfG031oP8jrYRMw8= +github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b h1:uZ++sW8yg7Fr/Wvmmrb/V+SfxvRs0iMC+2+u2bRmO8g= github.com/metacubex/quic-go v0.39.1-0.20231019030608-fd969d66f16b/go.mod h1:4pe6cY+nAMFU/Uxn1rfnxNIowsaJGDQ3uyy4VuiPkP4= -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-quic v0.0.0-20231008050747-a684db516966 h1:wbOsbU3kfD5LRuJIntJwEPmgGSQukof8CgLNypi8az8= +github.com/metacubex/sing-quic v0.0.0-20231008050747-a684db516966/go.mod h1:GU7g2AZesXItk4CspDP8Dc7eGtlA2GVDihyCwsUXRSo= +github.com/metacubex/sing-shadowsocks v0.2.5 h1:O2RRSHlKGEpAVG/OHJQxyHqDy8uvvdCW/oW2TDBOIhc= github.com/metacubex/sing-shadowsocks v0.2.5/go.mod h1:Xz2uW9BEYGEoA8B4XEpoxt7ERHClFCwsMAvWaruoyMo= -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-shadowsocks2 v0.1.4 h1:OOCf8lgsVcpTOJUeaFAMzyKVebaQOBnKirDdUdBoKIE= github.com/metacubex/sing-shadowsocks2 v0.1.4/go.mod h1:Qz028sLfdY3qxGRm9FDI+IM2Ae3ty2wR7HIzD/56h/k= -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-tun v0.1.15-0.20231003075803-dffa0200e64c/go.mod h1:vwmlad7eS1E+Hdv6ux0muC1FCM4UF23FHOMlrDtVARU= -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-tun v0.1.15-0.20231103033938-170591e8d5bd h1:k0+92eARqyTAovGhg2AxdsMWHjUsdiGCnR5NuXF3CQY= +github.com/metacubex/sing-tun v0.1.15-0.20231103033938-170591e8d5bd/go.mod h1:Q7zmpJ+qOvMMXyUoYlxGQuWkqALUpXzFSSqO+KLPyzA= +github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74 h1:FtupiyFkaVjFvRa7B/uDtRWg5BNsoyPC9MTev3sDasY= github.com/metacubex/sing-vmess v0.1.9-0.20230921005247-a0488d7dac74/go.mod h1:8EWBZpc+qNvf5gmvjAtMHK1/DpcWqzfcBL842K00BsM= -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/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170 h1:DBGA0hmrP4pVIwLiXUONdphjcppED+plmVaKf1oqkwk= github.com/metacubex/sing-wireguard v0.0.0-20231001110902-321836559170/go.mod h1:/VbJfbdLnANE+SKXyMk/96sTRrD4GdFLh5mkegqqFcY= -github.com/miekg/dns v1.1.55 h1:GoQ4hpsj0nFLYe+bWiCToyrBEJXkQfOOIvFGFy0lEgo= -github.com/miekg/dns v1.1.55/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY= +github.com/miekg/dns v1.1.56 h1:5imZaSeoRNvpM9SzWNhEcP9QliKiz20/dA2QabIGVnE= github.com/miekg/dns v1.1.56/go.mod h1:cRm6Oo2C8TY9ZS/TqsSrseAcncm74lfK5G+ikN2SWWY= 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= @@ -155,13 +150,11 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= -github.com/puzpuzpuz/xsync/v2 v2.5.0 h1:2k4qrO/orvmEXZ3hmtHqIy9XaQtPTwzMZk1+iErpE8c= -github.com/puzpuzpuz/xsync/v2 v2.5.0/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= +github.com/puzpuzpuz/xsync/v2 v2.5.1 h1:mVGYAvzDSu52+zaGyNjC+24Xw2bQi3kTr4QJ6N9pIIU= github.com/puzpuzpuz/xsync/v2 v2.5.1/go.mod h1:gD2H2krq/w52MfPLE+Uy64TzJDVY7lP2znR9qmR35kU= 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.3 h1:17/glZSLI9P9fDAeyCHBFSWSqJcwx1byhLwP5eUIDCM= -github.com/quic-go/qtls-go1-20 v0.3.3/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= +github.com/quic-go/qtls-go1-20 v0.3.4 h1:MfFAPULvst4yoMgY9QmtpYmfij/em7O8UUi+bNVm7Cg= github.com/quic-go/qtls-go1-20 v0.3.4/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= @@ -170,11 +163,9 @@ 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.10-0.20230807080248-4db0062caa0a h1:b89t6Mjgk4rJ5lrNMnCzy1/J116XkhgdB3YNd9FHyF4= -github.com/sagernet/sing v0.2.10-0.20230807080248-4db0062caa0a/go.mod h1:9uOZwWkhT2Z2WldolLxX34s+1svAX4i4vvz5hy8u1MA= -github.com/sagernet/sing v0.2.13/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= -github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c h1:35/FowAvt3Z62mck0TXzVc4jS5R5CWq62qcV2P1cp0I= -github.com/sagernet/sing-mux v0.1.3-0.20230811111955-dc1639b5204c/go.mod h1:TKxqIvfQQgd36jp2tzsPavGjYTVZilV+atip1cssjIY= +github.com/sagernet/sing v0.2.14 h1:L3AXDh22nsOOYz2nTRU1JvpRsmzViWKI1B8TsQYG1eY= +github.com/sagernet/sing v0.2.14/go.mod h1:AhNEHu0GXrpqkuzvTwvC8+j2cQUU/dh+zLEmq4C99pg= +github.com/sagernet/sing-mux v0.1.3 h1:fAf7PZa2A55mCeh0KKM02f1k2Y4vEmxuZZ/51ahkkLA= github.com/sagernet/sing-mux v0.1.3/go.mod h1:wGeIeiiFLx4HUM5LAg65wrNZ/X1muOimqK0PEhNbPi0= github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k= github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= @@ -190,8 +181,7 @@ 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.8 h1:xnATPiybo6GgdRoC4YoGnxXZFRc3dqQTGi73oLvvBrE= -github.com/shirou/gopsutil/v3 v3.23.8/go.mod h1:7hmCaBn+2ZwaZOr6jmPBZDfawwMGuo1id3C6aM8EDqQ= +github.com/shirou/gopsutil/v3 v3.23.9 h1:ZI5bWVeu2ep4/DIxB4U9okeYJ7zp/QLTO4auRb/ty/E= github.com/shirou/gopsutil/v3 v3.23.9/go.mod h1:x/NWSb71eMcjFIO0vhyGW5nZ7oSIgVjrCnADckb85GA= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= @@ -228,7 +218,6 @@ github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695AP github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= 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.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= @@ -237,37 +226,33 @@ 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/mock v0.3.0 h1:3mUxI1No2/60yUYax92Pt8eNOEecx2D3lcXZh2NEZJo= +go.uber.org/mock v0.3.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= +go4.org/netipx v0.0.0-20230824141953-6213f710f925 h1:eeQDDVKFkx0g4Hyy8pHgmZaK0EqB4SD6rvKbUdN3ziQ= +go4.org/netipx v0.0.0-20230824141953-6213f710f925/go.mod h1:PLyyIXexvUFg3Owu6p/WfdlivPbZJsZdgWZlrGope/Y= 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.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck= -golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= +golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g= -golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k= +golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= 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.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= -golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.13.0 h1:I/DsJXRlw/8l/0c24sM9yb0T4z9liZTduXvdAWYiysY= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= 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.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= -golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= 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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= -golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= golang.org/x/sync v0.4.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= @@ -277,22 +262,18 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w 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-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= -golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220622161953-175b2fd9d664/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220731174439-a90be440212d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.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.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= @@ -304,9 +285,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn 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.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ= -golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58= +golang.org/x/tools v0.14.0 h1:jvNa2pY0M4r62jkRQ6RwEZZyPcymeL9XZMLBbV7U2nc= golang.org/x/tools v0.14.0/go.mod h1:uYBEerGOWcJyEORxN+Ek8+TT266gXkNlHdJBwexUsBg= 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= diff --git a/test/hysteria_test.go b/test/hysteria_test.go index ae638e62..e783d9c2 100644 --- a/test/hysteria_test.go +++ b/test/hysteria_test.go @@ -5,13 +5,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/assert" ) -func TestClash_Hysteria(t *testing.T) { +func TestMihomo_Hysteria(t *testing.T) { cfg := &container.Config{ Image: ImageHysteria, ExposedPorts: defaultExposedPorts, diff --git a/test/snell_test.go b/test/snell_test.go index ae9ce0c1..311ca7b7 100644 --- a/test/snell_test.go +++ b/test/snell_test.go @@ -5,13 +5,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/require" ) -func TestClash_SnellObfsHTTP(t *testing.T) { +func TestMihomo_SnellObfsHTTP(t *testing.T) { cfg := &container.Config{ Image: ImageSnell, ExposedPorts: defaultExposedPorts, @@ -44,7 +44,7 @@ func TestClash_SnellObfsHTTP(t *testing.T) { testSuit(t, proxy) } -func TestClash_SnellObfsTLS(t *testing.T) { +func TestMihomo_SnellObfsTLS(t *testing.T) { cfg := &container.Config{ Image: ImageSnell, ExposedPorts: defaultExposedPorts, @@ -77,7 +77,7 @@ func TestClash_SnellObfsTLS(t *testing.T) { testSuit(t, proxy) } -func TestClash_Snell(t *testing.T) { +func TestMihomo_Snell(t *testing.T) { cfg := &container.Config{ Image: ImageSnell, ExposedPorts: defaultExposedPorts, @@ -107,7 +107,7 @@ func TestClash_Snell(t *testing.T) { testSuit(t, proxy) } -func TestClash_Snellv3(t *testing.T) { +func TestMihomo_Snellv3(t *testing.T) { cfg := &container.Config{ Image: ImageSnell, ExposedPorts: defaultExposedPorts, diff --git a/test/ss_test.go b/test/ss_test.go index bec1734b..866fe3a8 100644 --- a/test/ss_test.go +++ b/test/ss_test.go @@ -8,13 +8,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/require" ) -func TestClash_Shadowsocks(t *testing.T) { +func TestMihomo_Shadowsocks(t *testing.T) { for _, method := range []string{ "aes-128-ctr", "aes-192-ctr", @@ -30,7 +30,7 @@ func TestClash_Shadowsocks(t *testing.T) { "xchacha20-ietf-poly1305", } { t.Run(method, func(t *testing.T) { - testClash_Shadowsocks(t, method, "FzcLbKs2dY9mhL") + testMihomo_Shadowsocks(t, method, "FzcLbKs2dY9mhL") }) } for _, method := range []string{ @@ -39,17 +39,17 @@ func TestClash_Shadowsocks(t *testing.T) { "chacha20-ietf-poly1305", } { t.Run(method, func(t *testing.T) { - testClash_ShadowsocksRust(t, method, "FzcLbKs2dY9mhL") + testMihomo_ShadowsocksRust(t, method, "FzcLbKs2dY9mhL") }) } } -func TestClash_Shadowsocks2022(t *testing.T) { +func TestMihomo_Shadowsocks2022(t *testing.T) { for _, method := range []string{ "2022-blake3-aes-128-gcm", } { t.Run(method, func(t *testing.T) { - testClash_ShadowsocksRust(t, method, mkKey(16)) + testMihomo_ShadowsocksRust(t, method, mkKey(16)) }) } for _, method := range []string{ @@ -57,7 +57,7 @@ func TestClash_Shadowsocks2022(t *testing.T) { "2022-blake3-chacha20-poly1305", } { t.Run(method, func(t *testing.T) { - testClash_ShadowsocksRust(t, method, mkKey(32)) + testMihomo_ShadowsocksRust(t, method, mkKey(32)) }) } } @@ -68,7 +68,7 @@ func mkKey(bits int) string { return base64.StdEncoding.EncodeToString(k) } -func testClash_Shadowsocks(t *testing.T, method string, password string) { +func testMihomo_Shadowsocks(t *testing.T, method string, password string) { cfg := &container.Config{ Image: ImageShadowsocks, Env: []string{ @@ -102,7 +102,7 @@ func testClash_Shadowsocks(t *testing.T, method string, password string) { testSuit(t, proxy) } -func testClash_ShadowsocksRust(t *testing.T, method string, password string) { +func testMihomo_ShadowsocksRust(t *testing.T, method string, password string) { cfg := &container.Config{ Image: ImageShadowsocksRust, Entrypoint: []string{"ssserver"}, @@ -134,7 +134,7 @@ func testClash_ShadowsocksRust(t *testing.T, method string, password string) { testSuit(t, proxy) } -func TestClash_ShadowsocksObfsHTTP(t *testing.T) { +func TestMihomo_ShadowsocksObfsHTTP(t *testing.T) { cfg := &container.Config{ Image: ImageShadowsocks, Env: []string{ @@ -172,7 +172,7 @@ func TestClash_ShadowsocksObfsHTTP(t *testing.T) { testSuit(t, proxy) } -func TestClash_ShadowsocksObfsTLS(t *testing.T) { +func TestMihomo_ShadowsocksObfsTLS(t *testing.T) { cfg := &container.Config{ Image: ImageShadowsocks, Env: []string{ @@ -210,7 +210,7 @@ func TestClash_ShadowsocksObfsTLS(t *testing.T) { testSuit(t, proxy) } -func TestClash_ShadowsocksV2RayPlugin(t *testing.T) { +func TestMihomo_ShadowsocksV2RayPlugin(t *testing.T) { cfg := &container.Config{ Image: ImageShadowsocks, Env: []string{ @@ -280,7 +280,7 @@ func Benchmark_Shadowsocks(b *testing.B) { benchmarkProxy(b, proxy) } -func TestClash_ShadowsocksUoT(t *testing.T) { +func TestMihomo_ShadowsocksUoT(t *testing.T) { configPath := C.Path.Resolve("xray-shadowsocks.json") cfg := &container.Config{ diff --git a/test/trojan_test.go b/test/trojan_test.go index 4885fd3b..c6b1fea0 100644 --- a/test/trojan_test.go +++ b/test/trojan_test.go @@ -6,13 +6,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/require" ) -func TestClash_Trojan(t *testing.T) { +func TestMihomo_Trojan(t *testing.T) { cfg := &container.Config{ Image: ImageTrojan, ExposedPorts: defaultExposedPorts, @@ -48,7 +48,7 @@ func TestClash_Trojan(t *testing.T) { testSuit(t, proxy) } -func TestClash_TrojanGrpc(t *testing.T) { +func TestMihomo_TrojanGrpc(t *testing.T) { cfg := &container.Config{ Image: ImageXray, ExposedPorts: defaultExposedPorts, @@ -87,7 +87,7 @@ func TestClash_TrojanGrpc(t *testing.T) { testSuit(t, proxy) } -func TestClash_TrojanWebsocket(t *testing.T) { +func TestMihomo_TrojanWebsocket(t *testing.T) { cfg := &container.Config{ Image: ImageTrojanGo, ExposedPorts: defaultExposedPorts, @@ -123,7 +123,7 @@ func TestClash_TrojanWebsocket(t *testing.T) { testSuit(t, proxy) } -func TestClash_TrojanXTLS(t *testing.T) { +func TestMihomo_TrojanXTLS(t *testing.T) { cfg := &container.Config{ Image: ImageXray, ExposedPorts: defaultExposedPorts, diff --git a/test/vless_test.go b/test/vless_test.go index b75fb3ad..d0e6f071 100644 --- a/test/vless_test.go +++ b/test/vless_test.go @@ -5,14 +5,14 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/assert" ) // TODO: fix udp test -func TestClash_VlessTLS(t *testing.T) { +func TestMihomo_VlessTLS(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -51,7 +51,7 @@ func TestClash_VlessTLS(t *testing.T) { } // TODO: fix udp test -func TestClash_VlessXTLS(t *testing.T) { +func TestMihomo_VlessXTLS(t *testing.T) { cfg := &container.Config{ Image: ImageXray, ExposedPorts: defaultExposedPorts, @@ -81,7 +81,6 @@ func TestClash_VlessXTLS(t *testing.T) { ServerName: "example.org", UDP: true, Flow: "xtls-rprx-direct", - FlowShow: true, }) if err != nil { assert.FailNow(t, err.Error()) @@ -92,7 +91,7 @@ func TestClash_VlessXTLS(t *testing.T) { } // TODO: fix udp test -func TestClash_VlessWS(t *testing.T) { +func TestMihomo_VlessWS(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, diff --git a/test/vmess_test.go b/test/vmess_test.go index fd83fff8..80c3d4d8 100644 --- a/test/vmess_test.go +++ b/test/vmess_test.go @@ -5,13 +5,13 @@ import ( "testing" "time" - "github.com/Dreamacro/clash/adapter/outbound" - C "github.com/Dreamacro/clash/constant" "github.com/docker/docker/api/types/container" + "github.com/metacubex/mihomo/adapter/outbound" + C "github.com/metacubex/mihomo/constant" "github.com/stretchr/testify/require" ) -func TestClash_Vmess(t *testing.T) { +func TestMihomo_Vmess(t *testing.T) { configPath := C.Path.Resolve("vmess.json") cfg := &container.Config{ @@ -44,7 +44,7 @@ func TestClash_Vmess(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessAuthenticatedLength(t *testing.T) { +func TestMihomo_VmessAuthenticatedLength(t *testing.T) { configPath := C.Path.Resolve("vmess.json") cfg := &container.Config{ @@ -78,7 +78,7 @@ func TestClash_VmessAuthenticatedLength(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessPacketAddr(t *testing.T) { +func TestMihomo_VmessPacketAddr(t *testing.T) { configPath := C.Path.Resolve("vmess.json") cfg := &container.Config{ @@ -112,7 +112,7 @@ func TestClash_VmessPacketAddr(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessTLS(t *testing.T) { +func TestMihomo_VmessTLS(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -149,7 +149,7 @@ func TestClash_VmessTLS(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessHTTP2(t *testing.T) { +func TestMihomo_VmessHTTP2(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -191,7 +191,7 @@ func TestClash_VmessHTTP2(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessHTTP(t *testing.T) { +func TestMihomo_VmessHTTP(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -241,7 +241,7 @@ func TestClash_VmessHTTP(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessWebsocket(t *testing.T) { +func TestMihomo_VmessWebsocket(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -274,7 +274,7 @@ func TestClash_VmessWebsocket(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessWebsocketTLS(t *testing.T) { +func TestMihomo_VmessWebsocketTLS(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -311,7 +311,7 @@ func TestClash_VmessWebsocketTLS(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessGrpc(t *testing.T) { +func TestMihomo_VmessGrpc(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -352,7 +352,7 @@ func TestClash_VmessGrpc(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessWebsocket0RTT(t *testing.T) { +func TestMihomo_VmessWebsocket0RTT(t *testing.T) { cfg := &container.Config{ Image: ImageVmess, ExposedPorts: defaultExposedPorts, @@ -390,7 +390,7 @@ func TestClash_VmessWebsocket0RTT(t *testing.T) { testSuit(t, proxy) } -func TestClash_VmessWebsocketXray0RTT(t *testing.T) { +func TestMihomo_VmessWebsocketXray0RTT(t *testing.T) { cfg := &container.Config{ Image: ImageXray, ExposedPorts: defaultExposedPorts, diff --git a/transport/gun/gun.go b/transport/gun/gun.go index d6ef6317..cf986c8e 100644 --- a/transport/gun/gun.go +++ b/transport/gun/gun.go @@ -17,10 +17,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/buf" - "github.com/Dreamacro/clash/common/pool" - tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/buf" + "github.com/metacubex/mihomo/common/pool" + tlsC "github.com/metacubex/mihomo/component/tls" "golang.org/x/net/http2" ) diff --git a/transport/hysteria/conns/faketcp/obfs.go b/transport/hysteria/conns/faketcp/obfs.go index 35f7d013..cf58e569 100644 --- a/transport/hysteria/conns/faketcp/obfs.go +++ b/transport/hysteria/conns/faketcp/obfs.go @@ -1,7 +1,7 @@ package faketcp import ( - "github.com/Dreamacro/clash/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/obfs" "net" "sync" "syscall" diff --git a/transport/hysteria/conns/faketcp/tcp_linux.go b/transport/hysteria/conns/faketcp/tcp_linux.go index 76ed0d5e..2aaaf139 100644 --- a/transport/hysteria/conns/faketcp/tcp_linux.go +++ b/transport/hysteria/conns/faketcp/tcp_linux.go @@ -20,7 +20,7 @@ import ( "github.com/metacubex/gopacket" "github.com/metacubex/gopacket/layers" - "github.com/Dreamacro/clash/component/dialer" + "github.com/metacubex/mihomo/component/dialer" ) var ( diff --git a/transport/hysteria/conns/udp/hop.go b/transport/hysteria/conns/udp/hop.go index 447a7592..eb0732f0 100644 --- a/transport/hysteria/conns/udp/hop.go +++ b/transport/hysteria/conns/udp/hop.go @@ -9,8 +9,8 @@ import ( "syscall" "time" - "github.com/Dreamacro/clash/transport/hysteria/obfs" - "github.com/Dreamacro/clash/transport/hysteria/utils" + "github.com/metacubex/mihomo/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/utils" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/hysteria/conns/udp/obfs.go b/transport/hysteria/conns/udp/obfs.go index d63034b5..a5c6c06c 100644 --- a/transport/hysteria/conns/udp/obfs.go +++ b/transport/hysteria/conns/udp/obfs.go @@ -1,7 +1,7 @@ package udp import ( - "github.com/Dreamacro/clash/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/obfs" "net" "sync" "time" diff --git a/transport/hysteria/conns/wechat/obfs.go b/transport/hysteria/conns/wechat/obfs.go index d13cca55..4266d268 100644 --- a/transport/hysteria/conns/wechat/obfs.go +++ b/transport/hysteria/conns/wechat/obfs.go @@ -6,8 +6,8 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/hysteria/obfs" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/hysteria/obfs" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index ecc8a6f1..b556c70d 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -11,10 +11,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/transport/hysteria/obfs" - "github.com/Dreamacro/clash/transport/hysteria/pmtud_fix" - "github.com/Dreamacro/clash/transport/hysteria/transport" - "github.com/Dreamacro/clash/transport/hysteria/utils" + "github.com/metacubex/mihomo/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/pmtud_fix" + "github.com/metacubex/mihomo/transport/hysteria/transport" + "github.com/metacubex/mihomo/transport/hysteria/utils" "github.com/lunixbochs/struc" "github.com/metacubex/quic-go" diff --git a/transport/hysteria/transport/client.go b/transport/hysteria/transport/client.go index 67568bc8..f5cc9f07 100644 --- a/transport/hysteria/transport/client.go +++ b/transport/hysteria/transport/client.go @@ -9,11 +9,11 @@ import ( "github.com/metacubex/quic-go" - "github.com/Dreamacro/clash/transport/hysteria/conns/faketcp" - "github.com/Dreamacro/clash/transport/hysteria/conns/udp" - "github.com/Dreamacro/clash/transport/hysteria/conns/wechat" - obfsPkg "github.com/Dreamacro/clash/transport/hysteria/obfs" - "github.com/Dreamacro/clash/transport/hysteria/utils" + "github.com/metacubex/mihomo/transport/hysteria/conns/faketcp" + "github.com/metacubex/mihomo/transport/hysteria/conns/udp" + "github.com/metacubex/mihomo/transport/hysteria/conns/wechat" + obfsPkg "github.com/metacubex/mihomo/transport/hysteria/obfs" + "github.com/metacubex/mihomo/transport/hysteria/utils" ) type ClientTransport struct { diff --git a/transport/shadowsocks/core/cipher.go b/transport/shadowsocks/core/cipher.go index cd30360c..44b2e8d4 100644 --- a/transport/shadowsocks/core/cipher.go +++ b/transport/shadowsocks/core/cipher.go @@ -7,9 +7,9 @@ import ( "sort" "strings" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowstream" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowstream" ) type Cipher interface { diff --git a/transport/shadowsocks/shadowaead/packet.go b/transport/shadowsocks/shadowaead/packet.go index e84ac570..f9d21ec7 100644 --- a/transport/shadowsocks/shadowaead/packet.go +++ b/transport/shadowsocks/shadowaead/packet.go @@ -6,8 +6,8 @@ import ( "io" "net" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" ) // ErrShortPacket means that the packet is too short for a valid encrypted packet. diff --git a/transport/shadowsocks/shadowaead/stream.go b/transport/shadowsocks/shadowaead/stream.go index e92bddab..de0993b2 100644 --- a/transport/shadowsocks/shadowaead/stream.go +++ b/transport/shadowsocks/shadowaead/stream.go @@ -7,7 +7,7 @@ import ( "io" "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) const ( diff --git a/transport/shadowsocks/shadowstream/packet.go b/transport/shadowsocks/shadowstream/packet.go index f0bf43ef..39d09a70 100644 --- a/transport/shadowsocks/shadowstream/packet.go +++ b/transport/shadowsocks/shadowstream/packet.go @@ -6,8 +6,8 @@ import ( "io" "net" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" ) // ErrShortPacket means the packet is too short to be a valid encrypted packet. diff --git a/transport/shadowtls/shadowtls.go b/transport/shadowtls/shadowtls.go index 2c0c5946..a0a3d7fb 100644 --- a/transport/shadowtls/shadowtls.go +++ b/transport/shadowtls/shadowtls.go @@ -11,8 +11,8 @@ import ( "io" "net" - "github.com/Dreamacro/clash/common/pool" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" ) const ( diff --git a/transport/simple-obfs/http.go b/transport/simple-obfs/http.go index 80db34ba..681c1864 100644 --- a/transport/simple-obfs/http.go +++ b/transport/simple-obfs/http.go @@ -8,7 +8,7 @@ import ( "net" "net/http" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/simple-obfs/tls.go b/transport/simple-obfs/tls.go index 20166bbe..78317f0a 100644 --- a/transport/simple-obfs/tls.go +++ b/transport/simple-obfs/tls.go @@ -7,7 +7,7 @@ import ( "net" "time" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/sing-shadowtls/shadowtls.go b/transport/sing-shadowtls/shadowtls.go index 6d731ae6..982d847a 100644 --- a/transport/sing-shadowtls/shadowtls.go +++ b/transport/sing-shadowtls/shadowtls.go @@ -5,9 +5,9 @@ import ( "crypto/tls" "net" - "github.com/Dreamacro/clash/component/ca" - tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/component/ca" + tlsC "github.com/metacubex/mihomo/component/tls" + "github.com/metacubex/mihomo/log" "github.com/sagernet/sing-shadowtls" sing_common "github.com/sagernet/sing/common" diff --git a/transport/snell/cipher.go b/transport/snell/cipher.go index 24999e28..e18ce510 100644 --- a/transport/snell/cipher.go +++ b/transport/snell/cipher.go @@ -4,7 +4,7 @@ import ( "crypto/aes" "crypto/cipher" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" "golang.org/x/crypto/argon2" "golang.org/x/crypto/chacha20poly1305" diff --git a/transport/snell/pool.go b/transport/snell/pool.go index 2a233a75..cc097df7 100644 --- a/transport/snell/pool.go +++ b/transport/snell/pool.go @@ -5,8 +5,8 @@ import ( "net" "time" - "github.com/Dreamacro/clash/component/pool" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/component/pool" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" ) type Pool struct { @@ -61,7 +61,7 @@ func (pc *PoolConn) Write(b []byte) (int, error) { } func (pc *PoolConn) Close() error { - // clash use SetReadDeadline to break bidirectional copy between client and server. + // mihomo use SetReadDeadline to break bidirectional copy between client and server. // reset it before reuse connection to avoid io timeout error. _ = pc.Snell.Conn.SetReadDeadline(time.Time{}) pc.pool.Put(pc.Snell) diff --git a/transport/snell/snell.go b/transport/snell/snell.go index e2bd2820..fe3e4ee0 100644 --- a/transport/snell/snell.go +++ b/transport/snell/snell.go @@ -8,9 +8,9 @@ import ( "net" "sync" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/shadowsocks/shadowaead" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/shadowsocks/shadowaead" + "github.com/metacubex/mihomo/transport/socks5" ) const ( diff --git a/transport/socks4/socks4.go b/transport/socks4/socks4.go index 0d5c5a77..9533a1c0 100644 --- a/transport/socks4/socks4.go +++ b/transport/socks4/socks4.go @@ -9,7 +9,7 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/component/auth" + "github.com/metacubex/mihomo/component/auth" ) const Version = 0x04 diff --git a/transport/socks5/socks5.go b/transport/socks5/socks5.go index 6f95cce9..c97c370c 100644 --- a/transport/socks5/socks5.go +++ b/transport/socks5/socks5.go @@ -9,7 +9,7 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/component/auth" + "github.com/metacubex/mihomo/component/auth" ) // Error represents a SOCKS error diff --git a/transport/ssr/obfs/http_simple.go b/transport/ssr/obfs/http_simple.go index c91cca49..359ca342 100644 --- a/transport/ssr/obfs/http_simple.go +++ b/transport/ssr/obfs/http_simple.go @@ -8,7 +8,7 @@ import ( "strconv" "strings" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/obfs/random_head.go b/transport/ssr/obfs/random_head.go index 4c55d951..9a2072fe 100644 --- a/transport/ssr/obfs/random_head.go +++ b/transport/ssr/obfs/random_head.go @@ -5,7 +5,7 @@ import ( "hash/crc32" "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/obfs/tls1.2_ticket_auth.go b/transport/ssr/obfs/tls1.2_ticket_auth.go index af945133..d5e3ca88 100644 --- a/transport/ssr/obfs/tls1.2_ticket_auth.go +++ b/transport/ssr/obfs/tls1.2_ticket_auth.go @@ -8,8 +8,8 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/ssr/tools" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/ssr/tools" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/auth_aes128_md5.go b/transport/ssr/protocol/auth_aes128_md5.go index d3bc9417..c6ae415e 100644 --- a/transport/ssr/protocol/auth_aes128_md5.go +++ b/transport/ssr/protocol/auth_aes128_md5.go @@ -1,6 +1,6 @@ package protocol -import "github.com/Dreamacro/clash/transport/ssr/tools" +import "github.com/metacubex/mihomo/transport/ssr/tools" func init() { register("auth_aes128_md5", newAuthAES128MD5, 9) diff --git a/transport/ssr/protocol/auth_aes128_sha1.go b/transport/ssr/protocol/auth_aes128_sha1.go index e2f0e143..6ee4160e 100644 --- a/transport/ssr/protocol/auth_aes128_sha1.go +++ b/transport/ssr/protocol/auth_aes128_sha1.go @@ -8,10 +8,10 @@ import ( "strconv" "strings" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/ssr/tools" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/ssr/tools" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/auth_chain_a.go b/transport/ssr/protocol/auth_chain_a.go index 12345db6..396172ef 100644 --- a/transport/ssr/protocol/auth_chain_a.go +++ b/transport/ssr/protocol/auth_chain_a.go @@ -12,11 +12,11 @@ import ( "strconv" "strings" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/shadowsocks/core" - "github.com/Dreamacro/clash/transport/ssr/tools" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/shadowsocks/core" + "github.com/metacubex/mihomo/transport/ssr/tools" ) func init() { @@ -108,7 +108,7 @@ func (a *authChainA) Decode(dst, src *bytes.Buffer) error { dataLength := int(binary.LittleEndian.Uint16(src.Bytes()[:2]) ^ binary.LittleEndian.Uint16(a.lastServerHash[14:16])) randDataLength := a.randDataLength(dataLength, a.lastServerHash, &a.randomServer) length := dataLength + randDataLength - // Temporary workaround for https://github.com/Dreamacro/clash/issues/1352 + // Temporary workaround for https://github.com/metacubex/mihomo/issues/1352 if dataLength < 0 || randDataLength < 0 || length < 0 { return errors.New("ssr crashing blocked") } @@ -135,7 +135,7 @@ func (a *authChainA) Decode(dst, src *bytes.Buffer) error { if dataLength > 0 && randDataLength > 0 { pos += getRandStartPos(randDataLength, &a.randomServer) } - // Temporary workaround for https://github.com/Dreamacro/clash/issues/1352 + // Temporary workaround for https://github.com/metacubex/mihomo/issues/1352 if pos < 0 || pos+dataLength < 0 || dataLength < 0 { return errors.New("ssr crashing blocked") } diff --git a/transport/ssr/protocol/auth_chain_b.go b/transport/ssr/protocol/auth_chain_b.go index 857b2a3a..223613a9 100644 --- a/transport/ssr/protocol/auth_chain_b.go +++ b/transport/ssr/protocol/auth_chain_b.go @@ -4,7 +4,7 @@ import ( "net" "sort" - "github.com/Dreamacro/clash/transport/ssr/tools" + "github.com/metacubex/mihomo/transport/ssr/tools" ) func init() { diff --git a/transport/ssr/protocol/auth_sha1_v4.go b/transport/ssr/protocol/auth_sha1_v4.go index 26039181..ed1a39f1 100644 --- a/transport/ssr/protocol/auth_sha1_v4.go +++ b/transport/ssr/protocol/auth_sha1_v4.go @@ -7,9 +7,9 @@ import ( "hash/crc32" "net" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/transport/ssr/tools" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/ssr/tools" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/base.go b/transport/ssr/protocol/base.go index a826bec8..e26a6587 100644 --- a/transport/ssr/protocol/base.go +++ b/transport/ssr/protocol/base.go @@ -9,9 +9,9 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/transport/shadowsocks/core" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/shadowsocks/core" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/origin.go b/transport/ssr/protocol/origin.go index 52525a2f..4d8b630a 100644 --- a/transport/ssr/protocol/origin.go +++ b/transport/ssr/protocol/origin.go @@ -4,7 +4,7 @@ import ( "bytes" "net" - N "github.com/Dreamacro/clash/common/net" + N "github.com/metacubex/mihomo/common/net" ) type origin struct{} diff --git a/transport/ssr/protocol/packet.go b/transport/ssr/protocol/packet.go index 988ff75d..86d573f3 100644 --- a/transport/ssr/protocol/packet.go +++ b/transport/ssr/protocol/packet.go @@ -3,8 +3,8 @@ package protocol import ( "net" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" ) type PacketConn struct { diff --git a/transport/ssr/protocol/protocol.go b/transport/ssr/protocol/protocol.go index 1c27da48..a04e6bd4 100644 --- a/transport/ssr/protocol/protocol.go +++ b/transport/ssr/protocol/protocol.go @@ -6,7 +6,7 @@ import ( "fmt" "net" - N "github.com/Dreamacro/clash/common/net" + N "github.com/metacubex/mihomo/common/net" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/ssr/protocol/stream.go b/transport/ssr/protocol/stream.go index 3c846157..436859c3 100644 --- a/transport/ssr/protocol/stream.go +++ b/transport/ssr/protocol/stream.go @@ -4,7 +4,7 @@ import ( "bytes" "net" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type Conn struct { diff --git a/transport/ssr/tools/random.go b/transport/ssr/tools/random.go index 338543ea..c76011e4 100644 --- a/transport/ssr/tools/random.go +++ b/transport/ssr/tools/random.go @@ -3,7 +3,7 @@ package tools import ( "encoding/binary" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) // XorShift128Plus - a pseudorandom number generator diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 20ba80b3..c4bd1167 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -12,13 +12,13 @@ import ( "net/http" "sync" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/pool" - "github.com/Dreamacro/clash/component/ca" - tlsC "github.com/Dreamacro/clash/component/tls" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/vmess" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/component/ca" + tlsC "github.com/metacubex/mihomo/component/tls" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/vmess" ) const ( diff --git a/transport/tuic/common/congestion.go b/transport/tuic/common/congestion.go index 13c1300f..485e2e6a 100644 --- a/transport/tuic/common/congestion.go +++ b/transport/tuic/common/congestion.go @@ -1,8 +1,8 @@ package common import ( - "github.com/Dreamacro/clash/transport/tuic/congestion" - congestionv2 "github.com/Dreamacro/clash/transport/tuic/congestion_v2" + "github.com/metacubex/mihomo/transport/tuic/congestion" + congestionv2 "github.com/metacubex/mihomo/transport/tuic/congestion_v2" "github.com/metacubex/quic-go" c "github.com/metacubex/quic-go/congestion" diff --git a/transport/tuic/common/type.go b/transport/tuic/common/type.go index 9a568dd7..c663fa0b 100644 --- a/transport/tuic/common/type.go +++ b/transport/tuic/common/type.go @@ -7,8 +7,8 @@ import ( "net" "time" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/pool_client.go b/transport/tuic/pool_client.go index 4a779706..e492fba7 100644 --- a/transport/tuic/pool_client.go +++ b/transport/tuic/pool_client.go @@ -8,10 +8,10 @@ import ( "sync" "time" - "github.com/Dreamacro/clash/common/generics/list" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/generics/list" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/server.go b/transport/tuic/server.go index cabc04e0..a273e462 100644 --- a/transport/tuic/server.go +++ b/transport/tuic/server.go @@ -7,14 +7,14 @@ import ( "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/metacubex/mihomo/adapter/inbound" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/tuic/common" + v4 "github.com/metacubex/mihomo/transport/tuic/v4" + v5 "github.com/metacubex/mihomo/transport/tuic/v5" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/transport/tuic/tuic.go b/transport/tuic/tuic.go index 387a152c..02aaa3ad 100644 --- a/transport/tuic/tuic.go +++ b/transport/tuic/tuic.go @@ -1,10 +1,10 @@ package tuic import ( - 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" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/tuic/common" + v4 "github.com/metacubex/mihomo/transport/tuic/v4" + v5 "github.com/metacubex/mihomo/transport/tuic/v5" ) type ClientOptionV4 = v4.ClientOption diff --git a/transport/tuic/v4/client.go b/transport/tuic/v4/client.go index ce33b72b..0bc8f9bb 100644 --- a/transport/tuic/v4/client.go +++ b/transport/tuic/v4/client.go @@ -13,13 +13,13 @@ 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" + atomic2 "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/puzpuzpuz/xsync/v2" diff --git a/transport/tuic/v4/packet.go b/transport/tuic/v4/packet.go index 2066ceb7..5bd6504c 100644 --- a/transport/tuic/v4/packet.go +++ b/transport/tuic/v4/packet.go @@ -5,10 +5,10 @@ import ( "sync" "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" + "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/v4/protocol.go b/transport/tuic/v4/protocol.go index bbdca67c..29536742 100644 --- a/transport/tuic/v4/protocol.go +++ b/transport/tuic/v4/protocol.go @@ -11,8 +11,8 @@ import ( "github.com/metacubex/quic-go" "lukechampine.com/blake3" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" ) type BufferedReader interface { diff --git a/transport/tuic/v4/server.go b/transport/tuic/v4/server.go index 56133fea..c4e4d735 100644 --- a/transport/tuic/v4/server.go +++ b/transport/tuic/v4/server.go @@ -7,13 +7,13 @@ import ( "net" "sync" - "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" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/tuic/common" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/transport/tuic/v5/client.go b/transport/tuic/v5/client.go index c4ac25d4..e37d60fc 100644 --- a/transport/tuic/v5/client.go +++ b/transport/tuic/v5/client.go @@ -12,12 +12,12 @@ import ( "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" + atomic2 "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/puzpuzpuz/xsync/v2" diff --git a/transport/tuic/v5/frag.go b/transport/tuic/v5/frag.go index 8df9f785..4e07a1c7 100644 --- a/transport/tuic/v5/frag.go +++ b/transport/tuic/v5/frag.go @@ -4,7 +4,7 @@ import ( "bytes" "sync" - "github.com/Dreamacro/clash/common/cache" + "github.com/metacubex/mihomo/common/cache" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go index efbe0bb9..8ab45068 100644 --- a/transport/tuic/v5/packet.go +++ b/transport/tuic/v5/packet.go @@ -6,10 +6,10 @@ import ( "sync" "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" + "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/pool" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/metacubex/quic-go" "github.com/zhangyunhao116/fastrand" diff --git a/transport/tuic/v5/protocol.go b/transport/tuic/v5/protocol.go index 964401e1..de51a080 100644 --- a/transport/tuic/v5/protocol.go +++ b/transport/tuic/v5/protocol.go @@ -8,9 +8,9 @@ import ( "net/netip" "strconv" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" "github.com/metacubex/quic-go" ) diff --git a/transport/tuic/v5/server.go b/transport/tuic/v5/server.go index 10003a9d..c8170f62 100644 --- a/transport/tuic/v5/server.go +++ b/transport/tuic/v5/server.go @@ -7,12 +7,12 @@ import ( "net" "sync" - "github.com/Dreamacro/clash/adapter/inbound" - "github.com/Dreamacro/clash/common/atomic" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/transport/socks5" - "github.com/Dreamacro/clash/transport/tuic/common" + "github.com/metacubex/mihomo/adapter/inbound" + "github.com/metacubex/mihomo/common/atomic" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/transport/socks5" + "github.com/metacubex/mihomo/transport/tuic/common" "github.com/gofrs/uuid/v5" "github.com/metacubex/quic-go" diff --git a/transport/v2ray-plugin/websocket.go b/transport/v2ray-plugin/websocket.go index 9cb4420c..1c7056d6 100644 --- a/transport/v2ray-plugin/websocket.go +++ b/transport/v2ray-plugin/websocket.go @@ -6,8 +6,8 @@ import ( "net" "net/http" - "github.com/Dreamacro/clash/component/ca" - "github.com/Dreamacro/clash/transport/vmess" + "github.com/metacubex/mihomo/component/ca" + "github.com/metacubex/mihomo/transport/vmess" ) // Option is options of websocket obfs diff --git a/transport/vless/config.pb.go b/transport/vless/config.pb.go index 1407e4d7..14fcc5f9 100644 --- a/transport/vless/config.pb.go +++ b/transport/vless/config.pb.go @@ -108,7 +108,7 @@ func file_transport_vless_config_proto_rawDescGZIP() []byte { var file_transport_vless_config_proto_msgTypes = make([]protoimpl.MessageInfo, 1) var file_transport_vless_config_proto_goTypes = []interface{}{ - (*Addons)(nil), // 0: clash.transport.vless.Addons + (*Addons)(nil), // 0: mihomo.transport.vless.Addons } var file_transport_vless_config_proto_depIdxs = []int32{ 0, // [0:0] is the sub-list for method output_type diff --git a/transport/vless/config.proto b/transport/vless/config.proto index 80900230..44cad479 100644 --- a/transport/vless/config.proto +++ b/transport/vless/config.proto @@ -1,9 +1,9 @@ syntax = "proto3"; -package clash.transport.vless; -option csharp_namespace = "Clash.Transport.Vless"; -option go_package = "github.com/Dreamacro/clash/transport/vless"; -option java_package = "com.clash.transport.vless"; +package mihomo.transport.vless; +option csharp_namespace = "Mihomo.Transport.Vless"; +option go_package = "github.com/metacubex/mihomo/transport/vless"; +option java_package = "com.mihomo.transport.vless"; option java_multiple_files = true; message Addons { diff --git a/transport/vless/conn.go b/transport/vless/conn.go index 33ecd97a..02224892 100644 --- a/transport/vless/conn.go +++ b/transport/vless/conn.go @@ -7,9 +7,9 @@ import ( "net" "sync" - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/transport/vless/vision" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/transport/vless/vision" "github.com/gofrs/uuid/v5" "google.golang.org/protobuf/proto" diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go index 03f524aa..79c77835 100644 --- a/transport/vless/vision/conn.go +++ b/transport/vless/vision/conn.go @@ -9,9 +9,9 @@ import ( "io" "net" - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/log" "github.com/gofrs/uuid/v5" utls "github.com/sagernet/utls" diff --git a/transport/vless/vision/filter.go b/transport/vless/vision/filter.go index e070de35..55b5663f 100644 --- a/transport/vless/vision/filter.go +++ b/transport/vless/vision/filter.go @@ -4,7 +4,7 @@ import ( "bytes" "encoding/binary" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/log" ) var ( diff --git a/transport/vless/vision/padding.go b/transport/vless/vision/padding.go index d5a230d1..e5f9dc85 100644 --- a/transport/vless/vision/padding.go +++ b/transport/vless/vision/padding.go @@ -4,8 +4,8 @@ import ( "bytes" "encoding/binary" - "github.com/Dreamacro/clash/common/buf" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/buf" + "github.com/metacubex/mihomo/log" "github.com/gofrs/uuid/v5" "github.com/zhangyunhao116/fastrand" diff --git a/transport/vless/vision/vision.go b/transport/vless/vision/vision.go index 3b52dd4b..09299b23 100644 --- a/transport/vless/vision/vision.go +++ b/transport/vless/vision/vision.go @@ -10,8 +10,8 @@ import ( "reflect" "unsafe" - N "github.com/Dreamacro/clash/common/net" - tlsC "github.com/Dreamacro/clash/component/tls" + N "github.com/metacubex/mihomo/common/net" + tlsC "github.com/metacubex/mihomo/component/tls" "github.com/gofrs/uuid/v5" "github.com/sagernet/sing/common" diff --git a/transport/vless/vless.go b/transport/vless/vless.go index 6c01b839..ce07cdb4 100644 --- a/transport/vless/vless.go +++ b/transport/vless/vless.go @@ -3,7 +3,7 @@ package vless import ( "net" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/gofrs/uuid/v5" ) diff --git a/transport/vmess/aead.go b/transport/vmess/aead.go index d4fbf2d9..89ec6a3b 100644 --- a/transport/vmess/aead.go +++ b/transport/vmess/aead.go @@ -7,7 +7,7 @@ import ( "io" "sync" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) type aeadWriter struct { diff --git a/transport/vmess/chunk.go b/transport/vmess/chunk.go index ab1adb6d..f52fc82c 100644 --- a/transport/vmess/chunk.go +++ b/transport/vmess/chunk.go @@ -5,7 +5,7 @@ import ( "errors" "io" - "github.com/Dreamacro/clash/common/pool" + "github.com/metacubex/mihomo/common/pool" ) const ( diff --git a/transport/vmess/http.go b/transport/vmess/http.go index d9e73f68..782e7eb2 100644 --- a/transport/vmess/http.go +++ b/transport/vmess/http.go @@ -8,7 +8,7 @@ import ( "net/http" "net/textproto" - "github.com/Dreamacro/clash/common/util" + "github.com/metacubex/mihomo/common/util" "github.com/zhangyunhao116/fastrand" ) diff --git a/transport/vmess/tls.go b/transport/vmess/tls.go index 8bcb6513..bdaa8ccc 100644 --- a/transport/vmess/tls.go +++ b/transport/vmess/tls.go @@ -6,8 +6,8 @@ import ( "errors" "net" - "github.com/Dreamacro/clash/component/ca" - tlsC "github.com/Dreamacro/clash/component/tls" + "github.com/metacubex/mihomo/component/ca" + tlsC "github.com/metacubex/mihomo/component/tls" ) type TLSConfig struct { diff --git a/transport/vmess/vmess.go b/transport/vmess/vmess.go index 2dd071eb..7c587c6a 100644 --- a/transport/vmess/vmess.go +++ b/transport/vmess/vmess.go @@ -5,7 +5,7 @@ import ( "net" "runtime" - "github.com/Dreamacro/clash/common/utils" + "github.com/metacubex/mihomo/common/utils" "github.com/gofrs/uuid/v5" "github.com/zhangyunhao116/fastrand" diff --git a/transport/vmess/websocket.go b/transport/vmess/websocket.go index 9f09185b..b30bb8aa 100644 --- a/transport/vmess/websocket.go +++ b/transport/vmess/websocket.go @@ -18,10 +18,10 @@ import ( "strings" "time" - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - tlsC "github.com/Dreamacro/clash/component/tls" - "github.com/Dreamacro/clash/log" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + tlsC "github.com/metacubex/mihomo/component/tls" + "github.com/metacubex/mihomo/log" "github.com/gobwas/ws" "github.com/gobwas/ws/wsutil" diff --git a/tunnel/connection.go b/tunnel/connection.go index 9fc4f405..33cc4e8d 100644 --- a/tunnel/connection.go +++ b/tunnel/connection.go @@ -6,9 +6,9 @@ import ( "net/netip" "time" - N "github.com/Dreamacro/clash/common/net" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/log" + N "github.com/metacubex/mihomo/common/net" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" ) func handleUDPToRemote(packet C.UDPPacket, pc C.PacketConn, metadata *C.Metadata) error { diff --git a/tunnel/statistic/manager.go b/tunnel/statistic/manager.go index 4797829f..8e962dae 100644 --- a/tunnel/statistic/manager.go +++ b/tunnel/statistic/manager.go @@ -4,7 +4,7 @@ import ( "os" "time" - "github.com/Dreamacro/clash/common/atomic" + "github.com/metacubex/mihomo/common/atomic" "github.com/puzpuzpuz/xsync/v2" "github.com/shirou/gopsutil/v3/process" diff --git a/tunnel/statistic/tracker.go b/tunnel/statistic/tracker.go index bc2dbd5c..0bf7995d 100644 --- a/tunnel/statistic/tracker.go +++ b/tunnel/statistic/tracker.go @@ -6,11 +6,11 @@ import ( "net/netip" "time" - "github.com/Dreamacro/clash/common/atomic" - "github.com/Dreamacro/clash/common/buf" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/common/utils" - C "github.com/Dreamacro/clash/constant" + "github.com/metacubex/mihomo/common/atomic" + "github.com/metacubex/mihomo/common/buf" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/common/utils" + C "github.com/metacubex/mihomo/constant" "github.com/gofrs/uuid/v5" ) diff --git a/tunnel/tunnel.go b/tunnel/tunnel.go index fe37d75e..596e26d7 100644 --- a/tunnel/tunnel.go +++ b/tunnel/tunnel.go @@ -12,16 +12,16 @@ import ( "github.com/jpillora/backoff" - N "github.com/Dreamacro/clash/common/net" - "github.com/Dreamacro/clash/component/nat" - P "github.com/Dreamacro/clash/component/process" - "github.com/Dreamacro/clash/component/resolver" - "github.com/Dreamacro/clash/component/sniffer" - C "github.com/Dreamacro/clash/constant" - "github.com/Dreamacro/clash/constant/provider" - icontext "github.com/Dreamacro/clash/context" - "github.com/Dreamacro/clash/log" - "github.com/Dreamacro/clash/tunnel/statistic" + N "github.com/metacubex/mihomo/common/net" + "github.com/metacubex/mihomo/component/nat" + P "github.com/metacubex/mihomo/component/process" + "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/component/sniffer" + C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/constant/provider" + icontext "github.com/metacubex/mihomo/context" + "github.com/metacubex/mihomo/log" + "github.com/metacubex/mihomo/tunnel/statistic" ) var (