From 89a097faa8f7242a108b3ea7a162d04dab77c864 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 28 Apr 2024 13:24:16 +0800 Subject: [PATCH 01/30] chore: update quic-go to 0.43.0 --- dns/doh.go | 2 +- go.mod | 4 ++-- go.sum | 10 ++++------ transport/hysteria/core/client.go | 2 +- transport/tuic/v4/packet.go | 2 +- transport/tuic/v5/packet.go | 4 ++-- 6 files changed, 11 insertions(+), 13 deletions(-) diff --git a/dns/doh.go b/dns/doh.go index ef4b653f..09d311b5 100644 --- a/dns/doh.go +++ b/dns/doh.go @@ -515,7 +515,7 @@ func (doh *dnsOverHTTPS) createTransportH3( }, DisableCompression: true, TLSClientConfig: tlsConfig, - QuicConfig: doh.getQUICConfig(), + QUICConfig: doh.getQUICConfig(), } return &http3Transport{baseTransport: rt}, nil diff --git a/go.mod b/go.mod index a8feb726..01d67032 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.42.1-0.20240418003344-f006b5735d98 - github.com/metacubex/sing-quic v0.0.0-20240418004036-814c531c378d + github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 + github.com/metacubex/sing-quic v0.0.0-20240428052223-bf4b8b6c1b22 github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.2.0 github.com/metacubex/sing-tun v0.2.6 diff --git a/go.sum b/go.sum index 8cd6d29d..c250677c 100644 --- a/go.sum +++ b/go.sum @@ -78,8 +78,6 @@ github.com/google/tink/go v1.6.1 h1:t7JHqO8Ath2w2ig5vjwQYJzhGEZymedQc90lQXUBa4I= 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-20240227161007-c728f5dd21c8 h1:V3plQrMHRWOB5zMm3yNqvBxDQVW1+/wHBSok5uPdmVs= -github.com/insomniacslk/dhcp v0.0.0-20240227161007-c728f5dd21c8/go.mod h1:izxuNQZeFrbx2nK2fAyN5iNUB34Fe9j0nK4PwLzAkKw= github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 h1:/OuvSMGT9+xnyZ+7MZQ1zdngaCCAdPoSw8B/uurZ7pg= github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49/go.mod h1:KclMyHxX06VrVr0DJmeFSUb1ankt7xTfoOA35pCkoic= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -106,12 +104,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-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec/go.mod h1:8BVmQ+3cxjqzWElafm24rb2Ae4jRI6vAXNXWqWjfrXw= -github.com/metacubex/quic-go v0.42.1-0.20240418003344-f006b5735d98 h1:oMLlJV4a9AylNo8ZLBNUiqZ02Vme6GLLHjuWJz8amSk= -github.com/metacubex/quic-go v0.42.1-0.20240418003344-f006b5735d98/go.mod h1:iGx3Y1zynls/FjFgykLSqDcM81U0IKePRTXEz5g3iiQ= +github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 h1:qqIZ8CjoxVJP38JU9ml1RkWJfaUd7QtmOk1vl7shuRY= +github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764 h1:+czGKoynxYA90YaL3NlCAIJHnlqwoUlLWgmOhdm5ZU8= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/metacubex/sing-quic v0.0.0-20240418004036-814c531c378d h1:RAe0ND8J5SOPGI623oEXfaHKaaUrrzHx+U1DN9Awcco= -github.com/metacubex/sing-quic v0.0.0-20240418004036-814c531c378d/go.mod h1:WyY0zYxv+o+18R/Ece+QFontlgXoobKbNqbtYn2zjz8= +github.com/metacubex/sing-quic v0.0.0-20240428052223-bf4b8b6c1b22 h1:LPiTgdUBxOeQqDmHn/W2gDb5W2C+JPWOf/mkRl9nfCM= +github.com/metacubex/sing-quic v0.0.0-20240428052223-bf4b8b6c1b22/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= diff --git a/transport/hysteria/core/client.go b/transport/hysteria/core/client.go index 199fe0d4..97c9225e 100644 --- a/transport/hysteria/core/client.go +++ b/transport/hysteria/core/client.go @@ -406,7 +406,7 @@ func (c *quicPktConn) WriteTo(p []byte, addr string) error { if errors.As(err, &errSize) { // need to frag msg.MsgID = uint16(fastrand.Intn(0xFFFF)) + 1 // msgID must be > 0 when fragCount > 1 - fragMsgs := fragUDPMessage(msg, int(errSize.PeerMaxDatagramFrameSize)) + fragMsgs := fragUDPMessage(msg, int(errSize.MaxDatagramPayloadSize)) for _, fragMsg := range fragMsgs { msgBuf.Reset() _ = struc.Pack(&msgBuf, &fragMsg) diff --git a/transport/tuic/v4/packet.go b/transport/tuic/v4/packet.go index 8f5bb5b3..47484e78 100644 --- a/transport/tuic/v4/packet.go +++ b/transport/tuic/v4/packet.go @@ -123,7 +123,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 != common.QUIC && len(p) > q.maxUdpRelayPacketSize { - return 0, &quic.DatagramTooLargeError{PeerMaxDatagramFrameSize: int64(q.maxUdpRelayPacketSize)} + return 0, &quic.DatagramTooLargeError{MaxDatagramPayloadSize: int64(q.maxUdpRelayPacketSize)} } if q.closed { return 0, net.ErrClosed diff --git a/transport/tuic/v5/packet.go b/transport/tuic/v5/packet.go index 86f839a5..5608db81 100644 --- a/transport/tuic/v5/packet.go +++ b/transport/tuic/v5/packet.go @@ -137,7 +137,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 len(p) > 0xffff { // uint16 max - return 0, &quic.DatagramTooLargeError{PeerMaxDatagramFrameSize: 0xffff} + return 0, &quic.DatagramTooLargeError{MaxDatagramPayloadSize: 0xffff} } if q.closed { return 0, net.ErrClosed @@ -189,7 +189,7 @@ func (q *quicStreamPacketConn) WriteTo(p []byte, addr net.Addr) (n int, err erro var tooLarge *quic.DatagramTooLargeError if errors.As(err, &tooLarge) { - err = fragWriteNative(q.quicConn, packet, buf, int(tooLarge.PeerMaxDatagramFrameSize)-PacketOverHead) + err = fragWriteNative(q.quicConn, packet, buf, int(tooLarge.MaxDatagramPayloadSize)-PacketOverHead) } if err != nil { return From 314c0bb34b27db978d63029d693eee02ef30a054 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Mon, 29 Apr 2024 12:14:11 +0800 Subject: [PATCH 02/30] fix: hy2 udp incompatible with quic-go 0.43.0 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 01d67032..dad18d9e 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.43.1-0.20240428051621-a109abfb4cf6 - github.com/metacubex/sing-quic v0.0.0-20240428052223-bf4b8b6c1b22 + github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.2.0 github.com/metacubex/sing-tun v0.2.6 diff --git a/go.sum b/go.sum index c250677c..8c4836b2 100644 --- a/go.sum +++ b/go.sum @@ -108,8 +108,8 @@ github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 h1:qqIZ8CjoxV github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764 h1:+czGKoynxYA90YaL3NlCAIJHnlqwoUlLWgmOhdm5ZU8= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/metacubex/sing-quic v0.0.0-20240428052223-bf4b8b6c1b22 h1:LPiTgdUBxOeQqDmHn/W2gDb5W2C+JPWOf/mkRl9nfCM= -github.com/metacubex/sing-quic v0.0.0-20240428052223-bf4b8b6c1b22/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4= +github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e h1:UW+yfzoLzjEhAoJ6A4mVnov3Aergi7uFM/h7ReNekKI= +github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= From 107e3e763009668b174a6ef4d36a4c06e3169930 Mon Sep 17 00:00:00 2001 From: Pylogmon Date: Tue, 30 Apr 2024 17:01:46 +0800 Subject: [PATCH 03/30] feat: Allow upgrade to latest release (#1235) --- hub/updater/updater.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/hub/updater/updater.go b/hub/updater/updater.go index 02ff07ba..df5da3f4 100644 --- a/hub/updater/updater.go +++ b/hub/updater/updater.go @@ -16,7 +16,6 @@ import ( "time" mihomoHttp "github.com/metacubex/mihomo/component/http" - "github.com/metacubex/mihomo/constant" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/log" @@ -52,6 +51,10 @@ func init() { if runtime.GOARCH == "amd64" && cpuid.CPU.X64Level() < 3 { amd64Compatible = "-compatible" } + if !strings.HasPrefix(C.Version, "alpha") { + baseURL = "https://github.com/MetaCubeX/mihomo/releases/latest/download/mihomo" + versionURL = "https://github.com/MetaCubeX/mihomo/releases/latest/download/version.txt" + } } type updateError struct { @@ -73,9 +76,9 @@ func Update(execPath string) (err error) { return err } - log.Infoln("current version %s, latest version %s", constant.Version, latestVersion) + log.Infoln("current version %s, latest version %s", C.Version, latestVersion) - if latestVersion == constant.Version { + if latestVersion == C.Version { err := &updateError{Message: "already using latest version"} return err } From 8861eaf9033db6d1db2da5f59962770884f92013 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 1 May 2024 09:41:04 +0800 Subject: [PATCH 04/30] chore: hysteria2 will only change remote port in hopLoop --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index dad18d9e..0769a212 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.43.1-0.20240428051621-a109abfb4cf6 - github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e + github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.2.0 github.com/metacubex/sing-tun v0.2.6 diff --git a/go.sum b/go.sum index 8c4836b2..a4d90759 100644 --- a/go.sum +++ b/go.sum @@ -108,8 +108,8 @@ github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 h1:qqIZ8CjoxV github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764 h1:+czGKoynxYA90YaL3NlCAIJHnlqwoUlLWgmOhdm5ZU8= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e h1:UW+yfzoLzjEhAoJ6A4mVnov3Aergi7uFM/h7ReNekKI= -github.com/metacubex/sing-quic v0.0.0-20240429040940-fa3a4ff2533e/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4= +github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f h1:Xyd8SHaPHS3iX3xXPnus9PsYhJIo/2e7sJ6vTKLKUm8= +github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= From a2b43faa0ba8c959bb4e3ff8ad16abeee25148b7 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 4 May 2024 18:41:08 +0800 Subject: [PATCH 05/30] Update README.md --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 975f1268..d38fbedd 100644 --- a/README.md +++ b/README.md @@ -98,4 +98,3 @@ API. This software is released under the GPL-3.0 license. -[![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) From 5dd883e790ef5525197fa2edfdcbba0627aa7fd2 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Mon, 6 May 2024 14:03:29 +0800 Subject: [PATCH 06/30] chore: Add use-system-hosts option --- component/resolver/host.go | 8 ++++++-- config/config.go | 28 ++++++++++++++++------------ hub/executor/executor.go | 1 + 3 files changed, 23 insertions(+), 14 deletions(-) diff --git a/component/resolver/host.go b/component/resolver/host.go index 4a429629..7e299a09 100644 --- a/component/resolver/host.go +++ b/component/resolver/host.go @@ -13,7 +13,10 @@ import ( "github.com/zhangyunhao116/fastrand" ) -var DisableSystemHosts, _ = strconv.ParseBool(os.Getenv("DISABLE_SYSTEM_HOSTS")) +var ( + DisableSystemHosts, _ = strconv.ParseBool(os.Getenv("DISABLE_SYSTEM_HOSTS")) + UseSystemHosts bool +) type Hosts struct { *trie.DomainTrie[HostValue] @@ -51,7 +54,8 @@ func (h *Hosts) Search(domain string, isDomain bool) (*HostValue, bool) { return &hostValue, false } - if !isDomain && !DisableSystemHosts { + + if !isDomain && !DisableSystemHosts && UseSystemHosts { addr, _ := lookupStaticHost(domain) if hostValue, err := NewHostValue(addr); err == nil { return &hostValue, true diff --git a/config/config.go b/config/config.go index f425092a..b76c40ff 100644 --- a/config/config.go +++ b/config/config.go @@ -114,6 +114,7 @@ type DNS struct { PreferH3 bool `yaml:"prefer-h3"` IPv6 bool `yaml:"ipv6"` IPv6Timeout uint `yaml:"ipv6-timeout"` + UseSystemHosts bool `yaml:"use-system-hosts"` NameServer []dns.NameServer `yaml:"nameserver"` Fallback []dns.NameServer `yaml:"fallback"` FallbackFilter FallbackFilter `yaml:"fallback-filter"` @@ -209,6 +210,7 @@ type RawDNS struct { IPv6 bool `yaml:"ipv6" json:"ipv6"` IPv6Timeout uint `yaml:"ipv6-timeout" json:"ipv6-timeout"` UseHosts bool `yaml:"use-hosts" json:"use-hosts"` + UseSystemHosts bool `yaml:"use-system-hosts" json:"use-system-hosts"` NameServer []string `yaml:"nameserver" json:"nameserver"` Fallback []string `yaml:"fallback" json:"fallback"` FallbackFilter RawFallbackFilter `yaml:"fallback-filter" json:"fallback-filter"` @@ -456,12 +458,13 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { Interval: 30, }, DNS: RawDNS{ - Enable: false, - IPv6: false, - UseHosts: true, - IPv6Timeout: 100, - EnhancedMode: C.DNSMapping, - FakeIPRange: "198.18.0.1/16", + Enable: false, + IPv6: false, + UseHosts: true, + UseSystemHosts: true, + IPv6Timeout: 100, + EnhancedMode: C.DNSMapping, + FakeIPRange: "198.18.0.1/16", FallbackFilter: RawFallbackFilter{ GeoIP: true, GeoIPCode: "CN", @@ -1285,12 +1288,13 @@ func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rul } dnsCfg := &DNS{ - Enable: cfg.Enable, - Listen: cfg.Listen, - PreferH3: cfg.PreferH3, - IPv6Timeout: cfg.IPv6Timeout, - IPv6: cfg.IPv6, - EnhancedMode: cfg.EnhancedMode, + Enable: cfg.Enable, + Listen: cfg.Listen, + PreferH3: cfg.PreferH3, + IPv6Timeout: cfg.IPv6Timeout, + IPv6: cfg.IPv6, + UseSystemHosts: cfg.UseSystemHosts, + EnhancedMode: cfg.EnhancedMode, FallbackFilter: FallbackFilter{ IPCIDR: []netip.Prefix{}, GeoSite: []router.DomainMatcher{}, diff --git a/hub/executor/executor.go b/hub/executor/executor.go index c23eb9f3..56e71632 100644 --- a/hub/executor/executor.go +++ b/hub/executor/executor.go @@ -253,6 +253,7 @@ func updateDNS(c *config.DNS, ruleProvider map[string]provider.RuleProvider, gen resolver.DefaultResolver = r resolver.DefaultHostMapper = m resolver.DefaultLocalServer = dns.NewLocalServer(r, m) + resolver.UseSystemHosts = c.UseSystemHosts if pr.Invalid() { resolver.ProxyServerHostResolver = pr From 6d1c62bbf036e7a6c471a1bf0ca6fae27ffa48bd Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 8 May 2024 09:27:13 +0800 Subject: [PATCH 07/30] fix: shadowsocks uot not work with dialer-proxy --- adapter/outbound/shadowsocks.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 98932f0c..714c4a7d 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -166,12 +166,6 @@ 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 { @@ -179,6 +173,12 @@ func (ss *ShadowSocks) ListenPacketWithDialer(ctx context.Context, dialer C.Dial } return ss.ListenPacketOnStreamConn(ctx, tcpConn, metadata) } + if len(ss.option.DialerProxy) > 0 { + dialer, err = proxydialer.NewByName(ss.option.DialerProxy, dialer) + if err != nil { + return nil, err + } + } addr, err := resolveUDPAddrWithPrefer(ctx, "udp", ss.addr, ss.prefer) if err != nil { return nil, err From 619f34119efcf448cfb01ce085d1ba8f3bef1284 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 May 2024 00:10:51 +0800 Subject: [PATCH 08/30] action: add golang1.21 with special revert commit to work on Windows7 --- .github/workflows/build.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index df320d29..a588dc54 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,6 +64,12 @@ jobs: - { goos: android, goarch: arm, ndk: armv7a-linux-androideabi34, output: armv7 } - { goos: android, goarch: arm64, ndk: aarch64-linux-android34, output: arm64-v8 } + # Go 1.21 can revert commit `9e4385` to work on Windows 7 + # https://github.com/golang/go/issues/64622#issuecomment-1847475161 + - { goos: windows, goarch: '386', output: '386-go121', goversion: '1.21' } + - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go121, goversion: '1.21' } + - { goos: windows, goarch: amd64, goamd64: v3, output: amd64-go121, goversion: '1.21' } + # 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. - { goos: windows, goarch: '386', output: '386-go120', goversion: '1.20' } - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go120, goversion: '1.20' } @@ -108,6 +114,13 @@ jobs: sudo tar zxf go1.21.5.linux-amd64-abi2.tar.gz -C /usr/local echo "/usr/local/go/bin" >> $GITHUB_PATH + # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 + - name: Set up Go1.21 for Windows + if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.21' }} + run: | + cd $(go env GOROOT) + curl https://github.com/golang/go/commit/9e43850a3298a9b8b1162ba0033d4c53f8637571.diff | patch --verbose -R -p 1 + - name: Set variables if: ${{github.ref_name=='Alpha'}} run: echo "VERSION=alpha-$(git rev-parse --short HEAD)" >> $GITHUB_ENV From b840eae4c60356e4b03f83e5f3a446eaff08c510 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 May 2024 12:36:48 +0800 Subject: [PATCH 09/30] fix: x509 error in windows7/8 --- component/ca/config.go | 3 --- component/ca/fix_windows.go | 15 +++++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 component/ca/fix_windows.go diff --git a/component/ca/config.go b/component/ca/config.go index d56809a1..9d002db6 100644 --- a/component/ca/config.go +++ b/component/ca/config.go @@ -67,9 +67,6 @@ func ResetCertificate() { } func getCertPool() *x509.CertPool { - if len(trustCerts) == 0 { - return nil - } if globalCertPool == nil { mutex.Lock() defer mutex.Unlock() diff --git a/component/ca/fix_windows.go b/component/ca/fix_windows.go new file mode 100644 index 00000000..00c894d8 --- /dev/null +++ b/component/ca/fix_windows.go @@ -0,0 +1,15 @@ +package ca + +import ( + "golang.org/x/sys/windows" +) + +func init() { + majorVersion, _, _ := windows.RtlGetNtVersionNumbers() + // crypto/x509: certificate validation in Windows fails to validate IP in SAN + // https://github.com/golang/go/issues/37176 + // As far as I can tell this is still the case on most older versions of Windows (but seems to be fixed in 10) + if majorVersion < 10 && len(_CaCertificates) > 0 { + DisableSystemCa = true + } +} From adf0ff588ff7ab1f6e76d4b869be7dc51fa4dfcc Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 May 2024 13:32:07 +0800 Subject: [PATCH 10/30] action: let golang1.22's build can work on windows7/8 --- ...def151adff1af707d82d28f55dba81ceb08e1.diff | 158 ++++++++++++++++++ .github/workflows/build.yml | 14 +- 2 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 .github/693def151adff1af707d82d28f55dba81ceb08e1.diff diff --git a/.github/693def151adff1af707d82d28f55dba81ceb08e1.diff b/.github/693def151adff1af707d82d28f55dba81ceb08e1.diff new file mode 100644 index 00000000..ca41ec31 --- /dev/null +++ b/.github/693def151adff1af707d82d28f55dba81ceb08e1.diff @@ -0,0 +1,158 @@ +diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go +index 62738e2cb1a7d..d0dcc7cc71fc0 100644 +--- a/src/crypto/rand/rand.go ++++ b/src/crypto/rand/rand.go +@@ -15,7 +15,7 @@ import "io" + // available, /dev/urandom otherwise. + // On OpenBSD and macOS, Reader uses getentropy(2). + // On other Unix-like systems, Reader reads from /dev/urandom. +-// On Windows systems, Reader uses the RtlGenRandom API. ++// On Windows systems, Reader uses the ProcessPrng API. + // On JS/Wasm, Reader uses the Web Crypto API. + // On WASIP1/Wasm, Reader uses random_get from wasi_snapshot_preview1. + var Reader io.Reader +diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go +index 6c0655c72b692..7380f1f0f1e6e 100644 +--- a/src/crypto/rand/rand_windows.go ++++ b/src/crypto/rand/rand_windows.go +@@ -15,11 +15,8 @@ func init() { Reader = &rngReader{} } + + type rngReader struct{} + +-func (r *rngReader) Read(b []byte) (n int, err error) { +- // RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at +- // most 1<<31-1 bytes at a time so that this works the same on 32-bit +- // and 64-bit systems. +- if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil { ++func (r *rngReader) Read(b []byte) (int, error) { ++ if err := windows.ProcessPrng(b); err != nil { + return 0, err + } + return len(b), nil +diff --git a/src/internal/syscall/windows/syscall_windows.go b/src/internal/syscall/windows/syscall_windows.go +index ab4ad2ec64108..5854ca60b5cef 100644 +--- a/src/internal/syscall/windows/syscall_windows.go ++++ b/src/internal/syscall/windows/syscall_windows.go +@@ -373,7 +373,7 @@ func ErrorLoadingGetTempPath2() error { + //sys DestroyEnvironmentBlock(block *uint16) (err error) = userenv.DestroyEnvironmentBlock + //sys CreateEvent(eventAttrs *SecurityAttributes, manualReset uint32, initialState uint32, name *uint16) (handle syscall.Handle, err error) = kernel32.CreateEventW + +-//sys RtlGenRandom(buf []byte) (err error) = advapi32.SystemFunction036 ++//sys ProcessPrng(buf []byte) (err error) = bcryptprimitives.ProcessPrng + + type FILE_ID_BOTH_DIR_INFO struct { + NextEntryOffset uint32 +diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go +index e3f6d8d2a2208..5a587ad4f146c 100644 +--- a/src/internal/syscall/windows/zsyscall_windows.go ++++ b/src/internal/syscall/windows/zsyscall_windows.go +@@ -37,13 +37,14 @@ func errnoErr(e syscall.Errno) error { + } + + var ( +- modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) +- modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) +- modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) +- modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) +- modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) +- moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) +- modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) ++ modadvapi32 = syscall.NewLazyDLL(sysdll.Add("advapi32.dll")) ++ modbcryptprimitives = syscall.NewLazyDLL(sysdll.Add("bcryptprimitives.dll")) ++ modiphlpapi = syscall.NewLazyDLL(sysdll.Add("iphlpapi.dll")) ++ modkernel32 = syscall.NewLazyDLL(sysdll.Add("kernel32.dll")) ++ modnetapi32 = syscall.NewLazyDLL(sysdll.Add("netapi32.dll")) ++ modpsapi = syscall.NewLazyDLL(sysdll.Add("psapi.dll")) ++ moduserenv = syscall.NewLazyDLL(sysdll.Add("userenv.dll")) ++ modws2_32 = syscall.NewLazyDLL(sysdll.Add("ws2_32.dll")) + + procAdjustTokenPrivileges = modadvapi32.NewProc("AdjustTokenPrivileges") + procDuplicateTokenEx = modadvapi32.NewProc("DuplicateTokenEx") +@@ -55,7 +56,7 @@ var ( + procQueryServiceStatus = modadvapi32.NewProc("QueryServiceStatus") + procRevertToSelf = modadvapi32.NewProc("RevertToSelf") + procSetTokenInformation = modadvapi32.NewProc("SetTokenInformation") +- procSystemFunction036 = modadvapi32.NewProc("SystemFunction036") ++ procProcessPrng = modbcryptprimitives.NewProc("ProcessPrng") + procGetAdaptersAddresses = modiphlpapi.NewProc("GetAdaptersAddresses") + procCreateEventW = modkernel32.NewProc("CreateEventW") + procGetACP = modkernel32.NewProc("GetACP") +@@ -179,12 +180,12 @@ func SetTokenInformation(tokenHandle syscall.Token, tokenInformationClass uint32 + return + } + +-func RtlGenRandom(buf []byte) (err error) { ++func ProcessPrng(buf []byte) (err error) { + var _p0 *byte + if len(buf) > 0 { + _p0 = &buf[0] + } +- r1, _, e1 := syscall.Syscall(procSystemFunction036.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) ++ r1, _, e1 := syscall.Syscall(procProcessPrng.Addr(), 2, uintptr(unsafe.Pointer(_p0)), uintptr(len(buf)), 0) + if r1 == 0 { + err = errnoErr(e1) + } +diff --git a/src/runtime/os_windows.go b/src/runtime/os_windows.go +index 8ca8d7790909e..3772a864b2ff4 100644 +--- a/src/runtime/os_windows.go ++++ b/src/runtime/os_windows.go +@@ -127,15 +127,8 @@ var ( + _WriteFile, + _ stdFunction + +- // Use RtlGenRandom to generate cryptographically random data. +- // This approach has been recommended by Microsoft (see issue +- // 15589 for details). +- // The RtlGenRandom is not listed in advapi32.dll, instead +- // RtlGenRandom function can be found by searching for SystemFunction036. +- // Also some versions of Mingw cannot link to SystemFunction036 +- // when building executable as Cgo. So load SystemFunction036 +- // manually during runtime startup. +- _RtlGenRandom stdFunction ++ // Use ProcessPrng to generate cryptographically random data. ++ _ProcessPrng stdFunction + + // Load ntdll.dll manually during startup, otherwise Mingw + // links wrong printf function to cgo executable (see issue +@@ -151,11 +144,11 @@ var ( + ) + + var ( +- advapi32dll = [...]uint16{'a', 'd', 'v', 'a', 'p', 'i', '3', '2', '.', 'd', 'l', 'l', 0} +- ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} +- powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} +- winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} +- ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} ++ bcryptprimitivesdll = [...]uint16{'b', 'c', 'r', 'y', 'p', 't', 'p', 'r', 'i', 'm', 'i', 't', 'i', 'v', 'e', 's', '.', 'd', 'l', 'l', 0} ++ ntdlldll = [...]uint16{'n', 't', 'd', 'l', 'l', '.', 'd', 'l', 'l', 0} ++ powrprofdll = [...]uint16{'p', 'o', 'w', 'r', 'p', 'r', 'o', 'f', '.', 'd', 'l', 'l', 0} ++ winmmdll = [...]uint16{'w', 'i', 'n', 'm', 'm', '.', 'd', 'l', 'l', 0} ++ ws2_32dll = [...]uint16{'w', 's', '2', '_', '3', '2', '.', 'd', 'l', 'l', 0} + ) + + // Function to be called by windows CreateThread +@@ -251,11 +244,11 @@ func windowsLoadSystemLib(name []uint16) uintptr { + } + + func loadOptionalSyscalls() { +- a32 := windowsLoadSystemLib(advapi32dll[:]) +- if a32 == 0 { +- throw("advapi32.dll not found") ++ bcryptPrimitives := windowsLoadSystemLib(bcryptprimitivesdll[:]) ++ if bcryptPrimitives == 0 { ++ throw("bcryptprimitives.dll not found") + } +- _RtlGenRandom = windowsFindfunc(a32, []byte("SystemFunction036\000")) ++ _ProcessPrng = windowsFindfunc(bcryptPrimitives, []byte("ProcessPrng\000")) + + n32 := windowsLoadSystemLib(ntdlldll[:]) + if n32 == 0 { +@@ -531,7 +524,7 @@ func osinit() { + //go:nosplit + func readRandom(r []byte) int { + n := 0 +- if stdcall2(_RtlGenRandom, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { ++ if stdcall2(_ProcessPrng, uintptr(unsafe.Pointer(&r[0])), uintptr(len(r)))&0xff != 0 { + n = len(r) + } + return n \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a588dc54..4f36e40d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,12 +64,6 @@ jobs: - { goos: android, goarch: arm, ndk: armv7a-linux-androideabi34, output: armv7 } - { goos: android, goarch: arm64, ndk: aarch64-linux-android34, output: arm64-v8 } - # Go 1.21 can revert commit `9e4385` to work on Windows 7 - # https://github.com/golang/go/issues/64622#issuecomment-1847475161 - - { goos: windows, goarch: '386', output: '386-go121', goversion: '1.21' } - - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go121, goversion: '1.21' } - - { goos: windows, goarch: amd64, goamd64: v3, output: amd64-go121, goversion: '1.21' } - # 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. - { goos: windows, goarch: '386', output: '386-go120', goversion: '1.20' } - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go120, goversion: '1.20' } @@ -115,11 +109,13 @@ jobs: echo "/usr/local/go/bin" >> $GITHUB_PATH # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 - - name: Set up Go1.21 for Windows - if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.21' }} + # this patch file only works on golang1.22.x + # that means after golang1.23 release it must be changed + - name: Revert Golang1.22 commit for Windows7/8 + if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '' }} run: | cd $(go env GOROOT) - curl https://github.com/golang/go/commit/9e43850a3298a9b8b1162ba0033d4c53f8637571.diff | patch --verbose -R -p 1 + patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/693def151adff1af707d82d28f55dba81ceb08e1.diff - name: Set variables if: ${{github.ref_name=='Alpha'}} From fc82a32a483cc9bd2bc46ad6dee688b830c8db14 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 May 2024 15:52:10 +0800 Subject: [PATCH 11/30] fix: `system` tun stack not working in win7 --- go.mod | 2 +- go.sum | 4 ++-- listener/sing_tun/server.go | 4 ++++ listener/sing_tun/server_windows.go | 8 ++++++++ 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 0769a212..904a9274 100644 --- a/go.mod +++ b/go.mod @@ -23,7 +23,7 @@ require ( github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.2.0 - github.com/metacubex/sing-tun v0.2.6 + github.com/metacubex/sing-tun v0.2.7-0.20240512075008-89e7c6208eec github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 diff --git a/go.sum b/go.sum index a4d90759..ae199963 100644 --- a/go.sum +++ b/go.sum @@ -114,8 +114,8 @@ github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwV github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= github.com/metacubex/sing-shadowsocks2 v0.2.0/go.mod h1:LCKF6j1P94zN8ZS+LXRK1gmYTVGB3squivBSXAFnOg8= -github.com/metacubex/sing-tun v0.2.6 h1:frc58BqnIClqcC9KcYBfVAn5bgO6WW1ANKvZW3/HYAQ= -github.com/metacubex/sing-tun v0.2.6/go.mod h1:4VsMwZH1IlgPGFK1ZbBomZ/B2MYkTgs2+gnBAr5GOIo= +github.com/metacubex/sing-tun v0.2.7-0.20240512075008-89e7c6208eec h1:K4Wq3GOdLZ/xcqwyzAt4kmYQrjokyKQ3u/Xh5Yft14U= +github.com/metacubex/sing-tun v0.2.7-0.20240512075008-89e7c6208eec/go.mod h1:4VsMwZH1IlgPGFK1ZbBomZ/B2MYkTgs2+gnBAr5GOIo= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f h1:QjXrHKbTMBip/C+R79bvbfr42xH1gZl3uFb0RELdZiQ= github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f/go.mod h1:olVkD4FChQ5gKMHG4ZzuD7+fMkJY1G8vwOKpRehjrmY= github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 h1:AGyIB55UfQm/0ZH0HtQO9u3l//yjtHUpjeRjjPGfGRI= diff --git a/listener/sing_tun/server.go b/listener/sing_tun/server.go index 7cd9fc72..2dc6524e 100644 --- a/listener/sing_tun/server.go +++ b/listener/sing_tun/server.go @@ -20,12 +20,14 @@ import ( tun "github.com/metacubex/sing-tun" "github.com/sagernet/sing/common" + "github.com/sagernet/sing/common/control" E "github.com/sagernet/sing/common/exceptions" F "github.com/sagernet/sing/common/format" "github.com/sagernet/sing/common/ranges" ) var InterfaceName = "Meta" +var EnforceBindInterface = false type Listener struct { closed bool @@ -263,6 +265,8 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis UDPTimeout: udpTimeout, Handler: handler, Logger: log.SingLogger, + InterfaceFinder: control.DefaultInterfaceFinder(), + EnforceBindInterface: EnforceBindInterface, } if options.FileDescriptor > 0 { diff --git a/listener/sing_tun/server_windows.go b/listener/sing_tun/server_windows.go index 8da21287..4bc04835 100644 --- a/listener/sing_tun/server_windows.go +++ b/listener/sing_tun/server_windows.go @@ -6,6 +6,8 @@ import ( "github.com/metacubex/mihomo/log" tun "github.com/metacubex/sing-tun" + + "golang.org/x/sys/windows" ) func tunNew(options tun.Options) (tunIf tun.Tun, err error) { @@ -27,4 +29,10 @@ func tunNew(options tun.Options) (tunIf tun.Tun, err error) { func init() { tun.TunnelType = InterfaceName + + majorVersion, _, _ := windows.RtlGetNtVersionNumbers() + if majorVersion < 10 { + // to resolve "bind: The requested address is not valid in its context" + EnforceBindInterface = true + } } From 7df1c269427dcb6207e9741f20c72cf3b29de1b6 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 May 2024 19:34:25 +0800 Subject: [PATCH 12/30] fix: fingerprint passing --- adapter/adapter.go | 3 +++ adapter/outbound/shadowsocks.go | 1 + adapter/outbound/vmess.go | 2 ++ transport/trojan/trojan.go | 6 ++++++ 4 files changed, 12 insertions(+) diff --git a/adapter/adapter.go b/adapter/adapter.go index dbf3db6e..8136827a 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -2,6 +2,7 @@ package adapter import ( "context" + "crypto/tls" "encoding/json" "fmt" "net" @@ -14,6 +15,7 @@ import ( "github.com/metacubex/mihomo/common/atomic" "github.com/metacubex/mihomo/common/queue" "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/ca" "github.com/metacubex/mihomo/component/dialer" C "github.com/metacubex/mihomo/constant" "github.com/puzpuzpuz/xsync/v3" @@ -230,6 +232,7 @@ func (p *Proxy) URLTest(ctx context.Context, url string, expectedStatus utils.In IdleConnTimeout: 90 * time.Second, TLSHandshakeTimeout: 10 * time.Second, ExpectContinueTimeout: 1 * time.Second, + TLSClientConfig: ca.GetGlobalTLSConfig(&tls.Config{}), } client := http.Client{ diff --git a/adapter/outbound/shadowsocks.go b/adapter/outbound/shadowsocks.go index 714c4a7d..88fb8456 100644 --- a/adapter/outbound/shadowsocks.go +++ b/adapter/outbound/shadowsocks.go @@ -273,6 +273,7 @@ func NewShadowSocks(option ShadowSocksOption) (*ShadowSocks, error) { if opts.TLS { v2rayOption.TLS = true v2rayOption.SkipCertVerify = opts.SkipCertVerify + v2rayOption.Fingerprint = opts.Fingerprint } } else if option.Plugin == shadowtls.Mode { obfsMode = shadowtls.Mode diff --git a/adapter/outbound/vmess.go b/adapter/outbound/vmess.go index c1c981ce..7d5a7224 100644 --- a/adapter/outbound/vmess.go +++ b/adapter/outbound/vmess.go @@ -179,6 +179,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M tlsOpts := mihomoVMess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, + FingerPrint: v.option.Fingerprint, NextProtos: []string{"h2"}, ClientFingerprint: v.option.ClientFingerprint, Reality: v.realityConfig, @@ -208,6 +209,7 @@ func (v *Vmess) StreamConnContext(ctx context.Context, c net.Conn, metadata *C.M tlsOpts := &mihomoVMess.TLSConfig{ Host: host, SkipCertVerify: v.option.SkipCertVerify, + FingerPrint: v.option.Fingerprint, ClientFingerprint: v.option.ClientFingerprint, Reality: v.realityConfig, NextProtos: v.option.ALPN, diff --git a/transport/trojan/trojan.go b/transport/trojan/trojan.go index 09be1124..17f403c1 100644 --- a/transport/trojan/trojan.go +++ b/transport/trojan/trojan.go @@ -129,6 +129,12 @@ func (t *Trojan) StreamWebsocketConn(ctx context.Context, conn net.Conn, wsOptio ServerName: t.option.ServerName, } + var err error + tlsConfig, err = ca.GetSpecifiedFingerprintTLSConfig(tlsConfig, t.option.Fingerprint) + if err != nil { + return nil, err + } + return vmess.StreamWebsocketConn(ctx, conn, &vmess.WebsocketConfig{ Host: wsOptions.Host, Port: wsOptions.Port, From a50339bd5f90ee5dcab2d00e5e35797bcc0b3c2d Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 May 2024 20:23:13 +0800 Subject: [PATCH 13/30] chore: swtich `RtlGetNtVersionNumbers` to `RtlGetVersion` https://go-review.googlesource.com/c/go/+/571015 --- component/ca/fix_windows.go | 5 ++--- constant/features/version.go | 5 +++++ constant/features/version_windows.go | 10 ++++++++++ listener/sing_tun/server_windows.go | 6 ++---- 4 files changed, 19 insertions(+), 7 deletions(-) create mode 100644 constant/features/version.go create mode 100644 constant/features/version_windows.go diff --git a/component/ca/fix_windows.go b/component/ca/fix_windows.go index 00c894d8..42511791 100644 --- a/component/ca/fix_windows.go +++ b/component/ca/fix_windows.go @@ -1,15 +1,14 @@ package ca import ( - "golang.org/x/sys/windows" + "github.com/metacubex/mihomo/constant/features" ) func init() { - majorVersion, _, _ := windows.RtlGetNtVersionNumbers() // crypto/x509: certificate validation in Windows fails to validate IP in SAN // https://github.com/golang/go/issues/37176 // As far as I can tell this is still the case on most older versions of Windows (but seems to be fixed in 10) - if majorVersion < 10 && len(_CaCertificates) > 0 { + if features.WindowsMajorVersion < 10 && len(_CaCertificates) > 0 { DisableSystemCa = true } } diff --git a/constant/features/version.go b/constant/features/version.go new file mode 100644 index 00000000..1710e218 --- /dev/null +++ b/constant/features/version.go @@ -0,0 +1,5 @@ +package features + +var WindowsMajorVersion uint32 +var WindowsMinorVersion uint32 +var WindowsBuildNumber uint32 diff --git a/constant/features/version_windows.go b/constant/features/version_windows.go new file mode 100644 index 00000000..192df950 --- /dev/null +++ b/constant/features/version_windows.go @@ -0,0 +1,10 @@ +package features + +import "golang.org/x/sys/windows" + +func init() { + version := windows.RtlGetVersion() + WindowsMajorVersion = version.MajorVersion + WindowsMinorVersion = version.MinorVersion + WindowsBuildNumber = version.MinorVersion +} diff --git a/listener/sing_tun/server_windows.go b/listener/sing_tun/server_windows.go index 4bc04835..325cf096 100644 --- a/listener/sing_tun/server_windows.go +++ b/listener/sing_tun/server_windows.go @@ -3,11 +3,10 @@ package sing_tun import ( "time" + "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/log" tun "github.com/metacubex/sing-tun" - - "golang.org/x/sys/windows" ) func tunNew(options tun.Options) (tunIf tun.Tun, err error) { @@ -30,8 +29,7 @@ func tunNew(options tun.Options) (tunIf tun.Tun, err error) { func init() { tun.TunnelType = InterfaceName - majorVersion, _, _ := windows.RtlGetNtVersionNumbers() - if majorVersion < 10 { + if features.WindowsMajorVersion < 10 { // to resolve "bind: The requested address is not valid in its context" EnforceBindInterface = true } From 3ae4014b393ea1dccb04f1f93c389cb1ab65b091 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 12 May 2024 20:44:12 +0800 Subject: [PATCH 14/30] chore: disable tfo when lower than Windows 10.0.14393 --- component/dialer/dialer.go | 2 +- component/dialer/tfo.go | 2 ++ component/dialer/tfo_windows.go | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 component/dialer/tfo_windows.go diff --git a/component/dialer/dialer.go b/component/dialer/dialer.go index 8fb5a0a6..c21e638e 100644 --- a/component/dialer/dialer.go +++ b/component/dialer/dialer.go @@ -164,7 +164,7 @@ func dialContext(ctx context.Context, network string, destination netip.Addr, po if opt.mpTcp { setMultiPathTCP(dialer) } - if opt.tfo { + if opt.tfo && !DisableTFO { return dialTFO(ctx, *dialer, network, address) } return dialer.DialContext(ctx, network, address) diff --git a/component/dialer/tfo.go b/component/dialer/tfo.go index 228e9689..76fe94d0 100644 --- a/component/dialer/tfo.go +++ b/component/dialer/tfo.go @@ -9,6 +9,8 @@ import ( "github.com/metacubex/tfo-go" ) +var DisableTFO = false + type tfoConn struct { net.Conn closed bool diff --git a/component/dialer/tfo_windows.go b/component/dialer/tfo_windows.go new file mode 100644 index 00000000..63266118 --- /dev/null +++ b/component/dialer/tfo_windows.go @@ -0,0 +1,11 @@ +package dialer + +import "github.com/metacubex/mihomo/constant/features" + +func init() { + // According to MSDN, this option is available since Windows 10, 1607 + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms738596(v=vs.85).aspx + if features.WindowsMajorVersion < 10 || (features.WindowsMajorVersion == 10 && features.WindowsBuildNumber < 14393) { + DisableTFO = true + } +} From fd7ecc004f8fdb018d9e61a2602d4d66e8c97f3f Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Mon, 13 May 2024 20:30:31 +0800 Subject: [PATCH 15/30] chore: Add filter for include-all-proxies --- adapter/outboundgroup/parser.go | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 876c92fa..941179e0 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" + "github.com/dlclark/regexp2" + "github.com/metacubex/mihomo/adapter/outbound" "github.com/metacubex/mihomo/adapter/provider" "github.com/metacubex/mihomo/common/structure" @@ -70,7 +72,22 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide groupOption.Use = append(groupOption.Use, AllProviders...) } if groupOption.IncludeAllProxies { - groupOption.Proxies = append(groupOption.Proxies, AllProxies...) + if groupOption.Filter != "" { + var filterRegs []*regexp2.Regexp + for _, filter := range strings.Split(groupOption.Filter, "`") { + filterReg := regexp2.MustCompile(filter, 0) + filterRegs = append(filterRegs, filterReg) + } + for _, p := range AllProxies { + for _, filterReg := range filterRegs { + if mat, _ := filterReg.FindStringMatch(p); mat != nil { + groupOption.Proxies = append(groupOption.Proxies, p) + } + } + } + } else { + groupOption.Proxies = append(groupOption.Proxies, AllProxies...) + } } if len(groupOption.Proxies) == 0 && len(groupOption.Use) == 0 { From 5da9ccaa98374f170e028e022bcf5fab881e31fb Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Wed, 15 May 2024 08:32:57 +0800 Subject: [PATCH 16/30] action: Upgrade loongarch golang version --- .github/workflows/build.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4f36e40d..1e2c9dc5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -94,18 +94,18 @@ jobs: with: go-version: ${{ matrix.jobs.goversion }} - - name: Set up Go1.21 loongarch abi1 + - name: Set up Go1.22 loongarch abi1 if: ${{ matrix.jobs.goarch == 'loong64' && matrix.jobs.abi == '1' }} run: | - wget -q https://github.com/xishang0128/loongarch64-golang/releases/download/1.21.5/go1.21.5.linux-amd64-abi1.tar.gz - sudo tar zxf go1.21.5.linux-amd64-abi1.tar.gz -C /usr/local + wget -q https://github.com/xishang0128/loongarch64-golang/releases/download/1.22.0/go1.22.0.linux-amd64-abi1.tar.gz + sudo tar zxf go1.22.0.linux-amd64-abi1.tar.gz -C /usr/local echo "/usr/local/go/bin" >> $GITHUB_PATH - - name: Set up Go1.21 loongarch abi2 + - name: Set up Go1.22 loongarch abi2 if: ${{ matrix.jobs.goarch == 'loong64' && matrix.jobs.abi == '2' }} run: | - wget -q https://github.com/xishang0128/loongarch64-golang/releases/download/1.21.5/go1.21.5.linux-amd64-abi2.tar.gz - sudo tar zxf go1.21.5.linux-amd64-abi2.tar.gz -C /usr/local + wget -q https://github.com/xishang0128/loongarch64-golang/releases/download/1.22.0/go1.22.0.linux-amd64-abi2.tar.gz + sudo tar zxf go1.22.0.linux-amd64-abi2.tar.gz -C /usr/local echo "/usr/local/go/bin" >> $GITHUB_PATH # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 From ed1e7e32c78f0b9a3a61786c9f2decbb022f69fd Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 15 May 2024 09:14:34 +0800 Subject: [PATCH 17/30] action: revert more golang1.22 commit for win7 --- ...42aa09c2f878c4faa576948b07fe625c4707a.diff | 54 ++++++ ...def151adff1af707d82d28f55dba81ceb08e1.diff | 0 ...157f9544922e96945196b47b95664b1e39108.diff | 162 ++++++++++++++++++ .github/workflows/build.yml | 22 ++- 4 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 .github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff rename .github/{ => patch_go122}/693def151adff1af707d82d28f55dba81ceb08e1.diff (100%) create mode 100644 .github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff diff --git a/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff b/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff new file mode 100644 index 00000000..2c682333 --- /dev/null +++ b/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff @@ -0,0 +1,54 @@ +diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go +index 06e684c7116b4..b311a5c74684b 100644 +--- a/src/syscall/exec_windows.go ++++ b/src/syscall/exec_windows.go +@@ -319,17 +319,6 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle + } + } + +- var maj, min, build uint32 +- rtlGetNtVersionNumbers(&maj, &min, &build) +- isWin7 := maj < 6 || (maj == 6 && min <= 1) +- // NT kernel handles are divisible by 4, with the bottom 3 bits left as +- // a tag. The fully set tag correlates with the types of handles we're +- // concerned about here. Except, the kernel will interpret some +- // special handle values, like -1, -2, and so forth, so kernelbase.dll +- // checks to see that those bottom three bits are checked, but that top +- // bit is not checked. +- isLegacyWin7ConsoleHandle := func(handle Handle) bool { return isWin7 && handle&0x10000003 == 3 } +- + p, _ := GetCurrentProcess() + parentProcess := p + if sys.ParentProcess != 0 { +@@ -338,15 +327,7 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle + fd := make([]Handle, len(attr.Files)) + for i := range attr.Files { + if attr.Files[i] > 0 { +- destinationProcessHandle := parentProcess +- +- // On Windows 7, console handles aren't real handles, and can only be duplicated +- // into the current process, not a parent one, which amounts to the same thing. +- if parentProcess != p && isLegacyWin7ConsoleHandle(Handle(attr.Files[i])) { +- destinationProcessHandle = p +- } +- +- err := DuplicateHandle(p, Handle(attr.Files[i]), destinationProcessHandle, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) ++ err := DuplicateHandle(p, Handle(attr.Files[i]), parentProcess, &fd[i], 0, true, DUPLICATE_SAME_ACCESS) + if err != nil { + return 0, 0, err + } +@@ -377,14 +358,6 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle + + fd = append(fd, sys.AdditionalInheritedHandles...) + +- // On Windows 7, console handles aren't real handles, so don't pass them +- // through to PROC_THREAD_ATTRIBUTE_HANDLE_LIST. +- for i := range fd { +- if isLegacyWin7ConsoleHandle(fd[i]) { +- fd[i] = 0 +- } +- } +- + // The presence of a NULL handle in the list is enough to cause PROC_THREAD_ATTRIBUTE_HANDLE_LIST + // to treat the entire list as empty, so remove NULL handles. + j := 0 \ No newline at end of file diff --git a/.github/693def151adff1af707d82d28f55dba81ceb08e1.diff b/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff similarity index 100% rename from .github/693def151adff1af707d82d28f55dba81ceb08e1.diff rename to .github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff diff --git a/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff b/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff new file mode 100644 index 00000000..c1fc5f6d --- /dev/null +++ b/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff @@ -0,0 +1,162 @@ +diff --git a/src/net/hook_windows.go b/src/net/hook_windows.go +index ab8656cbbf343..28c49cc6de7e7 100644 +--- a/src/net/hook_windows.go ++++ b/src/net/hook_windows.go +@@ -14,7 +14,6 @@ var ( + testHookDialChannel = func() { time.Sleep(time.Millisecond) } // see golang.org/issue/5349 + + // Placeholders for socket system calls. +- socketFunc func(int, int, int) (syscall.Handle, error) = syscall.Socket + wsaSocketFunc func(int32, int32, int32, *syscall.WSAProtocolInfo, uint32, uint32) (syscall.Handle, error) = windows.WSASocket + connectFunc func(syscall.Handle, syscall.Sockaddr) error = syscall.Connect + listenFunc func(syscall.Handle, int) error = syscall.Listen +diff --git a/src/net/internal/socktest/main_test.go b/src/net/internal/socktest/main_test.go +index 0197feb3f199a..967ce6795aedb 100644 +--- a/src/net/internal/socktest/main_test.go ++++ b/src/net/internal/socktest/main_test.go +@@ -2,7 +2,7 @@ + // Use of this source code is governed by a BSD-style + // license that can be found in the LICENSE file. + +-//go:build !js && !plan9 && !wasip1 ++//go:build !js && !plan9 && !wasip1 && !windows + + package socktest_test + +diff --git a/src/net/internal/socktest/main_windows_test.go b/src/net/internal/socktest/main_windows_test.go +deleted file mode 100644 +index df1cb97784b51..0000000000000 +--- a/src/net/internal/socktest/main_windows_test.go ++++ /dev/null +@@ -1,22 +0,0 @@ +-// Copyright 2015 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 socktest_test +- +-import "syscall" +- +-var ( +- socketFunc func(int, int, int) (syscall.Handle, error) +- closeFunc func(syscall.Handle) error +-) +- +-func installTestHooks() { +- socketFunc = sw.Socket +- closeFunc = sw.Closesocket +-} +- +-func uninstallTestHooks() { +- socketFunc = syscall.Socket +- closeFunc = syscall.Closesocket +-} +diff --git a/src/net/internal/socktest/sys_windows.go b/src/net/internal/socktest/sys_windows.go +index 8c1c862f33c9b..1c42e5c7f34b7 100644 +--- a/src/net/internal/socktest/sys_windows.go ++++ b/src/net/internal/socktest/sys_windows.go +@@ -9,38 +9,6 @@ import ( + "syscall" + ) + +-// Socket wraps syscall.Socket. +-func (sw *Switch) Socket(family, sotype, proto int) (s syscall.Handle, err error) { +- sw.once.Do(sw.init) +- +- so := &Status{Cookie: cookie(family, sotype, proto)} +- sw.fmu.RLock() +- f, _ := sw.fltab[FilterSocket] +- sw.fmu.RUnlock() +- +- af, err := f.apply(so) +- if err != nil { +- return syscall.InvalidHandle, err +- } +- s, so.Err = syscall.Socket(family, sotype, proto) +- if err = af.apply(so); err != nil { +- if so.Err == nil { +- syscall.Closesocket(s) +- } +- return syscall.InvalidHandle, err +- } +- +- sw.smu.Lock() +- defer sw.smu.Unlock() +- if so.Err != nil { +- sw.stats.getLocked(so.Cookie).OpenFailed++ +- return syscall.InvalidHandle, so.Err +- } +- nso := sw.addLocked(s, family, sotype, proto) +- sw.stats.getLocked(nso.Cookie).Opened++ +- return s, nil +-} +- + // WSASocket wraps [syscall.WSASocket]. + func (sw *Switch) WSASocket(family, sotype, proto int32, protinfo *syscall.WSAProtocolInfo, group uint32, flags uint32) (s syscall.Handle, err error) { + sw.once.Do(sw.init) +diff --git a/src/net/main_windows_test.go b/src/net/main_windows_test.go +index 07f21b72eb1fc..bc024c0bbd82d 100644 +--- a/src/net/main_windows_test.go ++++ b/src/net/main_windows_test.go +@@ -8,7 +8,6 @@ import "internal/poll" + + var ( + // Placeholders for saving original socket system calls. +- origSocket = socketFunc + origWSASocket = wsaSocketFunc + origClosesocket = poll.CloseFunc + origConnect = connectFunc +@@ -18,7 +17,6 @@ var ( + ) + + func installTestHooks() { +- socketFunc = sw.Socket + wsaSocketFunc = sw.WSASocket + poll.CloseFunc = sw.Closesocket + connectFunc = sw.Connect +@@ -28,7 +26,6 @@ func installTestHooks() { + } + + func uninstallTestHooks() { +- socketFunc = origSocket + wsaSocketFunc = origWSASocket + poll.CloseFunc = origClosesocket + connectFunc = origConnect +diff --git a/src/net/sock_windows.go b/src/net/sock_windows.go +index fa11c7af2e727..5540135a2c43e 100644 +--- a/src/net/sock_windows.go ++++ b/src/net/sock_windows.go +@@ -19,21 +19,6 @@ func maxListenerBacklog() int { + func sysSocket(family, sotype, proto int) (syscall.Handle, error) { + s, err := wsaSocketFunc(int32(family), int32(sotype), int32(proto), + nil, 0, windows.WSA_FLAG_OVERLAPPED|windows.WSA_FLAG_NO_HANDLE_INHERIT) +- if err == nil { +- return s, nil +- } +- // WSA_FLAG_NO_HANDLE_INHERIT flag is not supported on some +- // old versions of Windows, see +- // https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx +- // for details. Just use syscall.Socket, if windows.WSASocket failed. +- +- // See ../syscall/exec_unix.go for description of ForkLock. +- syscall.ForkLock.RLock() +- s, err = socketFunc(family, sotype, proto) +- if err == nil { +- syscall.CloseOnExec(s) +- } +- syscall.ForkLock.RUnlock() + if err != nil { + return syscall.InvalidHandle, os.NewSyscallError("socket", err) + } +diff --git a/src/syscall/exec_windows.go b/src/syscall/exec_windows.go +index 0a93bc0a80d4e..06e684c7116b4 100644 +--- a/src/syscall/exec_windows.go ++++ b/src/syscall/exec_windows.go +@@ -14,6 +14,7 @@ import ( + "unsafe" + ) + ++// ForkLock is not used on Windows. + var ForkLock sync.RWMutex + + // EscapeArg rewrites command line argument s as prescribed \ No newline at end of file diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1e2c9dc5..9556c7c3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -64,6 +64,13 @@ jobs: - { goos: android, goarch: arm, ndk: armv7a-linux-androideabi34, output: armv7 } - { goos: android, goarch: arm64, ndk: aarch64-linux-android34, output: arm64-v8 } + # Go 1.21 can revert commit `9e4385` to work on Windows 7 + # https://github.com/golang/go/issues/64622#issuecomment-1847475161 + # (OR we can just use golang1.21.4 which unneeded any patch) + - { goos: windows, goarch: '386', output: '386-go121', goversion: '1.21' } + - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go121, goversion: '1.21' } + - { goos: windows, goarch: amd64, goamd64: v3, output: amd64-go121, goversion: '1.21' } + # 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. - { goos: windows, goarch: '386', output: '386-go120', goversion: '1.20' } - { goos: windows, goarch: amd64, goamd64: v1, output: amd64-compatible-go120, goversion: '1.20' } @@ -111,11 +118,24 @@ jobs: # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 # this patch file only works on golang1.22.x # that means after golang1.23 release it must be changed + # revert: + # 693def151adff1af707d82d28f55dba81ceb08e1: "crypto/rand,runtime: switch RtlGenRandom for ProcessPrng" + # 7c1157f9544922e96945196b47b95664b1e39108: "net: remove sysSocket fallback for Windows 7" + # 48042aa09c2f878c4faa576948b07fe625c4707a: "syscall: remove Windows 7 console handle workaround" - name: Revert Golang1.22 commit for Windows7/8 if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '' }} run: | cd $(go env GOROOT) - patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/693def151adff1af707d82d28f55dba81ceb08e1.diff + patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/patch_go122/693def151adff1af707d82d28f55dba81ceb08e1.diff + patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/patch_go122/7c1157f9544922e96945196b47b95664b1e39108.diff + patch --verbose -R -p 1 < $GITHUB_WORKSPACE/.github/patch_go122/48042aa09c2f878c4faa576948b07fe625c4707a.diff + + # modify from https://github.com/restic/restic/issues/4636#issuecomment-1896455557 + - name: Revert Golang1.21 commit for Windows7/8 + if: ${{ matrix.jobs.goos == 'windows' && matrix.jobs.goversion == '1.21' }} + run: | + cd $(go env GOROOT) + curl https://github.com/golang/go/commit/9e43850a3298a9b8b1162ba0033d4c53f8637571.diff | patch --verbose -R -p 1 - name: Set variables if: ${{github.ref_name=='Alpha'}} From 1bc3c16b5938706fb8e5c576ecf62999fbd8ffc2 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 15 May 2024 10:44:56 +0800 Subject: [PATCH 18/30] feat: add `PROCESS-NAME-REGEX` and `PROCESS-PATH-REGEX` --- adapter/outboundgroup/groupbase.go | 10 +++++----- adapter/outboundgroup/parser.go | 4 ++-- adapter/provider/healthcheck.go | 4 ++-- adapter/provider/provider.go | 8 ++++---- constant/rule.go | 12 +++++++++--- rules/common/domain_regex.go | 11 ++++++----- rules/common/process.go | 30 ++++++++++++++++++++++++++++-- rules/parser.go | 8 ++++++-- 8 files changed, 62 insertions(+), 25 deletions(-) diff --git a/adapter/outboundgroup/groupbase.go b/adapter/outboundgroup/groupbase.go index b39ee3a6..69fbb617 100644 --- a/adapter/outboundgroup/groupbase.go +++ b/adapter/outboundgroup/groupbase.go @@ -48,7 +48,7 @@ type GroupBaseOption struct { func NewGroupBase(opt GroupBaseOption) *GroupBase { var excludeFilterReg *regexp2.Regexp if opt.excludeFilter != "" { - excludeFilterReg = regexp2.MustCompile(opt.excludeFilter, 0) + excludeFilterReg = regexp2.MustCompile(opt.excludeFilter, regexp2.None) } var excludeTypeArray []string if opt.excludeType != "" { @@ -58,7 +58,7 @@ func NewGroupBase(opt GroupBaseOption) *GroupBase { var filterRegs []*regexp2.Regexp if opt.filter != "" { for _, filter := range strings.Split(opt.filter, "`") { - filterReg := regexp2.MustCompile(filter, 0) + filterReg := regexp2.MustCompile(filter, regexp2.None) filterRegs = append(filterRegs, filterReg) } } @@ -126,7 +126,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { for _, filterReg := range gb.filterRegs { for _, p := range proxies { name := p.Name() - if mat, _ := filterReg.FindStringMatch(name); mat != nil { + if mat, _ := filterReg.MatchString(name); mat { if _, ok := proxiesSet[name]; !ok { proxiesSet[name] = struct{}{} newProxies = append(newProxies, p) @@ -150,7 +150,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { for _, filterReg := range gb.filterRegs { for _, p := range proxies { name := p.Name() - if mat, _ := filterReg.FindStringMatch(name); mat != nil { + if mat, _ := filterReg.MatchString(name); mat { if _, ok := proxiesSet[name]; !ok { proxiesSet[name] = struct{}{} newProxies = append(newProxies, p) @@ -191,7 +191,7 @@ func (gb *GroupBase) GetProxies(touch bool) []C.Proxy { var newProxies []C.Proxy for _, p := range proxies { name := p.Name() - if mat, _ := gb.excludeFilterReg.FindStringMatch(name); mat != nil { + if mat, _ := gb.excludeFilterReg.MatchString(name); mat { continue } newProxies = append(newProxies, p) diff --git a/adapter/outboundgroup/parser.go b/adapter/outboundgroup/parser.go index 941179e0..67dc104d 100644 --- a/adapter/outboundgroup/parser.go +++ b/adapter/outboundgroup/parser.go @@ -75,12 +75,12 @@ func ParseProxyGroup(config map[string]any, proxyMap map[string]C.Proxy, provide if groupOption.Filter != "" { var filterRegs []*regexp2.Regexp for _, filter := range strings.Split(groupOption.Filter, "`") { - filterReg := regexp2.MustCompile(filter, 0) + filterReg := regexp2.MustCompile(filter, regexp2.None) filterRegs = append(filterRegs, filterReg) } for _, p := range AllProxies { for _, filterReg := range filterRegs { - if mat, _ := filterReg.FindStringMatch(p); mat != nil { + if mat, _ := filterReg.MatchString(p); mat { groupOption.Proxies = append(groupOption.Proxies, p) } } diff --git a/adapter/provider/healthcheck.go b/adapter/provider/healthcheck.go index bfbcf8d9..8b5e8338 100644 --- a/adapter/provider/healthcheck.go +++ b/adapter/provider/healthcheck.go @@ -181,14 +181,14 @@ func (hc *HealthCheck) execute(b *batch.Batch[bool], url, uid string, option *ex filters = append(filters, filter) } - filterReg = regexp2.MustCompile(strings.Join(filters, "|"), 0) + filterReg = regexp2.MustCompile(strings.Join(filters, "|"), regexp2.None) } } for _, proxy := range hc.proxies { // skip proxies that do not require health check if filterReg != nil { - if match, _ := filterReg.FindStringMatch(proxy.Name()); match == nil { + if match, _ := filterReg.MatchString(proxy.Name()); !match { continue } } diff --git a/adapter/provider/provider.go b/adapter/provider/provider.go index a40a50ec..daef017c 100644 --- a/adapter/provider/provider.go +++ b/adapter/provider/provider.go @@ -169,7 +169,7 @@ func stopProxyProvider(pd *ProxySetProvider) { } func NewProxySetProvider(name string, interval time.Duration, filter string, excludeFilter string, excludeType string, dialerProxy string, override OverrideSchema, vehicle types.Vehicle, hc *HealthCheck) (*ProxySetProvider, error) { - excludeFilterReg, err := regexp2.Compile(excludeFilter, 0) + excludeFilterReg, err := regexp2.Compile(excludeFilter, regexp2.None) if err != nil { return nil, fmt.Errorf("invalid excludeFilter regex: %w", err) } @@ -180,7 +180,7 @@ func NewProxySetProvider(name string, interval time.Duration, filter string, exc var filterRegs []*regexp2.Regexp for _, filter := range strings.Split(filter, "`") { - filterReg, err := regexp2.Compile(filter, 0) + filterReg, err := regexp2.Compile(filter, regexp2.None) if err != nil { return nil, fmt.Errorf("invalid filter regex: %w", err) } @@ -356,12 +356,12 @@ func proxiesParseAndFilter(filter string, excludeFilter string, excludeTypeArray continue } if len(excludeFilter) > 0 { - if mat, _ := excludeFilterReg.FindStringMatch(name); mat != nil { + if mat, _ := excludeFilterReg.MatchString(name); mat { continue } } if len(filter) > 0 { - if mat, _ := filterReg.FindStringMatch(name); mat == nil { + if mat, _ := filterReg.MatchString(name); !mat { continue } } diff --git a/constant/rule.go b/constant/rule.go index 8fdd75a6..161c200a 100644 --- a/constant/rule.go +++ b/constant/rule.go @@ -22,8 +22,10 @@ const ( InUser InName InType - Process + ProcessName ProcessPath + ProcessNameRegex + ProcessPathRegex RuleSet Network Uid @@ -76,10 +78,14 @@ func (rt RuleType) String() string { return "InName" case InType: return "InType" - case Process: - return "Process" + case ProcessName: + return "ProcessName" case ProcessPath: return "ProcessPath" + case ProcessNameRegex: + return "ProcessNameRegex" + case ProcessPathRegex: + return "ProcessPathRegex" case MATCH: return "Match" case RuleSet: diff --git a/rules/common/domain_regex.go b/rules/common/domain_regex.go index 3d961542..d214a772 100644 --- a/rules/common/domain_regex.go +++ b/rules/common/domain_regex.go @@ -1,14 +1,14 @@ package common import ( - "regexp" - C "github.com/metacubex/mihomo/constant" + + "github.com/dlclark/regexp2" ) type DomainRegex struct { *Base - regex *regexp.Regexp + regex *regexp2.Regexp adapter string } @@ -18,7 +18,8 @@ func (dr *DomainRegex) RuleType() C.RuleType { func (dr *DomainRegex) Match(metadata *C.Metadata) (bool, string) { domain := metadata.RuleHost() - return dr.regex.MatchString(domain), dr.adapter + match, _ := dr.regex.MatchString(domain) + return match, dr.adapter } func (dr *DomainRegex) Adapter() string { @@ -30,7 +31,7 @@ func (dr *DomainRegex) Payload() string { } func NewDomainRegex(regex string, adapter string) (*DomainRegex, error) { - r, err := regexp.Compile(regex) + r, err := regexp2.Compile(regex, regexp2.IgnoreCase) if err != nil { return nil, err } diff --git a/rules/common/process.go b/rules/common/process.go index ce643594..8932e946 100644 --- a/rules/common/process.go +++ b/rules/common/process.go @@ -4,6 +4,8 @@ import ( "strings" C "github.com/metacubex/mihomo/constant" + + "github.com/dlclark/regexp2" ) type Process struct { @@ -11,21 +13,36 @@ type Process struct { adapter string process string nameOnly bool + regexp *regexp2.Regexp } func (ps *Process) RuleType() C.RuleType { if ps.nameOnly { - return C.Process + if ps.regexp != nil { + return C.ProcessNameRegex + } + return C.ProcessName } + if ps.regexp != nil { + return C.ProcessPathRegex + } return C.ProcessPath } func (ps *Process) Match(metadata *C.Metadata) (bool, string) { if ps.nameOnly { + if ps.regexp != nil { + match, _ := ps.regexp.MatchString(metadata.Process) + return match, ps.adapter + } return strings.EqualFold(metadata.Process, ps.process), ps.adapter } + if ps.regexp != nil { + match, _ := ps.regexp.MatchString(metadata.ProcessPath) + return match, ps.adapter + } return strings.EqualFold(metadata.ProcessPath, ps.process), ps.adapter } @@ -41,11 +58,20 @@ func (ps *Process) ShouldFindProcess() bool { return true } -func NewProcess(process string, adapter string, nameOnly bool) (*Process, error) { +func NewProcess(process string, adapter string, nameOnly bool, regex bool) (*Process, error) { + var r *regexp2.Regexp + var err error + if regex { + r, err = regexp2.Compile(process, regexp2.IgnoreCase) + if err != nil { + return nil, err + } + } return &Process{ Base: &Base{}, adapter: adapter, process: process, nameOnly: nameOnly, + regexp: r, }, nil } diff --git a/rules/parser.go b/rules/parser.go index 032a02e4..9b1f5520 100644 --- a/rules/parser.go +++ b/rules/parser.go @@ -50,9 +50,13 @@ func ParseRule(tp, payload, target string, params []string, subRules map[string] case "DSCP": parsed, parseErr = RC.NewDSCP(payload, target) case "PROCESS-NAME": - parsed, parseErr = RC.NewProcess(payload, target, true) + parsed, parseErr = RC.NewProcess(payload, target, true, false) case "PROCESS-PATH": - parsed, parseErr = RC.NewProcess(payload, target, false) + parsed, parseErr = RC.NewProcess(payload, target, false, false) + case "PROCESS-NAME-REGEX": + parsed, parseErr = RC.NewProcess(payload, target, true, true) + case "PROCESS-PATH-REGEX": + parsed, parseErr = RC.NewProcess(payload, target, false, true) case "NETWORK": parsed, parseErr = RC.NewNetworkType(payload, target) case "UID": From 87877d1b80587edb674fcd5bb65e7345eb871b18 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Wed, 15 May 2024 13:53:18 +0800 Subject: [PATCH 19/30] fix: don't ignore http.NewRequest's error --- component/tls/reality.go | 5 ++++- transport/simple-obfs/http.go | 7 +++++-- transport/vmess/http.go | 5 ++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index 687ef1ef..7728b4b2 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -139,7 +139,10 @@ func realityClientFallback(uConn net.Conn, serverName string, fingerprint utls.C }, }, } - request, _ := http.NewRequest("GET", "https://"+serverName, nil) + request, err := http.NewRequest("GET", "https://"+serverName, nil) + if err != nil { + return + } 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) diff --git a/transport/simple-obfs/http.go b/transport/simple-obfs/http.go index 681c1864..a38b1d69 100644 --- a/transport/simple-obfs/http.go +++ b/transport/simple-obfs/http.go @@ -65,7 +65,10 @@ func (ho *HTTPObfs) Write(b []byte) (int, error) { if ho.firstRequest { randBytes := make([]byte, 16) fastrand.Read(randBytes) - req, _ := http.NewRequest("GET", fmt.Sprintf("http://%s/", ho.host), bytes.NewBuffer(b[:])) + req, err := http.NewRequest("GET", fmt.Sprintf("http://%s/", ho.host), bytes.NewBuffer(b[:])) + if err != nil { + return 0, err + } 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") @@ -75,7 +78,7 @@ func (ho *HTTPObfs) Write(b []byte) (int, error) { } req.Header.Set("Sec-WebSocket-Key", base64.URLEncoding.EncodeToString(randBytes)) req.ContentLength = int64(len(b)) - err := req.Write(ho.Conn) + err = req.Write(ho.Conn) ho.firstRequest = false return len(b), err } diff --git a/transport/vmess/http.go b/transport/vmess/http.go index b023fee4..4a1b93ec 100644 --- a/transport/vmess/http.go +++ b/transport/vmess/http.go @@ -66,7 +66,10 @@ func (hc *httpConn) Write(b []byte) (int, error) { } u := fmt.Sprintf("http://%s%s", net.JoinHostPort(host, "80"), path) - req, _ := http.NewRequest(utils.EmptyOr(hc.cfg.Method, http.MethodGet), u, bytes.NewBuffer(b)) + req, err := http.NewRequest(utils.EmptyOr(hc.cfg.Method, http.MethodGet), u, bytes.NewBuffer(b)) + if err != nil { + return 0, err + } for key, list := range hc.cfg.Headers { req.Header.Set(key, list[fastrand.Intn(len(list))]) } From fe88f0e437fa7ea6a4b1614b902b3edb3acee2e0 Mon Sep 17 00:00:00 2001 From: xishang0128 Date: Wed, 15 May 2024 15:38:55 +0800 Subject: [PATCH 20/30] chore: Ensure that some expressions take effect --- config/config.go | 2 +- rules/provider/classical_strategy.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/config.go b/config/config.go index b76c40ff..311fd2e2 100644 --- a/config/config.go +++ b/config/config.go @@ -927,7 +927,7 @@ func parseRules(rulesConfig []string, proxies map[string]C.Proxy, subRules map[s l := len(rule) - if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" || ruleName == "SUB-RULE" || ruleName == "DOMAIN-REGEX" { + if ruleName == "NOT" || ruleName == "OR" || ruleName == "AND" || ruleName == "SUB-RULE" || ruleName == "DOMAIN-REGEX" || ruleName == "PROCESS-NAME-REGEX" || ruleName == "PROCESS-PATH-REGEX" { target = rule[l-1] payload = strings.Join(rule[1:l-1], ",") } else { diff --git a/rules/provider/classical_strategy.go b/rules/provider/classical_strategy.go index 6a2dccd5..8353ebce 100644 --- a/rules/provider/classical_strategy.go +++ b/rules/provider/classical_strategy.go @@ -77,7 +77,7 @@ func ruleParse(ruleRaw string) (string, string, []string) { } else if len(item) == 2 { return item[0], item[1], nil } else if len(item) > 2 { - if item[0] == "NOT" || item[0] == "OR" || item[0] == "AND" || item[0] == "SUB-RULE" || item[0] == "DOMAIN-REGEX" { + if item[0] == "NOT" || item[0] == "OR" || item[0] == "AND" || item[0] == "SUB-RULE" || item[0] == "DOMAIN-REGEX" || item[0] == "PROCESS-NAME-REGEX" || item[0] == "PROCESS-PATH-REGEX" { return item[0], strings.Join(item[1:len(item)], ","), nil } else { return item[0], item[1], item[2:] From 5c3a9b1dfcd4d115c7267781d1e1551f0df325a0 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Fri, 17 May 2024 11:49:09 +0800 Subject: [PATCH 21/30] fix: geo auto update #1261 --- .../updater/update_core.go | 2 +- {config => component/updater}/update_geo.go | 94 ++++++++++++++++++- {config => component/updater}/update_ui.go | 6 +- .../updater/utils.go | 23 +++++ config/config.go | 19 ++-- config/utils.go | 23 ----- hub/route/configs.go | 31 ++---- hub/route/upgrade.go | 10 +- main.go | 50 +--------- 9 files changed, 144 insertions(+), 114 deletions(-) rename hub/updater/updater.go => component/updater/update_core.go (99%) rename {config => component/updater}/update_geo.go (52%) rename {config => component/updater}/update_ui.go (97%) rename hub/updater/limitedreader.go => component/updater/utils.go (70%) diff --git a/hub/updater/updater.go b/component/updater/update_core.go similarity index 99% rename from hub/updater/updater.go rename to component/updater/update_core.go index df5da3f4..0070fbb1 100644 --- a/hub/updater/updater.go +++ b/component/updater/update_core.go @@ -67,7 +67,7 @@ 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(execPath string) (err error) { +func UpdateCore(execPath string) (err error) { mu.Lock() defer mu.Unlock() diff --git a/config/update_geo.go b/component/updater/update_geo.go similarity index 52% rename from config/update_geo.go rename to component/updater/update_geo.go index 43cac25c..a98d94dc 100644 --- a/config/update_geo.go +++ b/component/updater/update_geo.go @@ -1,18 +1,29 @@ -package config +package updater import ( + "errors" "fmt" + "os" "runtime" + "sync" + "time" + "github.com/metacubex/mihomo/common/atomic" "github.com/metacubex/mihomo/component/geodata" _ "github.com/metacubex/mihomo/component/geodata/standard" "github.com/metacubex/mihomo/component/mmdb" C "github.com/metacubex/mihomo/constant" + "github.com/metacubex/mihomo/log" "github.com/oschwald/maxminddb-golang" ) -func UpdateGeoDatabases() error { +var ( + updateGeoMux sync.Mutex + UpdatingGeo atomic.Bool +) + +func updateGeoDatabases() error { defer runtime.GC() geoLoader, err := geodata.GetGeoDataLoader("standard") if err != nil { @@ -88,3 +99,82 @@ func UpdateGeoDatabases() error { return nil } + +func UpdateGeoDatabases() error { + log.Infoln("[GEO] Start updating GEO database") + + updateGeoMux.Lock() + + if UpdatingGeo.Load() { + updateGeoMux.Unlock() + return errors.New("GEO database is updating, skip") + } + + UpdatingGeo.Store(true) + updateGeoMux.Unlock() + + defer func() { + UpdatingGeo.Store(false) + }() + + log.Infoln("[GEO] Updating GEO database") + + if err := updateGeoDatabases(); err != nil { + log.Errorln("[GEO] update GEO database error: %s", err.Error()) + return err + } + + return nil +} + +func getUpdateTime() (err error, time time.Time) { + var fileInfo os.FileInfo + if C.GeodataMode { + fileInfo, err = os.Stat(C.Path.GeoIP()) + if err != nil { + return err, time + } + } else { + fileInfo, err = os.Stat(C.Path.MMDB()) + if err != nil { + return err, time + } + } + + return nil, fileInfo.ModTime() +} + +func RegisterGeoUpdater() { + if C.GeoUpdateInterval <= 0 { + log.Errorln("[GEO] Invalid update interval: %d", C.GeoUpdateInterval) + return + } + + ticker := time.NewTicker(time.Duration(C.GeoUpdateInterval) * time.Hour) + defer ticker.Stop() + + log.Infoln("[GEO] update GEO database every %d hours", C.GeoUpdateInterval) + go func() { + err, lastUpdate := getUpdateTime() + if err != nil { + log.Errorln("[GEO] Get GEO database update time error: %s", err.Error()) + return + } + + log.Infoln("[GEO] last update time %s", lastUpdate) + if lastUpdate.Add(time.Duration(C.GeoUpdateInterval) * time.Hour).Before(time.Now()) { + log.Infoln("[GEO] Database has not been updated for %v, update now", time.Duration(C.GeoUpdateInterval)*time.Hour) + if err := UpdateGeoDatabases(); err != nil { + log.Errorln("[GEO] Failed to update GEO database: %s", err.Error()) + return + } + } + + for range ticker.C { + if err := UpdateGeoDatabases(); err != nil { + log.Errorln("[GEO] Failed to update GEO database: %s", err.Error()) + return + } + } + }() +} diff --git a/config/update_ui.go b/component/updater/update_ui.go similarity index 97% rename from config/update_ui.go rename to component/updater/update_ui.go index cff1d6d7..85452ba5 100644 --- a/config/update_ui.go +++ b/component/updater/update_ui.go @@ -1,4 +1,4 @@ -package config +package updater import ( "archive/zip" @@ -29,7 +29,7 @@ func UpdateUI() error { xdMutex.Lock() defer xdMutex.Unlock() - err := prepare() + err := prepare_ui() if err != nil { return err } @@ -64,7 +64,7 @@ func UpdateUI() error { return nil } -func prepare() error { +func prepare_ui() error { if ExternalUIPath == "" || ExternalUIURL == "" { return ErrIncompleteConf } diff --git a/hub/updater/limitedreader.go b/component/updater/utils.go similarity index 70% rename from hub/updater/limitedreader.go rename to component/updater/utils.go index c31db601..0eecfc6c 100644 --- a/hub/updater/limitedreader.go +++ b/component/updater/utils.go @@ -1,12 +1,35 @@ package updater import ( + "context" "fmt" "io" + "net/http" + "os" + "time" + + mihomoHttp "github.com/metacubex/mihomo/component/http" + C "github.com/metacubex/mihomo/constant" "golang.org/x/exp/constraints" ) +func downloadForBytes(url string) ([]byte, error) { + ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) + defer cancel() + resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, 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) +} + // LimitReachedError records the limit and the operation that caused it. type LimitReachedError struct { Limit int64 diff --git a/config/config.go b/config/config.go index 311fd2e2..9bc0afc8 100644 --- a/config/config.go +++ b/config/config.go @@ -28,6 +28,7 @@ import ( SNIFF "github.com/metacubex/mihomo/component/sniffer" tlsC "github.com/metacubex/mihomo/component/tls" "github.com/metacubex/mihomo/component/trie" + "github.com/metacubex/mihomo/component/updater" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/constant/features" providerTypes "github.com/metacubex/mihomo/constant/provider" @@ -640,28 +641,28 @@ func parseGeneral(cfg *RawConfig) (*General, error) { N.KeepAliveInterval = time.Duration(cfg.KeepAliveInterval) * time.Second } - ExternalUIPath = cfg.ExternalUI + updater.ExternalUIPath = cfg.ExternalUI // checkout externalUI exist - if ExternalUIPath != "" { - ExternalUIPath = C.Path.Resolve(ExternalUIPath) - if _, err := os.Stat(ExternalUIPath); os.IsNotExist(err) { + if updater.ExternalUIPath != "" { + updater.ExternalUIPath = C.Path.Resolve(updater.ExternalUIPath) + if _, err := os.Stat(updater.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) + log.Warnln("external-ui: %s does not exist, creating folder in %s", updater.ExternalUIPath, defaultUIpath) if err := os.MkdirAll(defaultUIpath, os.ModePerm); err != nil { return nil, err } - ExternalUIPath = defaultUIpath + updater.ExternalUIPath = defaultUIpath cfg.ExternalUI = defaultUIpath } } // checkout UIpath/name exist if cfg.ExternalUIName != "" { - ExternalUIName = cfg.ExternalUIName + updater.ExternalUIName = cfg.ExternalUIName } else { - ExternalUIFolder = ExternalUIPath + updater.ExternalUIFolder = updater.ExternalUIPath } if cfg.ExternalUIURL != "" { - ExternalUIURL = cfg.ExternalUIURL + updater.ExternalUIURL = cfg.ExternalUIURL } cfg.Tun.RedirectToTun = cfg.EBpf.RedirectToTun diff --git a/config/utils.go b/config/utils.go index 66bf3441..f87fb341 100644 --- a/config/utils.go +++ b/config/utils.go @@ -1,38 +1,15 @@ package config import ( - "context" "fmt" - "io" "net" - "net/http" "net/netip" - "os" "strings" - "time" "github.com/metacubex/mihomo/adapter/outboundgroup" "github.com/metacubex/mihomo/common/structure" - mihomoHttp "github.com/metacubex/mihomo/component/http" - C "github.com/metacubex/mihomo/constant" ) -func downloadForBytes(url string) ([]byte, error) { - ctx, cancel := context.WithTimeout(context.Background(), time.Second*90) - defer cancel() - resp, err := mihomoHttp.HttpRequest(ctx, url, http.MethodGet, http.Header{"User-Agent": {C.UA}}, 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/hub/route/configs.go b/hub/route/configs.go index 653e4351..47fd26e0 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -4,11 +4,11 @@ import ( "net/http" "net/netip" "path/filepath" - "sync" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/component/dialer" "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/component/updater" "github.com/metacubex/mihomo/config" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/hub/executor" @@ -21,11 +21,6 @@ import ( "github.com/go-chi/render" ) -var ( - updateGeoMux sync.Mutex - updatingGeo = false -) - func configRouter() http.Handler { r := chi.NewRouter() r.Get("/", getConfigs) @@ -369,30 +364,20 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) { } func updateGeoDatabases(w http.ResponseWriter, r *http.Request) { - updateGeoMux.Lock() - - if updatingGeo { - updateGeoMux.Unlock() + if updater.UpdatingGeo.Load() { render.Status(r, http.StatusBadRequest) render.JSON(w, r, newError("updating...")) return } - updatingGeo = true - updateGeoMux.Unlock() + err := updater.UpdateGeoDatabases() + if err != nil { + render.Status(r, http.StatusBadRequest) + render.JSON(w, r, newError(err.Error())) + return + } go func() { - defer func() { - updatingGeo = false - }() - - log.Warnln("[REST-API] updating GEO databases...") - - if err := config.UpdateGeoDatabases(); err != nil { - log.Errorln("[REST-API] update GEO databases failed: %v", err) - return - } - cfg, err := executor.ParseWithPath(C.Path.Config()) if err != nil { log.Errorln("[REST-API] update GEO databases failed: %v", err) diff --git a/hub/route/upgrade.go b/hub/route/upgrade.go index ea371798..db00af5c 100644 --- a/hub/route/upgrade.go +++ b/hub/route/upgrade.go @@ -6,8 +6,7 @@ import ( "net/http" "os" - "github.com/metacubex/mihomo/config" - "github.com/metacubex/mihomo/hub/updater" + "github.com/metacubex/mihomo/component/updater" "github.com/metacubex/mihomo/log" "github.com/go-chi/chi/v5" @@ -18,6 +17,7 @@ func upgradeRouter() http.Handler { r := chi.NewRouter() r.Post("/", upgradeCore) r.Post("/ui", updateUI) + r.Post("/geo", updateGeoDatabases) return r } @@ -31,7 +31,7 @@ func upgradeCore(w http.ResponseWriter, r *http.Request) { return } - err = updater.Update(execPath) + err = updater.UpdateCore(execPath) if err != nil { log.Warnln("%s", err) render.Status(r, http.StatusInternalServerError) @@ -48,9 +48,9 @@ func upgradeCore(w http.ResponseWriter, r *http.Request) { } func updateUI(w http.ResponseWriter, r *http.Request) { - err := config.UpdateUI() + err := updater.UpdateUI() if err != nil { - if errors.Is(err, config.ErrIncompleteConf) { + if errors.Is(err, updater.ErrIncompleteConf) { log.Warnln("%s", err) render.Status(r, http.StatusNotImplemented) render.JSON(w, r, newError(fmt.Sprintf("%s", err))) diff --git a/main.go b/main.go index afe9cfd2..1d16f8bf 100644 --- a/main.go +++ b/main.go @@ -8,10 +8,9 @@ import ( "path/filepath" "runtime" "strings" - "sync" "syscall" - "time" + "github.com/metacubex/mihomo/component/updater" "github.com/metacubex/mihomo/config" C "github.com/metacubex/mihomo/constant" "github.com/metacubex/mihomo/constant/features" @@ -32,8 +31,6 @@ var ( externalController string externalControllerUnix string secret string - updateGeoMux sync.Mutex - updatingGeo = false ) func init() { @@ -116,14 +113,7 @@ func main() { } if C.GeoAutoUpdate { - ticker := time.NewTicker(time.Duration(C.GeoUpdateInterval) * time.Hour) - - log.Infoln("[GEO] Start update GEO database every %d hours", C.GeoUpdateInterval) - go func() { - for range ticker.C { - updateGeoDatabases() - } - }() + updater.RegisterGeoUpdater() } defer executor.Shutdown() @@ -145,39 +135,3 @@ func main() { } } } - -func updateGeoDatabases() { - log.Infoln("[GEO] Start updating GEO database") - updateGeoMux.Lock() - - if updatingGeo { - updateGeoMux.Unlock() - log.Infoln("[GEO] GEO database is updating, skip") - return - } - - updatingGeo = true - updateGeoMux.Unlock() - - go func() { - defer func() { - updatingGeo = false - }() - - log.Infoln("[GEO] Updating GEO database") - - if err := config.UpdateGeoDatabases(); err != nil { - log.Errorln("[GEO] update GEO database error: %s", err.Error()) - return - } - - cfg, err := executor.ParseWithPath(C.Path.Config()) - if err != nil { - log.Errorln("[GEO] update GEO database failed: %s", err.Error()) - return - } - - log.Infoln("[GEO] Update GEO database success, apply new config") - executor.ApplyConfig(cfg, false) - }() -} From 2b52809d2c355b85f5460b589838d869b065fbad Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 18 May 2024 11:47:30 +0800 Subject: [PATCH 22/30] chore: update quic-go to 0.43.1 --- go.mod | 26 +++++++++++++------------- go.sum | 53 +++++++++++++++++++++++++++-------------------------- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index 904a9274..c01dc643 100644 --- a/go.mod +++ b/go.mod @@ -12,15 +12,15 @@ require ( github.com/go-chi/chi/v5 v5.0.12 github.com/go-chi/cors v1.2.1 github.com/go-chi/render v1.0.3 - github.com/gobwas/ws v1.3.2 - github.com/gofrs/uuid/v5 v5.1.0 + github.com/gobwas/ws v1.4.0 + github.com/gofrs/uuid/v5 v5.2.0 github.com/insomniacslk/dhcp v0.0.0-20240419123447-f1cffa2c0c49 github.com/klauspost/cpuid/v2 v2.2.7 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.43.1-0.20240428051621-a109abfb4cf6 - github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f + github.com/metacubex/quic-go v0.43.2-0.20240518033621-2c3d14c6b38e + github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 github.com/metacubex/sing-shadowsocks v0.2.6 github.com/metacubex/sing-shadowsocks2 v0.2.0 github.com/metacubex/sing-tun v0.2.7-0.20240512075008-89e7c6208eec @@ -40,21 +40,21 @@ require ( github.com/sagernet/utls v1.5.4 github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e github.com/samber/lo v1.39.0 - github.com/shirou/gopsutil/v3 v3.24.3 + github.com/shirou/gopsutil/v3 v3.24.4 github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.9.0 github.com/wk8/go-ordered-map/v2 v2.1.8 github.com/zhangyunhao116/fastrand v0.4.0 go.uber.org/automaxprocs v1.5.3 go4.org/netipx v0.0.0-20231129151722-fdeea329fbba - golang.org/x/crypto v0.22.0 - golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f - golang.org/x/net v0.24.0 + golang.org/x/crypto v0.23.0 + golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 + golang.org/x/net v0.25.0 golang.org/x/sync v0.7.0 - golang.org/x/sys v0.19.0 - google.golang.org/protobuf v1.33.0 + golang.org/x/sys v0.20.0 + google.golang.org/protobuf v1.34.1 gopkg.in/yaml.v3 v3.0.1 - lukechampine.com/blake3 v1.2.2 + lukechampine.com/blake3 v1.3.0 ) require ( @@ -105,9 +105,9 @@ require ( gitlab.com/yawning/bsaes.git v0.0.0-20190805113838-0a714cd429ec // indirect go.uber.org/mock v0.4.0 // indirect golang.org/x/mod v0.17.0 // indirect - golang.org/x/text v0.14.0 // indirect + golang.org/x/text v0.15.0 // indirect golang.org/x/time v0.5.0 // indirect - golang.org/x/tools v0.20.0 // indirect + golang.org/x/tools v0.21.0 // indirect ) replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764 diff --git a/go.sum b/go.sum index ae199963..41190ce8 100644 --- a/go.sum +++ b/go.sum @@ -60,10 +60,10 @@ 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.2 h1:zlnbNHxumkRvfPWgfXu8RBwyNR1x8wh9cf5PTOCqs9Q= -github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY= -github.com/gofrs/uuid/v5 v5.1.0 h1:S5rqVKIigghZTCBKPCw0Y+bXkn26K3TB5mvQq2Ix8dk= -github.com/gofrs/uuid/v5 v5.1.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= +github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs= +github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc= +github.com/gofrs/uuid/v5 v5.2.0 h1:qw1GMx6/y8vhVsx626ImfKMuS5CvJmhIKKtuyvfajMM= +github.com/gofrs/uuid/v5 v5.2.0/go.mod h1:CDOjlDMVAtN56jqyRUZh58JT31Tiw7/oQyEXZV+9bD8= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU= @@ -104,12 +104,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-20240320004321-933faba989ec h1:HxreOiFTUrJXJautEo8rnE1uKTVGY8wtZepY1Tii/Nc= github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec/go.mod h1:8BVmQ+3cxjqzWElafm24rb2Ae4jRI6vAXNXWqWjfrXw= -github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6 h1:qqIZ8CjoxVJP38JU9ml1RkWJfaUd7QtmOk1vl7shuRY= -github.com/metacubex/quic-go v0.43.1-0.20240428051621-a109abfb4cf6/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk= +github.com/metacubex/quic-go v0.43.2-0.20240518033621-2c3d14c6b38e h1:Nzwe08FNIJpExWpy9iXkG336dN/8nJqn69yijB7vJ8g= +github.com/metacubex/quic-go v0.43.2-0.20240518033621-2c3d14c6b38e/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764 h1:+czGKoynxYA90YaL3NlCAIJHnlqwoUlLWgmOhdm5ZU8= github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= -github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f h1:Xyd8SHaPHS3iX3xXPnus9PsYhJIo/2e7sJ6vTKLKUm8= -github.com/metacubex/sing-quic v0.0.0-20240501013754-2a2b0f262f9f/go.mod h1:nfqibK+vkBtE6Ch8vYqrFTcaX4BC6TwKqNNl5rORll4= +github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 h1:Wr4g1HCb5Z/QIFwFiVNjO2qL+dRu25+Mdn9xtAZZ+ew= +github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= github.com/metacubex/sing-shadowsocks v0.2.6/go.mod h1:zIkMeSnb8Mbf4hdqhw0pjzkn1d99YJ3JQm/VBg5WMTg= github.com/metacubex/sing-shadowsocks2 v0.2.0 h1:hqwT/AfI5d5UdPefIzR6onGHJfDXs5zgOM5QSgaM/9A= @@ -169,8 +169,8 @@ github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e h1:iGH0RMv2F github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e/go.mod h1:YbL4TKHRR6APYQv3U2RGfwLDpPYSyWz6oUlpISBEzBE= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= github.com/samber/lo v1.39.0/go.mod h1:+m/ZKRl6ClXCE2Lgf3MsQlWfh4bn1bz6CXEOxnEXnEA= -github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= -github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= +github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU= +github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8= 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= @@ -222,18 +222,18 @@ go4.org/netipx v0.0.0-20231129151722-fdeea329fbba h1:0b9z3AuHCjxk0x/opv64kcgZLBs go4.org/netipx v0.0.0-20231129151722-fdeea329fbba/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.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY= -golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI= +golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI= +golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= +golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= 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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= golang.org/x/mod v0.17.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.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= -golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= +golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= @@ -253,25 +253,26 @@ 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.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o= golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= +golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y= +golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.20.0 h1:VnkxpohqXaOBYJtBmEppKUG6mXpi+4O6purfc2+sMhw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY= -golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg= +golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw= +golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= 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.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= -google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= +google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 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= 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.2.2 h1:wEAbSg0IVU4ih44CVlpMqMZMpzr5hf/6aqodLlevd/w= -lukechampine.com/blake3 v1.2.2/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= +lukechampine.com/blake3 v1.3.0 h1:sJ3XhFINmHSrYCgl958hscfIa3bw8x4DqMP3u1YvoYE= +lukechampine.com/blake3 v1.3.0/go.mod h1:0OFRp7fBtAylGVCO40o87sbupkyIGgbpv1+M1k1LM6k= From 56edd8f671b84bee3f18d45e60b470f8a417a967 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 18 May 2024 18:36:00 +0800 Subject: [PATCH 23/30] ci: better release --- .github/workflows/build.yml | 95 ++++++++++++++++++++++--------------- 1 file changed, 58 insertions(+), 37 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9556c7c3..e3275679 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,10 @@ name: Build on: workflow_dispatch: + inputs: + version: + description: "Tag version to release" + required: true push: paths-ignore: - "docs/**" @@ -13,7 +17,6 @@ on: pull_request_target: branches: - Alpha - concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -138,13 +141,13 @@ jobs: curl https://github.com/golang/go/commit/9e43850a3298a9b8b1162ba0033d4c53f8637571.diff | patch --verbose -R -p 1 - name: Set variables - if: ${{github.ref_name=='Alpha'}} - run: echo "VERSION=alpha-$(git rev-parse --short HEAD)" >> $GITHUB_ENV + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' }} + run: echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV shell: bash - name: Set variables - if: ${{github.ref_name=='' || github.ref_type=='tag'}} - run: echo "VERSION=$(git describe --tags)" >> $GITHUB_ENV + if: ${{ github.event_name != 'workflow_dispatch' && github.ref_name == 'Alpha' }} + run: echo "VERSION=alpha-$(git rev-parse --short HEAD)" >> $GITHUB_ENV shell: bash - name: Set Time Variable @@ -277,7 +280,7 @@ jobs: Upload-Prerelease: permissions: write-all - if: ${{ github.ref_type == 'branch' && !startsWith(github.event_name, 'pull_request') }} + if: ${{ github.event_name != 'workflow_dispatch' && github.ref_type == 'branch' && !startsWith(github.event_name, 'pull_request') }} needs: [build] runs-on: ubuntu-latest steps: @@ -328,44 +331,62 @@ jobs: Upload-Release: permissions: write-all - if: ${{ github.ref_type=='tag' }} + if: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version != '' }} needs: [build] runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 + - name: Checkout + uses: actions/checkout@v4 + with: + ref: Meta + fetch-depth: '0' + fetch-tags: 'true' - - name: Get tags - run: | - echo "CURRENTVERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV - git fetch --tags - echo "PREVERSION=$(git describe --tags --abbrev=0 HEAD^)" >> $GITHUB_ENV + - name: Get tags + run: | + echo "CURRENTVERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV + git fetch --tags + echo "PREVERSION=$(git describe --tags --abbrev=0 HEAD)" >> $GITHUB_ENV - - name: Generate release notes - run: | - cp ./.github/genReleaseNote.sh ./ - bash ./genReleaseNote.sh -v ${PREVERSION}...${CURRENTVERSION} - rm ./genReleaseNote.sh + - name: Merge Alpha branch into Meta + run: | + git config --global user.email "github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + git fetch origin Alpha:Alpha + git merge Alpha + git push origin Meta + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/download-artifact@v4 - with: - path: bin/ - merge-multiple: true + - name: Tag the commit + run: | + git tag ${{ github.event.inputs.version }} + git push origin ${{ github.event.inputs.version }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Display structure of downloaded files - run: ls -R - working-directory: bin - - - name: Upload Release - uses: softprops/action-gh-release@v1 - if: ${{ success() }} - with: - tag_name: ${{ github.ref_name }} - files: bin/* - generate_release_notes: true - body_path: release.md + - name: Generate release notes + run: | + cp ./.github/genReleaseNote.sh ./ + bash ./genReleaseNote.sh -v ${PREVERSION}...${CURRENTVERSION} + rm ./genReleaseNote.sh + + - uses: actions/download-artifact@v4 + with: + path: bin/ + merge-multiple: true + + - name: Display structure of downloaded files + run: ls -R + working-directory: bin + + - name: Upload Release + uses: softprops/action-gh-release@v2 + if: ${{ success() }} + with: + tag_name: ${{ github.event.inputs.version }} + files: bin/* + body_path: release.md Docker: if: ${{ !startsWith(github.event_name, 'pull_request') }} From 00e361c5acfa4fc31562ccc0b4d9c911843bf53f Mon Sep 17 00:00:00 2001 From: hunshcn Date: Sat, 18 May 2024 20:16:53 +0800 Subject: [PATCH 24/30] chore: stop using go:linkname for http.registerOnHitEOF, http.requestBodyRemains (#1275) relate to https://github.com/MetaCubeX/mihomo/pull/952#issuecomment-2118639385 --- listener/http/proxy.go | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/listener/http/proxy.go b/listener/http/proxy.go index f69c2b06..c77f9230 100644 --- a/listener/http/proxy.go +++ b/listener/http/proxy.go @@ -8,7 +8,6 @@ import ( "net/http" "strings" "sync" - _ "unsafe" "github.com/metacubex/mihomo/adapter/inbound" "github.com/metacubex/mihomo/common/lru" @@ -18,11 +17,19 @@ import ( "github.com/metacubex/mihomo/log" ) -//go:linkname registerOnHitEOF net/http.registerOnHitEOF -func registerOnHitEOF(rc io.ReadCloser, fn func()) +type bodyWrapper struct { + io.ReadCloser + once sync.Once + onHitEOF func() +} -//go:linkname requestBodyRemains net/http.requestBodyRemains -func requestBodyRemains(rc io.ReadCloser) bool +func (b *bodyWrapper) Read(p []byte) (n int, err error) { + n, err = b.ReadCloser.Read(p) + if err == io.EOF && b.onHitEOF != nil { + b.once.Do(b.onHitEOF) + } + return n, err +} func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], additions ...inbound.Addition) { client := newClient(c, tunnel, additions...) @@ -100,10 +107,10 @@ func HandleConn(c net.Conn, tunnel C.Tunnel, cache *lru.LruCache[string, bool], } }() } - if requestBodyRemains(request.Body) { - registerOnHitEOF(request.Body, startBackgroundRead) - } else { + if request.Body == nil || request.Body == http.NoBody { startBackgroundRead() + } else { + request.Body = &bodyWrapper{ReadCloser: request.Body, onHitEOF: startBackgroundRead} } resp, err = client.Do(request) if err != nil { From 30a913aad62f2986799f0e58448b601f6fe28039 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 18 May 2024 20:45:15 +0800 Subject: [PATCH 25/30] chore: stop using go:linkname for net.lookupStaticHost --- component/resolver/host.go | 8 +- component/resolver/hosts/hosts.go | 309 ++++++++++++++++++++++ component/resolver/hosts/hosts_windows.go | 13 + 3 files changed, 324 insertions(+), 6 deletions(-) create mode 100644 component/resolver/hosts/hosts.go create mode 100644 component/resolver/hosts/hosts_windows.go diff --git a/component/resolver/host.go b/component/resolver/host.go index 7e299a09..53fa5924 100644 --- a/component/resolver/host.go +++ b/component/resolver/host.go @@ -9,6 +9,7 @@ import ( _ "unsafe" "github.com/metacubex/mihomo/common/utils" + "github.com/metacubex/mihomo/component/resolver/hosts" "github.com/metacubex/mihomo/component/trie" "github.com/zhangyunhao116/fastrand" ) @@ -28,11 +29,6 @@ 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) { if value := h.DomainTrie.Search(domain); value != nil { @@ -56,7 +52,7 @@ func (h *Hosts) Search(domain string, isDomain bool) (*HostValue, bool) { } if !isDomain && !DisableSystemHosts && UseSystemHosts { - addr, _ := lookupStaticHost(domain) + addr, _ := hosts.LookupStaticHost(domain) if hostValue, err := NewHostValue(addr); err == nil { return &hostValue, true } diff --git a/component/resolver/hosts/hosts.go b/component/resolver/hosts/hosts.go new file mode 100644 index 00000000..780ebb24 --- /dev/null +++ b/component/resolver/hosts/hosts.go @@ -0,0 +1,309 @@ +package hosts + +// this file copy and modify from golang's std net/hosts.go + +import ( + "errors" + "io" + "io/fs" + "net/netip" + "os" + "strings" + "sync" + "time" +) + +var hostsFilePath = "/etc/hosts" + +const cacheMaxAge = 5 * time.Second + +func parseLiteralIP(addr string) string { + ip, err := netip.ParseAddr(addr) + if err != nil { + return "" + } + return ip.String() +} + +type byName struct { + addrs []string + canonicalName string +} + +// hosts contains known host entries. +var hosts struct { + sync.Mutex + + // Key for the list of literal IP addresses must be a host + // name. It would be part of DNS labels, a FQDN or an absolute + // FQDN. + // For now the key is converted to lower case for convenience. + byName map[string]byName + + // Key for the list of host names must be a literal IP address + // including IPv6 address with zone identifier. + // We don't support old-classful IP address notation. + byAddr map[string][]string + + expire time.Time + path string + mtime time.Time + size int64 +} + +func readHosts() { + now := time.Now() + hp := hostsFilePath + + if now.Before(hosts.expire) && hosts.path == hp && len(hosts.byName) > 0 { + return + } + mtime, size, err := stat(hp) + if err == nil && hosts.path == hp && hosts.mtime.Equal(mtime) && hosts.size == size { + hosts.expire = now.Add(cacheMaxAge) + return + } + + hs := make(map[string]byName) + is := make(map[string][]string) + + file, err := open(hp) + if err != nil { + if !errors.Is(err, fs.ErrNotExist) && !errors.Is(err, fs.ErrPermission) { + return + } + } + + if file != nil { + defer file.close() + for line, ok := file.readLine(); ok; line, ok = file.readLine() { + if i := strings.IndexByte(line, '#'); i >= 0 { + // Discard comments. + line = line[0:i] + } + f := getFields(line) + if len(f) < 2 { + continue + } + addr := parseLiteralIP(f[0]) + if addr == "" { + continue + } + + var canonical string + for i := 1; i < len(f); i++ { + name := absDomainName(f[i]) + h := []byte(f[i]) + lowerASCIIBytes(h) + key := absDomainName(string(h)) + + if i == 1 { + canonical = key + } + + is[addr] = append(is[addr], name) + + if v, ok := hs[key]; ok { + hs[key] = byName{ + addrs: append(v.addrs, addr), + canonicalName: v.canonicalName, + } + continue + } + + hs[key] = byName{ + addrs: []string{addr}, + canonicalName: canonical, + } + } + } + } + // Update the data cache. + hosts.expire = now.Add(cacheMaxAge) + hosts.path = hp + hosts.byName = hs + hosts.byAddr = is + hosts.mtime = mtime + hosts.size = size +} + +// LookupStaticHost looks up the addresses and the canonical name for the given host from /etc/hosts. +func LookupStaticHost(host string) ([]string, string) { + hosts.Lock() + defer hosts.Unlock() + readHosts() + if len(hosts.byName) != 0 { + if hasUpperCase(host) { + lowerHost := []byte(host) + lowerASCIIBytes(lowerHost) + host = string(lowerHost) + } + if byName, ok := hosts.byName[absDomainName(host)]; ok { + ipsCp := make([]string, len(byName.addrs)) + copy(ipsCp, byName.addrs) + return ipsCp, byName.canonicalName + } + } + return nil, "" +} + +// LookupStaticAddr looks up the hosts for the given address from /etc/hosts. +func LookupStaticAddr(addr string) []string { + hosts.Lock() + defer hosts.Unlock() + readHosts() + addr = parseLiteralIP(addr) + if addr == "" { + return nil + } + if len(hosts.byAddr) != 0 { + if hosts, ok := hosts.byAddr[addr]; ok { + hostsCp := make([]string, len(hosts)) + copy(hostsCp, hosts) + return hostsCp + } + } + return nil +} + +func stat(name string) (mtime time.Time, size int64, err error) { + st, err := os.Stat(name) + if err != nil { + return time.Time{}, 0, err + } + return st.ModTime(), st.Size(), nil +} + +type file struct { + file *os.File + data []byte + atEOF bool +} + +func (f *file) close() { f.file.Close() } + +func (f *file) getLineFromData() (s string, ok bool) { + data := f.data + i := 0 + for i = 0; i < len(data); i++ { + if data[i] == '\n' { + s = string(data[0:i]) + ok = true + // move data + i++ + n := len(data) - i + copy(data[0:], data[i:]) + f.data = data[0:n] + return + } + } + if f.atEOF && len(f.data) > 0 { + // EOF, return all we have + s = string(data) + f.data = f.data[0:0] + ok = true + } + return +} + +func (f *file) readLine() (s string, ok bool) { + if s, ok = f.getLineFromData(); ok { + return + } + if len(f.data) < cap(f.data) { + ln := len(f.data) + n, err := io.ReadFull(f.file, f.data[ln:cap(f.data)]) + if n >= 0 { + f.data = f.data[0 : ln+n] + } + if err == io.EOF || err == io.ErrUnexpectedEOF { + f.atEOF = true + } + } + s, ok = f.getLineFromData() + return +} + +func (f *file) stat() (mtime time.Time, size int64, err error) { + st, err := f.file.Stat() + if err != nil { + return time.Time{}, 0, err + } + return st.ModTime(), st.Size(), nil +} + +func open(name string) (*file, error) { + fd, err := os.Open(name) + if err != nil { + return nil, err + } + return &file{fd, make([]byte, 0, 64*1024), false}, nil +} + +func getFields(s string) []string { return splitAtBytes(s, " \r\t\n") } + +// Count occurrences in s of any bytes in t. +func countAnyByte(s string, t string) int { + n := 0 + for i := 0; i < len(s); i++ { + if strings.IndexByte(t, s[i]) >= 0 { + n++ + } + } + return n +} + +// Split s at any bytes in t. +func splitAtBytes(s string, t string) []string { + a := make([]string, 1+countAnyByte(s, t)) + n := 0 + last := 0 + for i := 0; i < len(s); i++ { + if strings.IndexByte(t, s[i]) >= 0 { + if last < i { + a[n] = s[last:i] + n++ + } + last = i + 1 + } + } + if last < len(s) { + a[n] = s[last:] + n++ + } + return a[0:n] +} + +// lowerASCIIBytes makes x ASCII lowercase in-place. +func lowerASCIIBytes(x []byte) { + for i, b := range x { + if 'A' <= b && b <= 'Z' { + x[i] += 'a' - 'A' + } + } +} + +// hasUpperCase tells whether the given string contains at least one upper-case. +func hasUpperCase(s string) bool { + for i := range s { + if 'A' <= s[i] && s[i] <= 'Z' { + return true + } + } + return false +} + +// absDomainName returns an absolute domain name which ends with a +// trailing dot to match pure Go reverse resolver and all other lookup +// routines. +// See golang.org/issue/12189. +// But we don't want to add dots for local names from /etc/hosts. +// It's hard to tell so we settle on the heuristic that names without dots +// (like "localhost" or "myhost") do not get trailing dots, but any other +// names do. +func absDomainName(s string) string { + if strings.IndexByte(s, '.') != -1 && s[len(s)-1] != '.' { + s += "." + } + return s +} diff --git a/component/resolver/hosts/hosts_windows.go b/component/resolver/hosts/hosts_windows.go new file mode 100644 index 00000000..8ad76e0a --- /dev/null +++ b/component/resolver/hosts/hosts_windows.go @@ -0,0 +1,13 @@ +package hosts + +// this file copy and modify from golang's std net/hook_windows.go + +import ( + "golang.org/x/sys/windows" +) + +func init() { + if dir, err := windows.GetSystemDirectory(); err == nil { + hostsFilePath = dir + "/Drivers/etc/hosts" + } +} From bfb6caeeafefdc0711d0de4f12b33bb35c2c416e Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sat, 18 May 2024 20:54:28 +0800 Subject: [PATCH 26/30] chore: stop using go:linkname for x/sys/windows --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c01dc643..747783e2 100644 --- a/go.mod +++ b/go.mod @@ -110,4 +110,4 @@ require ( golang.org/x/tools v0.21.0 // indirect ) -replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764 +replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1 diff --git a/go.sum b/go.sum index 41190ce8..d5443e03 100644 --- a/go.sum +++ b/go.sum @@ -106,8 +106,8 @@ github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec h1:HxreOiFTUrJXJa github.com/metacubex/gvisor v0.0.0-20240320004321-933faba989ec/go.mod h1:8BVmQ+3cxjqzWElafm24rb2Ae4jRI6vAXNXWqWjfrXw= github.com/metacubex/quic-go v0.43.2-0.20240518033621-2c3d14c6b38e h1:Nzwe08FNIJpExWpy9iXkG336dN/8nJqn69yijB7vJ8g= github.com/metacubex/quic-go v0.43.2-0.20240518033621-2c3d14c6b38e/go.mod h1:uXHODgJFUfUnkkCMWLd5Er6L5QY/LFRZb9LD5jyyhsk= -github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764 h1:+czGKoynxYA90YaL3NlCAIJHnlqwoUlLWgmOhdm5ZU8= -github.com/metacubex/sing v0.0.0-20240408015159-aa61c96df764/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= +github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1 h1:7hDHLTmjgtRoAp59STwPQpe5Pinwi4cWex+FB3Ohvco= +github.com/metacubex/sing v0.0.0-20240518125217-e63d65a914d1/go.mod h1:+60H3Cm91RnL9dpVGWDPHt0zTQImO9Vfqt9a4rSambI= github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72 h1:Wr4g1HCb5Z/QIFwFiVNjO2qL+dRu25+Mdn9xtAZZ+ew= github.com/metacubex/sing-quic v0.0.0-20240518034124-7696d3f7da72/go.mod h1:g7Mxj7b7zm7YVqD975mk/hSmrb0A0G4bVvIMr2MMzn8= github.com/metacubex/sing-shadowsocks v0.2.6 h1:6oEB3QcsFYnNiFeoevcXrCwJ3sAablwVSgtE9R3QeFQ= From b7c02a59230986d17042a8eeb019f9a5436a99e3 Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sat, 18 May 2024 23:09:21 +0800 Subject: [PATCH 27/30] ci: fix docker --- .github/workflows/build.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e3275679..b6b996ab 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -416,6 +416,18 @@ jobs: with: version: latest + - name: Set Docker tags and labels based on trigger + id: set-meta + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "tags=${{ github.event.inputs.version }}" >> $GITHUB_ENV + echo "labels=org.opencontainers.image.version=${{ github.event.inputs.version }}" >> $GITHUB_ENV + else + echo "tags=${{ steps.meta.outputs.tags }}" >> $GITHUB_ENV + echo "labels=${{ steps.meta.outputs.labels }}" >> $GITHUB_ENV + fi + + # Extract metadata (tags, labels) for Docker # https://github.com/docker/metadata-action - name: Extract Docker metadata From df69a31e6226df359a14165b81c3ba95732942c6 Mon Sep 17 00:00:00 2001 From: wwqgtxx Date: Sun, 19 May 2024 11:31:37 +0800 Subject: [PATCH 28/30] chore: stop using go:linkname for crypto/tls.aesgcmPreferred and update utls to 1.6.6 --- component/tls/reality.go | 15 +++++---------- component/tls/utls.go | 2 +- go.mod | 4 ++-- go.sum | 8 ++++---- transport/sing-shadowtls/shadowtls.go | 2 +- transport/vless/vision/conn.go | 2 +- transport/vless/vision/vision.go | 2 +- 7 files changed, 15 insertions(+), 20 deletions(-) diff --git a/component/tls/reality.go b/component/tls/reality.go index 7728b4b2..48da3e92 100644 --- a/component/tls/reality.go +++ b/component/tls/reality.go @@ -16,16 +16,13 @@ import ( "errors" "net" "net/http" - "reflect" "strings" "time" - "unsafe" - "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/ntp" - utls "github.com/sagernet/utls" + utls "github.com/metacubex/utls" "github.com/zhangyunhao116/fastrand" "golang.org/x/crypto/chacha20poly1305" "golang.org/x/crypto/hkdf" @@ -39,9 +36,6 @@ 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) { retry := 0 for fingerprint, exists := GetFingerprint(ClientFingerprint); exists; retry++ { @@ -102,7 +96,7 @@ func GetRealityConn(ctx context.Context, conn net.Conn, ClientFingerprint string return nil, err } var aeadCipher cipher.AEAD - if aesgcmPreferred(hello.CipherSuites) { + if utls.AesgcmPreferred(hello.CipherSuites) { aesBlock, _ := aes.NewCipher(authKey) aeadCipher, _ = cipher.NewGCM(aesBlock) } else { @@ -162,11 +156,12 @@ type realityVerifier struct { verified bool } -var pOffset = utils.MustOK(reflect.TypeOf((*utls.Conn)(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") - certs := *(*[]*x509.Certificate)(unsafe.Add(unsafe.Pointer(c.Conn), pOffset)) + //certs := *(*[]*x509.Certificate)(unsafe.Add(unsafe.Pointer(c.Conn), pOffset)) + certs := c.Conn.PeerCertificates() if pub, ok := certs[0].PublicKey.(ed25519.PublicKey); ok { h := hmac.New(sha512.New, c.authKey) h.Write(pub) diff --git a/component/tls/utls.go b/component/tls/utls.go index 3063fc55..31733e50 100644 --- a/component/tls/utls.go +++ b/component/tls/utls.go @@ -6,8 +6,8 @@ import ( "github.com/metacubex/mihomo/log" + utls "github.com/metacubex/utls" "github.com/mroth/weightedrand/v2" - utls "github.com/sagernet/utls" ) type UConn struct { diff --git a/go.mod b/go.mod index 747783e2..d9ed1228 100644 --- a/go.mod +++ b/go.mod @@ -27,6 +27,7 @@ require ( github.com/metacubex/sing-vmess v0.1.9-0.20231207122118-72303677451f github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 + github.com/metacubex/utls v1.6.6 github.com/miekg/dns v1.1.59 github.com/mroth/weightedrand/v2 v2.1.0 github.com/openacid/low v0.1.21 @@ -37,7 +38,6 @@ require ( github.com/sagernet/sing v0.3.8 github.com/sagernet/sing-mux v0.2.1-0.20240124034317-9bfb33698bb6 github.com/sagernet/sing-shadowtls v0.1.4 - github.com/sagernet/utls v1.5.4 github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e github.com/samber/lo v1.39.0 github.com/shirou/gopsutil/v3 v3.24.4 @@ -63,7 +63,7 @@ require ( github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.6 // indirect github.com/buger/jsonparser v1.1.1 // indirect - github.com/cloudflare/circl v1.3.6 // indirect + github.com/cloudflare/circl v1.3.7 // 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 diff --git a/go.sum b/go.sum index d5443e03..fb14d715 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,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.12.3 h1:8ht6F9MquybnY97at+VDZb3eQQr8ev79RueWeVaEcG4= github.com/cilium/ebpf v0.12.3/go.mod h1:TctK1ivibvI3znr66ljgi4hqOT8EYQjz1KWBfb1UVgM= -github.com/cloudflare/circl v1.3.6 h1:/xbKIqSHbZXHwkhbrhrt2YOHIwYJlXH94E3tI/gDlUg= -github.com/cloudflare/circl v1.3.6/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA= +github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU= +github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA= 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= @@ -122,6 +122,8 @@ github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63 h1:AGyIB5 github.com/metacubex/sing-wireguard v0.0.0-20240321042214-224f96122a63/go.mod h1:uY+BYb0UEknLrqvbGcwi9i++KgrKxsurysgI6G1Pveo= github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66 h1:as/aO/fM8nv4W4pOr9EETP6kV/Oaujk3fUNyQSJK61c= github.com/metacubex/tfo-go v0.0.0-20240228025757-be1269474a66/go.mod h1:c7bVFM9f5+VzeZ/6Kg77T/jrg1Xp8QpqlSHvG/aXVts= +github.com/metacubex/utls v1.6.6 h1:3D12YKHTf2Z41UPhQU2dWerNWJ5TVQD9gKoQ+H+iLC8= +github.com/metacubex/utls v1.6.6/go.mod h1:+WLFUnXjcpdxXCnyX25nggw8C6YonZ8zOK2Zm/oRvdo= github.com/miekg/dns v1.1.59 h1:C9EXc/UToRwKLhK5wKU/I4QVsBUc8kE6MkHBkeypWZs= github.com/miekg/dns v1.1.59/go.mod h1:nZpewl5p6IvctfgrckopVx2OlSEHPRO/U4SYkRklrEk= github.com/mroth/weightedrand/v2 v2.1.0 h1:o1ascnB1CIVzsqlfArQQjeMy1U0NcIbBO5rfd5E/OeU= @@ -163,8 +165,6 @@ github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnV github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ= github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7/go.mod h1:FP9X2xjT/Az1EsG/orYYoC+5MojWnuI7hrffz8fGwwo= -github.com/sagernet/utls v1.5.4 h1:KmsEGbB2dKUtCNC+44NwAdNAqnqQ6GA4pTO0Yik56co= -github.com/sagernet/utls v1.5.4/go.mod h1:CTGxPWExIloRipK3XFpYv0OVyhO8kk3XCGW/ieyTh1s= github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e h1:iGH0RMv2FzELOFNFQtvsxH7NPmlo7X5JizEK51UCojo= github.com/sagernet/wireguard-go v0.0.0-20231209092712-9a439356a62e/go.mod h1:YbL4TKHRR6APYQv3U2RGfwLDpPYSyWz6oUlpISBEzBE= github.com/samber/lo v1.39.0 h1:4gTz1wUhNYLhFSKl6O+8peW0v2F4BCY034GRpU9WnuA= diff --git a/transport/sing-shadowtls/shadowtls.go b/transport/sing-shadowtls/shadowtls.go index 982d847a..2012e20a 100644 --- a/transport/sing-shadowtls/shadowtls.go +++ b/transport/sing-shadowtls/shadowtls.go @@ -9,9 +9,9 @@ import ( tlsC "github.com/metacubex/mihomo/component/tls" "github.com/metacubex/mihomo/log" + utls "github.com/metacubex/utls" "github.com/sagernet/sing-shadowtls" sing_common "github.com/sagernet/sing/common" - utls "github.com/sagernet/utls" ) const ( diff --git a/transport/vless/vision/conn.go b/transport/vless/vision/conn.go index 5ad28134..69ccfba0 100644 --- a/transport/vless/vision/conn.go +++ b/transport/vless/vision/conn.go @@ -14,7 +14,7 @@ import ( "github.com/metacubex/mihomo/log" "github.com/gofrs/uuid/v5" - utls "github.com/sagernet/utls" + utls "github.com/metacubex/utls" ) var ( diff --git a/transport/vless/vision/vision.go b/transport/vless/vision/vision.go index 09299b23..3b9e9379 100644 --- a/transport/vless/vision/vision.go +++ b/transport/vless/vision/vision.go @@ -14,8 +14,8 @@ import ( tlsC "github.com/metacubex/mihomo/component/tls" "github.com/gofrs/uuid/v5" + utls "github.com/metacubex/utls" "github.com/sagernet/sing/common" - utls "github.com/sagernet/utls" ) var ErrNotTLS13 = errors.New("XTLS Vision based on TLS 1.3 outer connection") From c3ee921d30e4f8be7097d2f7d998e248befbaadf Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 19 May 2024 15:46:23 +0800 Subject: [PATCH 29/30] chore: apply config when geo update --- component/updater/update_geo.go | 23 ++++--------- hub/route/configs.go | 57 +++++++++++++++++++++------------ main.go | 18 +++++++++-- 3 files changed, 60 insertions(+), 38 deletions(-) diff --git a/component/updater/update_geo.go b/component/updater/update_geo.go index a98d94dc..4bb57e06 100644 --- a/component/updater/update_geo.go +++ b/component/updater/update_geo.go @@ -5,7 +5,6 @@ import ( "fmt" "os" "runtime" - "sync" "time" "github.com/metacubex/mihomo/common/atomic" @@ -19,8 +18,7 @@ import ( ) var ( - updateGeoMux sync.Mutex - UpdatingGeo atomic.Bool + UpdatingGeo atomic.Bool ) func updateGeoDatabases() error { @@ -100,22 +98,15 @@ func updateGeoDatabases() error { return nil } -func UpdateGeoDatabases() error { +func UpdateGeoDatabases(updateNotification chan struct{}) error { log.Infoln("[GEO] Start updating GEO database") - updateGeoMux.Lock() - if UpdatingGeo.Load() { - updateGeoMux.Unlock() return errors.New("GEO database is updating, skip") } UpdatingGeo.Store(true) - updateGeoMux.Unlock() - - defer func() { - UpdatingGeo.Store(false) - }() + defer UpdatingGeo.Store(false) log.Infoln("[GEO] Updating GEO database") @@ -124,6 +115,7 @@ func UpdateGeoDatabases() error { return err } + updateNotification <- struct{}{} return nil } @@ -144,7 +136,7 @@ func getUpdateTime() (err error, time time.Time) { return nil, fileInfo.ModTime() } -func RegisterGeoUpdater() { +func RegisterGeoUpdater(updateNotification chan struct{}) { if C.GeoUpdateInterval <= 0 { log.Errorln("[GEO] Invalid update interval: %d", C.GeoUpdateInterval) return @@ -164,16 +156,15 @@ func RegisterGeoUpdater() { log.Infoln("[GEO] last update time %s", lastUpdate) if lastUpdate.Add(time.Duration(C.GeoUpdateInterval) * time.Hour).Before(time.Now()) { log.Infoln("[GEO] Database has not been updated for %v, update now", time.Duration(C.GeoUpdateInterval)*time.Hour) - if err := UpdateGeoDatabases(); err != nil { + if err := UpdateGeoDatabases(updateNotification); err != nil { log.Errorln("[GEO] Failed to update GEO database: %s", err.Error()) return } } for range ticker.C { - if err := UpdateGeoDatabases(); err != nil { + if err := UpdateGeoDatabases(updateNotification); err != nil { log.Errorln("[GEO] Failed to update GEO database: %s", err.Error()) - return } } }() diff --git a/hub/route/configs.go b/hub/route/configs.go index 47fd26e0..35977885 100644 --- a/hub/route/configs.go +++ b/hub/route/configs.go @@ -364,30 +364,47 @@ func updateConfigs(w http.ResponseWriter, r *http.Request) { } func updateGeoDatabases(w http.ResponseWriter, r *http.Request) { - if updater.UpdatingGeo.Load() { - render.Status(r, http.StatusBadRequest) - render.JSON(w, r, newError("updating...")) - return - } - - err := updater.UpdateGeoDatabases() - if err != nil { - render.Status(r, http.StatusBadRequest) - render.JSON(w, r, newError(err.Error())) - return - } + updateNotification := make(chan struct{}) + errorChannel := make(chan error, 1) + done := make(chan struct{}) + defer func() { + close(updateNotification) + close(errorChannel) + }() go func() { - cfg, err := executor.ParseWithPath(C.Path.Config()) - if err != nil { - log.Errorln("[REST-API] update GEO databases failed: %v", err) - return + defer close(done) + for { + select { + case <-updateNotification: + cfg, err := executor.ParseWithPath(C.Path.Config()) + if err != nil { + log.Errorln("[REST-API] update GEO databases failed: %v", err) + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, newError("Error parsing configuration")) + return + } + + log.Warnln("[REST-API] update GEO databases success, applying config") + executor.ApplyConfig(cfg, false) + return + case err := <-errorChannel: + log.Errorln("[REST-API] update GEO databases failed: %v", err) + render.Status(r, http.StatusInternalServerError) + render.JSON(w, r, err.Error()) + return + } } - - log.Warnln("[REST-API] update GEO databases successful, apply config...") - - executor.ApplyConfig(cfg, false) }() + go func() { + err := updater.UpdateGeoDatabases(updateNotification) + if err != nil { + errorChannel <- err + } + }() + + <-done + render.NoContent(w, r) } diff --git a/main.go b/main.go index 1d16f8bf..081a7eb5 100644 --- a/main.go +++ b/main.go @@ -113,9 +113,23 @@ func main() { } if C.GeoAutoUpdate { - updater.RegisterGeoUpdater() - } + updateNotification := make(chan struct{}) + go updater.RegisterGeoUpdater(updateNotification) + go func() { + for range updateNotification { + cfg, err := executor.ParseWithPath(C.Path.Config()) + if err != nil { + log.Errorln("[GEO] update GEO databases failed: %v", err) + return + } + + log.Warnln("[GEO] update GEO databases success, applying config") + + executor.ApplyConfig(cfg, false) + } + }() + } defer executor.Shutdown() termSign := make(chan os.Signal, 1) From e749c7e4923bb3993862048c5d72fd2dd1e6f4ac Mon Sep 17 00:00:00 2001 From: Larvan2 <78135608+Larvan2@users.noreply.github.com> Date: Sun, 19 May 2024 16:41:05 +0800 Subject: [PATCH 30/30] ci: docker --- .github/workflows/build.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b6b996ab..84536a54 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -435,6 +435,9 @@ jobs: uses: docker/metadata-action@v5 with: images: ${{ env.REGISTRY }}/${{ github.repository }} + tags: ${{ env.tags }} + labels: ${{ env.labels }} + - name: Show files run: | @@ -463,4 +466,4 @@ jobs: linux/arm64 linux/arm/v7 tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file