From 6a6046ae728d744088d1304dff286b22354abc8b Mon Sep 17 00:00:00 2001 From: "github-action[bot]" Date: Sat, 24 Aug 2024 20:31:53 +0200 Subject: [PATCH] Update On Sat Aug 24 20:31:52 CEST 2024 --- .github/update.log | 1 + clash-meta/adapter/inbound/listen.go | 8 + clash-meta/adapter/inbound/mptcp_go120.go | 4 + clash-meta/adapter/inbound/mptcp_go121.go | 4 + clash-meta/common/nnip/netip.go | 20 + clash-meta/config/config.go | 537 +++++++++++------- clash-meta/hub/executor/executor.go | 55 +- clash-meta/hub/hub.go | 22 +- clash-meta/hub/route/configs.go | 33 +- clash-meta/listener/config/tun.go | 165 +++++- clash-meta/listener/inbound/tun.go | 32 +- clash-meta/listener/listener.go | 161 +----- clash-meta/tunnel/tunnel.go | 4 + clash-nyanpasu/.eslintrc.cjs | 2 +- .../frontend/interface/src/ipc/useClashWS.ts | 21 +- .../src/components/app/drawer-content.tsx | 4 +- .../components/layout/mutation-provider.tsx | 2 +- .../components/layout/use-custom-theme.tsx | 2 +- .../src/components/logs/log-provider.tsx | 2 +- .../profiles/profile-monaco-view.tsx | 2 +- .../src/components/proxies/node-list.tsx | 13 +- .../setting/modules/hotkey-dialog.tsx | 4 +- .../components/setting/setting-clash-port.tsx | 2 +- .../frontend/ui/src/chart/sparkline.tsx | 2 +- .../ui/src/hooks/use-click-position.ts | 2 +- .../components/baseDialog/index.tsx | 7 +- .../components/item/numberItem.tsx | 5 +- clash-nyanpasu/manifest/version.json | 4 +- clash-nyanpasu/package.json | 20 +- clash-nyanpasu/pnpm-lock.yaml | 398 ++++++------- echo/go.mod | 39 +- echo/go.sum | 82 +-- echo/internal/cli/config.go | 4 +- echo/internal/cli/flags.go | 4 +- echo/internal/conn/relay_conn.go | 90 +-- echo/internal/conn/relay_conn_test.go | 14 +- echo/internal/conn/udp_listener.go | 10 +- echo/internal/constant/constant.go | 12 +- echo/internal/metrics/ping.go | 2 +- echo/internal/relay/conf/cfg.go | 109 ++-- echo/internal/relay/relay.go | 9 +- echo/internal/relay/server.go | 17 +- echo/internal/transporter/base.go | 9 +- echo/internal/transporter/raw.go | 7 +- echo/pkg/sub/clash.go | 4 +- echo/pkg/sub/clash_types.go | 2 +- echo/test/relay_test.go | 50 +- mihomo/adapter/inbound/listen.go | 8 + mihomo/adapter/inbound/mptcp_go120.go | 4 + mihomo/adapter/inbound/mptcp_go121.go | 4 + mihomo/common/nnip/netip.go | 20 + mihomo/config/config.go | 537 +++++++++++------- mihomo/hub/executor/executor.go | 55 +- mihomo/hub/hub.go | 22 +- mihomo/hub/route/configs.go | 33 +- mihomo/listener/config/tun.go | 165 +++++- mihomo/listener/inbound/tun.go | 32 +- mihomo/listener/listener.go | 161 +----- mihomo/tunnel/tunnel.go | 4 + .../root/usr/share/passwall/subscribe.lua | 22 + .../root/usr/share/passwall/subscribe.lua | 22 + small/v2ray-core/Makefile | 4 +- small/v2ray-plugin/Makefile | 4 +- v2ray-core/core.go | 2 +- .../assembler/packetconn/req2packet.go | 25 +- 65 files changed, 1764 insertions(+), 1362 deletions(-) diff --git a/.github/update.log b/.github/update.log index 22e3acef8d..aaea275469 100644 --- a/.github/update.log +++ b/.github/update.log @@ -743,3 +743,4 @@ Update On Tue Aug 20 20:32:25 CEST 2024 Update On Wed Aug 21 20:32:11 CEST 2024 Update On Thu Aug 22 20:34:16 CEST 2024 Update On Fri Aug 23 20:31:39 CEST 2024 +Update On Sat Aug 24 20:31:41 CEST 2024 diff --git a/clash-meta/adapter/inbound/listen.go b/clash-meta/adapter/inbound/listen.go index 18dc1bc242..1b86c811a7 100644 --- a/clash-meta/adapter/inbound/listen.go +++ b/clash-meta/adapter/inbound/listen.go @@ -17,10 +17,18 @@ func SetTfo(open bool) { lc.DisableTFO = !open } +func Tfo() bool { + return !lc.DisableTFO +} + func SetMPTCP(open bool) { setMultiPathTCP(&lc.ListenConfig, open) } +func MPTCP() bool { + return getMultiPathTCP(&lc.ListenConfig) +} + func ListenContext(ctx context.Context, network, address string) (net.Listener, error) { return lc.Listen(ctx, network, address) } diff --git a/clash-meta/adapter/inbound/mptcp_go120.go b/clash-meta/adapter/inbound/mptcp_go120.go index f9b22533d2..faae6ec5d8 100644 --- a/clash-meta/adapter/inbound/mptcp_go120.go +++ b/clash-meta/adapter/inbound/mptcp_go120.go @@ -8,3 +8,7 @@ const multipathTCPAvailable = false func setMultiPathTCP(listenConfig *net.ListenConfig, open bool) { } + +func getMultiPathTCP(listenConfig *net.ListenConfig) bool { + return false +} diff --git a/clash-meta/adapter/inbound/mptcp_go121.go b/clash-meta/adapter/inbound/mptcp_go121.go index 6b35d1a83a..9163878a70 100644 --- a/clash-meta/adapter/inbound/mptcp_go121.go +++ b/clash-meta/adapter/inbound/mptcp_go121.go @@ -9,3 +9,7 @@ const multipathTCPAvailable = true func setMultiPathTCP(listenConfig *net.ListenConfig, open bool) { listenConfig.SetMultipathTCP(open) } + +func getMultiPathTCP(listenConfig *net.ListenConfig) bool { + return listenConfig.MultipathTCP() +} diff --git a/clash-meta/common/nnip/netip.go b/clash-meta/common/nnip/netip.go index e456613888..b987bb457f 100644 --- a/clash-meta/common/nnip/netip.go +++ b/clash-meta/common/nnip/netip.go @@ -51,3 +51,23 @@ func UnMasked(p netip.Prefix) netip.Addr { } return addr } + +// PrefixCompare returns an integer comparing two prefixes. +// The result will be 0 if p == p2, -1 if p < p2, and +1 if p > p2. +// modify from https://github.com/golang/go/issues/61642#issuecomment-1848587909 +func PrefixCompare(p, p2 netip.Prefix) int { + // compare by validity, address family and prefix base address + if c := p.Masked().Addr().Compare(p2.Masked().Addr()); c != 0 { + return c + } + // compare by prefix length + f1, f2 := p.Bits(), p2.Bits() + if f1 < f2 { + return -1 + } + if f1 > f2 { + return 1 + } + // compare by prefix address + return p.Addr().Compare(p2.Addr()) +} diff --git a/clash-meta/config/config.go b/clash-meta/config/config.go index 788f227b85..f1ffbce1fd 100644 --- a/clash-meta/config/config.go +++ b/clash-meta/config/config.go @@ -50,13 +50,12 @@ import ( // General config type General struct { Inbound - Controller - Mode T.TunnelMode `json:"mode"` - UnifiedDelay bool + Mode T.TunnelMode `json:"mode"` + UnifiedDelay bool `json:"unified-delay"` LogLevel log.LogLevel `json:"log-level"` IPv6 bool `json:"ipv6"` Interface string `json:"interface-name"` - RoutingMark int `json:"-"` + RoutingMark int `json:"routing-mark"` GeoXUrl GeoXUrl `json:"geox-url"` GeoAutoUpdate bool `json:"geo-auto-update"` GeoUpdateInterval int `json:"geo-update-interval"` @@ -91,24 +90,48 @@ type Inbound struct { InboundMPTCP bool `json:"inbound-mptcp"` } +// GeoXUrl config +type GeoXUrl struct { + GeoIp string `json:"geo-ip"` + Mmdb string `json:"mmdb"` + ASN string `json:"asn"` + GeoSite string `json:"geo-site"` +} + // Controller config type Controller struct { - ExternalController string `json:"-"` - ExternalControllerTLS string `json:"-"` - ExternalControllerUnix string `json:"-"` - ExternalUI string `json:"-"` - ExternalDohServer string `json:"-"` - Secret string `json:"-"` + ExternalController string + ExternalControllerTLS string + ExternalControllerUnix string + ExternalUI string + ExternalDohServer string + Secret string +} + +// Experimental config +type Experimental struct { + Fingerprints []string + QUICGoDisableGSO bool + QUICGoDisableECN bool + IP4PEnable bool +} + +// IPTables config +type IPTables struct { + Enable bool + InboundInterface string + Bypass []string + DnsRedirect bool } // NTP config type NTP struct { - Enable bool `yaml:"enable"` - Server string `yaml:"server"` - Port int `yaml:"port"` - Interval int `yaml:"interval"` - DialerProxy string `yaml:"dialer-proxy"` - WriteToSystem bool `yaml:"write-to-system"` + Enable bool + Server string + Port int + Interval int + DialerProxy string + WriteToSystem bool } // DNS config @@ -134,24 +157,11 @@ type DNS struct { // Profile config type Profile struct { - StoreSelected bool `yaml:"store-selected"` - StoreFakeIP bool `yaml:"store-fake-ip"` -} - -type TLS struct { - Certificate string `yaml:"certificate"` - PrivateKey string `yaml:"private-key"` - CustomTrustCert []string `yaml:"custom-certifactes"` -} - -// IPTables config -type IPTables struct { - Enable bool `yaml:"enable" json:"enable"` - InboundInterface string `yaml:"inbound-interface" json:"inbound-interface"` - Bypass []string `yaml:"bypass" json:"bypass"` - DnsRedirect bool `yaml:"dns-redirect" json:"dns-redirect"` + StoreSelected bool + StoreFakeIP bool } +// Sniffer config type Sniffer struct { Enable bool Sniffers map[snifferTypes.Type]SNIFF.SnifferConfig @@ -161,21 +171,21 @@ type Sniffer struct { ParsePureIp bool } -// Experimental config -type Experimental struct { - Fingerprints []string `yaml:"fingerprints"` - QUICGoDisableGSO bool `yaml:"quic-go-disable-gso"` - QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"` - IP4PEnable bool `yaml:"dialer-ip4p-convert"` +// TLS config +type TLS struct { + Certificate string + PrivateKey string + CustomTrustCert []string } // Config is mihomo config manager type Config struct { General *General + Controller *Controller + Experimental *Experimental IPTables *IPTables NTP *NTP DNS *DNS - Experimental *Experimental Hosts *trie.DomainTrie[resolver.HostValue] Profile *Profile Rules []C.Rule @@ -190,15 +200,6 @@ type Config struct { TLS *TLS } -type RawNTP struct { - Enable bool `yaml:"enable"` - Server string `yaml:"server"` - ServerPort int `yaml:"server-port"` - Interval int `yaml:"interval"` - DialerProxy string `yaml:"dialer-proxy"` - WriteToSystem bool `yaml:"write-to-system"` -} - type RawDNS struct { Enable bool `yaml:"enable" json:"enable"` PreferH3 bool `yaml:"prefer-h3" json:"prefer-h3"` @@ -233,6 +234,15 @@ type RawClashForAndroid struct { UiSubtitlePattern string `yaml:"ui-subtitle-pattern" json:"ui-subtitle-pattern"` } +type RawNTP struct { + Enable bool `yaml:"enable" json:"enable"` + Server string `yaml:"server" json:"server"` + Port int `yaml:"port" json:"port"` + Interval int `yaml:"interval" json:"interval"` + DialerProxy string `yaml:"dialer-proxy" json:"dialer-proxy"` + WriteToSystem bool `yaml:"write-to-system" json:"write-to-system"` +} + type RawTun struct { Enable bool `yaml:"enable" json:"enable"` Device string `yaml:"device" json:"device"` @@ -244,35 +254,35 @@ type RawTun struct { MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` GSO bool `yaml:"gso" json:"gso,omitempty"` GSOMaxSize uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` - //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` - Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` - IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2_table_index,omitempty"` - IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2_rule_index,omitempty"` - AutoRedirect bool `yaml:"auto-redirect" json:"auto_redirect,omitempty"` - AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto_redirect_input_mark,omitempty"` - AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto_redirect_output_mark,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` - RouteAddress []netip.Prefix `yaml:"route-address" json:"route_address,omitempty"` - RouteAddressSet []string `yaml:"route-address-set" json:"route_address_set,omitempty"` - RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route_exclude_address,omitempty"` - RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route_exclude_address_set,omitempty"` + //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2-table-index,omitempty"` + IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2-rule-index,omitempty"` + AutoRedirect bool `yaml:"auto-redirect" json:"auto-redirect,omitempty"` + AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto-redirect-input-mark,omitempty"` + AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto-redirect-output-mark,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` + RouteAddress []netip.Prefix `yaml:"route-address" json:"route-address,omitempty"` + RouteAddressSet []string `yaml:"route-address-set" json:"route-address-set,omitempty"` + RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route-exclude-address,omitempty"` + RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route-exclude-address-set,omitempty"` IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` - Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"` - Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` - Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4_route_exclude_address,omitempty"` - Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6_route_exclude_address,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` + Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` } type RawTuicServer struct { @@ -290,73 +300,26 @@ type RawTuicServer struct { CWND int `yaml:"cwnd" json:"cwnd,omitempty"` } -type RawConfig struct { - Port int `yaml:"port" json:"port"` - SocksPort int `yaml:"socks-port" json:"socks-port"` - RedirPort int `yaml:"redir-port" json:"redir-port"` - TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"` - MixedPort int `yaml:"mixed-port" json:"mixed-port"` - ShadowSocksConfig string `yaml:"ss-config"` - VmessConfig string `yaml:"vmess-config"` - InboundTfo bool `yaml:"inbound-tfo"` - InboundMPTCP bool `yaml:"inbound-mptcp"` - Authentication []string `yaml:"authentication" json:"authentication"` - SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"` - LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips"` - LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips"` - AllowLan bool `yaml:"allow-lan" json:"allow-lan"` - BindAddress string `yaml:"bind-address" json:"bind-address"` - Mode T.TunnelMode `yaml:"mode" json:"mode"` - UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"` - LogLevel log.LogLevel `yaml:"log-level" json:"log-level"` - IPv6 bool `yaml:"ipv6" json:"ipv6"` - ExternalController string `yaml:"external-controller"` - ExternalControllerUnix string `yaml:"external-controller-unix"` - ExternalControllerTLS string `yaml:"external-controller-tls"` - ExternalUI string `yaml:"external-ui"` - ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"` - ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"` - ExternalDohServer string `yaml:"external-doh-server"` - Secret string `yaml:"secret"` - Interface string `yaml:"interface-name"` - RoutingMark int `yaml:"routing-mark"` - Tunnels []LC.Tunnel `yaml:"tunnels"` - GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"` - GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"` - GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"` - GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"` - GeositeMatcher string `yaml:"geosite-matcher" json:"geosite-matcher"` - TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` - FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` - GlobalClientFingerprint string `yaml:"global-client-fingerprint"` - GlobalUA string `yaml:"global-ua"` - KeepAliveIdle int `yaml:"keep-alive-idle"` - KeepAliveInterval int `yaml:"keep-alive-interval"` - DisableKeepAlive bool `yaml:"disable-keep-alive"` - - Sniffer RawSniffer `yaml:"sniffer" json:"sniffer"` - ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` - RuleProvider map[string]map[string]any `yaml:"rule-providers"` - Hosts map[string]any `yaml:"hosts" json:"hosts"` - NTP RawNTP `yaml:"ntp" json:"ntp"` - DNS RawDNS `yaml:"dns" json:"dns"` - Tun RawTun `yaml:"tun"` - TuicServer RawTuicServer `yaml:"tuic-server"` - IPTables IPTables `yaml:"iptables"` - Experimental Experimental `yaml:"experimental"` - Profile Profile `yaml:"profile"` - GeoXUrl GeoXUrl `yaml:"geox-url"` - Proxy []map[string]any `yaml:"proxies"` - ProxyGroup []map[string]any `yaml:"proxy-groups"` - Rule []string `yaml:"rules"` - SubRules map[string][]string `yaml:"sub-rules"` - RawTLS TLS `yaml:"tls"` - Listeners []map[string]any `yaml:"listeners"` - - ClashForAndroid RawClashForAndroid `yaml:"clash-for-android" json:"clash-for-android"` +type RawIPTables struct { + Enable bool `yaml:"enable" json:"enable"` + InboundInterface string `yaml:"inbound-interface" json:"inbound-interface"` + Bypass []string `yaml:"bypass" json:"bypass"` + DnsRedirect bool `yaml:"dns-redirect" json:"dns-redirect"` } -type GeoXUrl struct { +type RawExperimental struct { + Fingerprints []string `yaml:"fingerprints"` + QUICGoDisableGSO bool `yaml:"quic-go-disable-gso"` + QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"` + IP4PEnable bool `yaml:"dialer-ip4p-convert"` +} + +type RawProfile struct { + StoreSelected bool `yaml:"store-selected" json:"store-selected"` + StoreFakeIP bool `yaml:"store-fake-ip" json:"store-fake-ip"` +} + +type RawGeoXUrl struct { GeoIp string `yaml:"geoip" json:"geoip"` Mmdb string `yaml:"mmdb" json:"mmdb"` ASN string `yaml:"asn" json:"asn"` @@ -380,6 +343,78 @@ type RawSniffingConfig struct { OverrideDest *bool `yaml:"override-destination" json:"override-destination"` } +type RawTLS struct { + Certificate string `yaml:"certificate" json:"certificate"` + PrivateKey string `yaml:"private-key" json:"private-key"` + CustomTrustCert []string `yaml:"custom-certifactes" json:"custom-certifactes"` +} + +type RawConfig struct { + Port int `yaml:"port" json:"port"` + SocksPort int `yaml:"socks-port" json:"socks-port"` + RedirPort int `yaml:"redir-port" json:"redir-port"` + TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"` + MixedPort int `yaml:"mixed-port" json:"mixed-port"` + ShadowSocksConfig string `yaml:"ss-config" json:"ss-config"` + VmessConfig string `yaml:"vmess-config" json:"vmess-config"` + InboundTfo bool `yaml:"inbound-tfo" json:"inbound-tfo"` + InboundMPTCP bool `yaml:"inbound-mptcp" json:"inbound-mptcp"` + Authentication []string `yaml:"authentication" json:"authentication"` + SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes" json:"skip-auth-prefixes"` + LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips" json:"lan-allowed-ips"` + LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips" json:"lan-disallowed-ips"` + AllowLan bool `yaml:"allow-lan" json:"allow-lan"` + BindAddress string `yaml:"bind-address" json:"bind-address"` + Mode T.TunnelMode `yaml:"mode" json:"mode"` + UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"` + LogLevel log.LogLevel `yaml:"log-level" json:"log-level"` + IPv6 bool `yaml:"ipv6" json:"ipv6"` + ExternalController string `yaml:"external-controller" json:"external-controller"` + ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"` + ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"` + ExternalUI string `yaml:"external-ui" json:"external-ui"` + ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"` + ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"` + ExternalDohServer string `yaml:"external-doh-server" json:"external-doh-server"` + Secret string `yaml:"secret" json:"secret"` + Interface string `yaml:"interface-name" json:"interface-name"` + RoutingMark int `yaml:"routing-mark" json:"routing-mark"` + Tunnels []LC.Tunnel `yaml:"tunnels" json:"tunnels"` + GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"` + GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"` + GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"` + GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"` + GeositeMatcher string `yaml:"geosite-matcher" json:"geosite-matcher"` + TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` + FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` + GlobalClientFingerprint string `yaml:"global-client-fingerprint" json:"global-client-fingerprint"` + GlobalUA string `yaml:"global-ua" json:"global-ua"` + KeepAliveIdle int `yaml:"keep-alive-idle" json:"keep-alive-idle"` + KeepAliveInterval int `yaml:"keep-alive-interval" json:"keep-alive-interval"` + DisableKeepAlive bool `yaml:"disable-keep-alive" json:"disable-keep-alive"` + + ProxyProvider map[string]map[string]any `yaml:"proxy-providers" json:"proxy-providers"` + RuleProvider map[string]map[string]any `yaml:"rule-providers" json:"rule-providers"` + Proxy []map[string]any `yaml:"proxies" json:"proxies"` + ProxyGroup []map[string]any `yaml:"proxy-groups" json:"proxy-groups"` + Rule []string `yaml:"rules" json:"rule"` + SubRules map[string][]string `yaml:"sub-rules" json:"sub-rules"` + Listeners []map[string]any `yaml:"listeners" json:"listeners"` + Hosts map[string]any `yaml:"hosts" json:"hosts"` + DNS RawDNS `yaml:"dns" json:"dns"` + NTP RawNTP `yaml:"ntp" json:"ntp"` + Tun RawTun `yaml:"tun" json:"tun"` + TuicServer RawTuicServer `yaml:"tuic-server" json:"tuic-server"` + IPTables RawIPTables `yaml:"iptables" json:"iptables"` + Experimental RawExperimental `yaml:"experimental" json:"experimental"` + Profile RawProfile `yaml:"profile" json:"profile"` + GeoXUrl RawGeoXUrl `yaml:"geox-url" json:"geox-url"` + Sniffer RawSniffer `yaml:"sniffer" json:"sniffer"` + TLS RawTLS `yaml:"tls" json:"tls"` + + ClashForAndroid RawClashForAndroid `yaml:"clash-for-android" json:"clash-for-android"` +} + var ( GroupsList = list.New() ProxiesList = list.New() @@ -418,41 +453,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { TCPConcurrent: false, FindProcessMode: P.FindProcessStrict, GlobalUA: "clash.meta/" + C.Version, - Tun: RawTun{ - Enable: false, - Device: "", - Stack: C.TunGvisor, - DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query - AutoRoute: true, - AutoDetectInterface: true, - Inet6Address: []netip.Prefix{netip.MustParsePrefix("fdfe:dcba:9876::1/126")}, - }, - TuicServer: RawTuicServer{ - Enable: false, - Token: nil, - Users: nil, - Certificate: "", - PrivateKey: "", - Listen: "", - CongestionController: "", - MaxIdleTime: 15000, - AuthenticationTimeout: 1000, - ALPN: []string{"h3"}, - MaxUdpRelayPacketSize: 1500, - }, - IPTables: IPTables{ - Enable: false, - InboundInterface: "lo", - Bypass: []string{}, - DnsRedirect: true, - }, - NTP: RawNTP{ - Enable: false, - WriteToSystem: false, - Server: "time.apple.com", - ServerPort: 123, - Interval: 30, - }, DNS: RawDNS{ Enable: false, IPv6: false, @@ -483,11 +483,55 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { "www.msftconnecttest.com", }, }, - Experimental: Experimental{ + NTP: RawNTP{ + Enable: false, + WriteToSystem: false, + Server: "time.apple.com", + Port: 123, + Interval: 30, + }, + Tun: RawTun{ + Enable: false, + Device: "", + Stack: C.TunGvisor, + DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query + AutoRoute: true, + AutoDetectInterface: true, + Inet6Address: []netip.Prefix{netip.MustParsePrefix("fdfe:dcba:9876::1/126")}, + }, + TuicServer: RawTuicServer{ + Enable: false, + Token: nil, + Users: nil, + Certificate: "", + PrivateKey: "", + Listen: "", + CongestionController: "", + MaxIdleTime: 15000, + AuthenticationTimeout: 1000, + ALPN: []string{"h3"}, + MaxUdpRelayPacketSize: 1500, + }, + IPTables: RawIPTables{ + Enable: false, + InboundInterface: "lo", + Bypass: []string{}, + DnsRedirect: true, + }, + Experimental: RawExperimental{ // https://github.com/quic-go/quic-go/issues/4178 // Quic-go currently cannot automatically fall back on platforms that do not support ecn, so this feature is turned off by default. QUICGoDisableECN: true, }, + Profile: RawProfile{ + StoreSelected: true, + }, + GeoXUrl: RawGeoXUrl{ + Mmdb: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + ASN: "https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb", + GeoIp: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", + GeoSite: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat", + }, Sniffer: RawSniffer{ Enable: false, Sniff: map[string]RawSniffingConfig{}, @@ -498,15 +542,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { ParsePureIp: true, OverrideDest: true, }, - Profile: Profile{ - StoreSelected: true, - }, - GeoXUrl: GeoXUrl{ - Mmdb: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", - ASN: "https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb", - GeoIp: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", - GeoSite: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat", - }, ExternalUIURL: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip", } @@ -521,10 +556,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { config := &Config{} log.Infoln("Start initial configuration in progress") //Segment finished in xxm startTime := time.Now() - config.Experimental = &rawCfg.Experimental - config.Profile = &rawCfg.Profile - config.IPTables = &rawCfg.IPTables - config.TLS = &rawCfg.RawTLS general, err := parseGeneral(rawCfg) if err != nil { @@ -537,6 +568,42 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint) } + controller, err := parseController(rawCfg) + if err != nil { + return nil, err + } + config.Controller = controller + + experimental, err := parseExperimental(rawCfg) + if err != nil { + return nil, err + } + config.Experimental = experimental + + iptables, err := parseIPTables(rawCfg) + if err != nil { + return nil, err + } + config.IPTables = iptables + + ntpCfg, err := parseNTP(rawCfg) + if err != nil { + return nil, err + } + config.NTP = ntpCfg + + profile, err := parseProfile(rawCfg) + if err != nil { + return nil, err + } + config.Profile = profile + + tlsCfg, err := parseTLS(rawCfg) + if err != nil { + return nil, err + } + config.TLS = tlsCfg + proxies, providers, err := parseProxies(rawCfg) if err != nil { return nil, err @@ -576,9 +643,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } config.Hosts = hosts - ntpCfg := paresNTP(rawCfg) - config.NTP = ntpCfg - dnsCfg, err := parseDNS(rawCfg, hosts, rules, ruleProviders) if err != nil { return nil, err @@ -687,21 +751,18 @@ func parseGeneral(cfg *RawConfig) (*General, error) { InboundTfo: cfg.InboundTfo, InboundMPTCP: cfg.InboundMPTCP, }, - Controller: Controller{ - ExternalController: cfg.ExternalController, - ExternalUI: cfg.ExternalUI, - Secret: cfg.Secret, - ExternalControllerUnix: cfg.ExternalControllerUnix, - ExternalControllerTLS: cfg.ExternalControllerTLS, - ExternalDohServer: cfg.ExternalDohServer, + UnifiedDelay: cfg.UnifiedDelay, + Mode: cfg.Mode, + LogLevel: cfg.LogLevel, + IPv6: cfg.IPv6, + Interface: cfg.Interface, + RoutingMark: cfg.RoutingMark, + GeoXUrl: GeoXUrl{ + GeoIp: cfg.GeoXUrl.GeoIp, + Mmdb: cfg.GeoXUrl.Mmdb, + ASN: cfg.GeoXUrl.ASN, + GeoSite: cfg.GeoXUrl.GeoSite, }, - UnifiedDelay: cfg.UnifiedDelay, - Mode: cfg.Mode, - LogLevel: cfg.LogLevel, - IPv6: cfg.IPv6, - Interface: cfg.Interface, - RoutingMark: cfg.RoutingMark, - GeoXUrl: cfg.GeoXUrl, GeoAutoUpdate: cfg.GeoAutoUpdate, GeoUpdateInterval: cfg.GeoUpdateInterval, GeodataMode: cfg.GeodataMode, @@ -713,6 +774,61 @@ func parseGeneral(cfg *RawConfig) (*General, error) { }, nil } +func parseController(cfg *RawConfig) (*Controller, error) { + return &Controller{ + ExternalController: cfg.ExternalController, + ExternalUI: cfg.ExternalUI, + Secret: cfg.Secret, + ExternalControllerUnix: cfg.ExternalControllerUnix, + ExternalControllerTLS: cfg.ExternalControllerTLS, + ExternalDohServer: cfg.ExternalDohServer, + }, nil +} + +func parseExperimental(cfg *RawConfig) (*Experimental, error) { + return &Experimental{ + Fingerprints: cfg.Experimental.Fingerprints, + QUICGoDisableGSO: cfg.Experimental.QUICGoDisableGSO, + QUICGoDisableECN: cfg.Experimental.QUICGoDisableECN, + IP4PEnable: cfg.Experimental.IP4PEnable, + }, nil +} + +func parseIPTables(cfg *RawConfig) (*IPTables, error) { + return &IPTables{ + Enable: cfg.IPTables.Enable, + InboundInterface: cfg.IPTables.InboundInterface, + Bypass: cfg.IPTables.Bypass, + DnsRedirect: cfg.IPTables.DnsRedirect, + }, nil +} + +func parseNTP(cfg *RawConfig) (*NTP, error) { + return &NTP{ + Enable: cfg.NTP.Enable, + Server: cfg.NTP.Server, + Port: cfg.NTP.Port, + Interval: cfg.NTP.Interval, + DialerProxy: cfg.NTP.DialerProxy, + WriteToSystem: cfg.NTP.WriteToSystem, + }, nil +} + +func parseProfile(cfg *RawConfig) (*Profile, error) { + return &Profile{ + StoreSelected: cfg.Profile.StoreSelected, + StoreFakeIP: cfg.Profile.StoreFakeIP, + }, nil +} + +func parseTLS(cfg *RawConfig) (*TLS, error) { + return &TLS{ + Certificate: cfg.TLS.Certificate, + PrivateKey: cfg.TLS.PrivateKey, + CustomTrustCert: cfg.TLS.CustomTrustCert, + }, nil +} + func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) { proxies = make(map[string]C.Proxy) providersMap = make(map[string]providerTypes.ProxyProvider) @@ -1259,19 +1375,6 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules [ return policy, nil } -func paresNTP(rawCfg *RawConfig) *NTP { - cfg := rawCfg.NTP - ntpCfg := &NTP{ - Enable: cfg.Enable, - Server: cfg.Server, - Port: cfg.ServerPort, - Interval: cfg.Interval, - DialerProxy: cfg.DialerProxy, - WriteToSystem: cfg.WriteToSystem, - } - return ntpCfg -} - func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) { cfg := rawCfg.DNS if cfg.Enable && len(cfg.NameServer) == 0 { diff --git a/clash-meta/hub/executor/executor.go b/clash-meta/hub/executor/executor.go index 891452412f..d54d55b752 100644 --- a/clash-meta/hub/executor/executor.go +++ b/clash-meta/hub/executor/executor.go @@ -22,6 +22,7 @@ import ( "github.com/metacubex/mihomo/component/profile/cachefile" "github.com/metacubex/mihomo/component/resolver" SNI "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" "github.com/metacubex/mihomo/config" @@ -90,6 +91,7 @@ func ApplyConfig(cfg *config.Config, force bool) { } } + updateExperimental(cfg.Experimental) updateUsers(cfg.Users) updateProxies(cfg.Proxies, cfg.Providers) updateRules(cfg.Rules, cfg.SubRules, cfg.RuleProviders) @@ -100,8 +102,6 @@ func ApplyConfig(cfg *config.Config, force bool) { updateDNS(cfg.DNS, cfg.General.IPv6) updateListeners(cfg.General, cfg.Listeners, force) updateIPTables(cfg) - updateTun(cfg.General) - updateExperimental(cfg) updateTunnels(cfg.Tunnels) tunnel.OnInnerLoading() @@ -146,19 +146,31 @@ func GetGeneral() *config.General { LanDisAllowedIPs: inbound.DisAllowedIPs(), AllowLan: listener.AllowLan(), BindAddress: listener.BindAddress(), + InboundTfo: inbound.Tfo(), + InboundMPTCP: inbound.MPTCP(), }, - Controller: config.Controller{}, - Mode: tunnel.Mode(), - LogLevel: log.Level(), - IPv6: !resolver.DisableIPv6, - GeodataMode: G.GeodataMode(), - GeoAutoUpdate: G.GeoAutoUpdate(), - GeoUpdateInterval: G.GeoUpdateInterval(), - GeodataLoader: G.LoaderName(), - GeositeMatcher: G.SiteMatcherName(), - Interface: dialer.DefaultInterface.Load(), - Sniffing: tunnel.IsSniffing(), - TCPConcurrent: dialer.GetTcpConcurrent(), + Mode: tunnel.Mode(), + UnifiedDelay: adapter.UnifiedDelay.Load(), + LogLevel: log.Level(), + IPv6: !resolver.DisableIPv6, + Interface: dialer.DefaultInterface.Load(), + RoutingMark: int(dialer.DefaultRoutingMark.Load()), + GeoXUrl: config.GeoXUrl{ + GeoIp: C.GeoIpUrl, + Mmdb: C.MmdbUrl, + ASN: C.ASNUrl, + GeoSite: C.GeoSiteUrl, + }, + GeoAutoUpdate: G.GeoAutoUpdate(), + GeoUpdateInterval: G.GeoUpdateInterval(), + GeodataMode: G.GeodataMode(), + GeodataLoader: G.LoaderName(), + GeositeMatcher: G.SiteMatcherName(), + TCPConcurrent: dialer.GetTcpConcurrent(), + FindProcessMode: tunnel.FindProcessMode(), + Sniffing: tunnel.IsSniffing(), + GlobalClientFingerprint: tlsC.GetGlobalFingerprint(), + GlobalUA: C.UA, } return general @@ -186,16 +198,17 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel) listener.ReCreateVmess(general.VmessConfig, tunnel.Tunnel) listener.ReCreateTuic(general.TuicServer, tunnel.Tunnel) + listener.ReCreateTun(general.Tun, tunnel.Tunnel) } -func updateExperimental(c *config.Config) { - if c.Experimental.QUICGoDisableGSO { +func updateExperimental(c *config.Experimental) { + if c.QUICGoDisableGSO { _ = os.Setenv("QUIC_GO_DISABLE_GSO", strconv.FormatBool(true)) } - if c.Experimental.QUICGoDisableECN { + if c.QUICGoDisableECN { _ = os.Setenv("QUIC_GO_DISABLE_ECN", strconv.FormatBool(true)) } - dialer.GetIP4PEnable(c.Experimental.IP4PEnable) + dialer.GetIP4PEnable(c.IP4PEnable) } func updateNTP(c *config.NTP) { @@ -343,12 +356,6 @@ func hcCompatibleProvider(proxyProviders map[string]provider.ProxyProvider) { } } -func updateTun(general *config.General) { - if general == nil { - return - } - listener.ReCreateTun(general.Tun, tunnel.Tunnel) -} func updateSniffer(sniffer *config.Sniffer) { if sniffer.Enable { diff --git a/clash-meta/hub/hub.go b/clash-meta/hub/hub.go index 57c91aaef9..2a53b19793 100644 --- a/clash-meta/hub/hub.go +++ b/clash-meta/hub/hub.go @@ -11,25 +11,25 @@ type Option func(*config.Config) func WithExternalUI(externalUI string) Option { return func(cfg *config.Config) { - cfg.General.ExternalUI = externalUI + cfg.Controller.ExternalUI = externalUI } } func WithExternalController(externalController string) Option { return func(cfg *config.Config) { - cfg.General.ExternalController = externalController + cfg.Controller.ExternalController = externalController } } func WithExternalControllerUnix(externalControllerUnix string) Option { return func(cfg *config.Config) { - cfg.General.ExternalControllerUnix = externalControllerUnix + cfg.Controller.ExternalControllerUnix = externalControllerUnix } } func WithSecret(secret string) Option { return func(cfg *config.Config) { - cfg.General.Secret = secret + cfg.Controller.Secret = secret } } @@ -44,18 +44,18 @@ func Parse(options ...Option) error { option(cfg) } - if cfg.General.ExternalUI != "" { - route.SetUIPath(cfg.General.ExternalUI) + if cfg.Controller.ExternalUI != "" { + route.SetUIPath(cfg.Controller.ExternalUI) } - if cfg.General.ExternalController != "" { - go route.Start(cfg.General.ExternalController, cfg.General.ExternalControllerTLS, - cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.General.ExternalDohServer, + if cfg.Controller.ExternalController != "" { + go route.Start(cfg.Controller.ExternalController, cfg.Controller.ExternalControllerTLS, + cfg.Controller.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.Controller.ExternalDohServer, cfg.General.LogLevel == log.DEBUG) } - if cfg.General.ExternalControllerUnix != "" { - go route.StartUnix(cfg.General.ExternalControllerUnix, cfg.General.ExternalDohServer, cfg.General.LogLevel == log.DEBUG) + if cfg.Controller.ExternalControllerUnix != "" { + go route.StartUnix(cfg.Controller.ExternalControllerUnix, cfg.Controller.ExternalDohServer, cfg.General.LogLevel == log.DEBUG) } executor.ApplyConfig(cfg, true) diff --git a/clash-meta/hub/route/configs.go b/clash-meta/hub/route/configs.go index c7b340c603..d4bda2bf4c 100644 --- a/clash-meta/hub/route/configs.go +++ b/clash-meta/hub/route/configs.go @@ -62,23 +62,22 @@ type tunSchema struct { DNSHijack *[]string `yaml:"dns-hijack" json:"dns-hijack"` AutoRoute *bool `yaml:"auto-route" json:"auto-route"` AutoDetectInterface *bool `yaml:"auto-detect-interface" json:"auto-detect-interface"` - //RedirectToTun []string `yaml:"-" json:"-"` MTU *uint32 `yaml:"mtu" json:"mtu,omitempty"` GSO *bool `yaml:"gso" json:"gso,omitempty"` GSOMaxSize *uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` //Inet4Address *[]netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - IPRoute2TableIndex *int `yaml:"iproute2-table-index" json:"iproute2_table_index,omitempty"` - IPRoute2RuleIndex *int `yaml:"iproute2-rule-index" json:"iproute2_rule_index,omitempty"` - AutoRedirect *bool `yaml:"auto-redirect" json:"auto_redirect,omitempty"` - AutoRedirectInputMark *uint32 `yaml:"auto-redirect-input-mark" json:"auto_redirect_input_mark,omitempty"` - AutoRedirectOutputMark *uint32 `yaml:"auto-redirect-output-mark" json:"auto_redirect_output_mark,omitempty"` + IPRoute2TableIndex *int `yaml:"iproute2-table-index" json:"iproute2-table-index,omitempty"` + IPRoute2RuleIndex *int `yaml:"iproute2-rule-index" json:"iproute2-rule-index,omitempty"` + AutoRedirect *bool `yaml:"auto-redirect" json:"auto-redirect,omitempty"` + AutoRedirectInputMark *uint32 `yaml:"auto-redirect-input-mark" json:"auto-redirect-input-mark,omitempty"` + AutoRedirectOutputMark *uint32 `yaml:"auto-redirect-output-mark" json:"auto-redirect-output-mark,omitempty"` StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` - RouteAddress *[]netip.Prefix `yaml:"route-address" json:"route_address,omitempty"` - RouteAddressSet *[]string `yaml:"route-address-set" json:"route_address_set,omitempty"` - RouteExcludeAddress *[]netip.Prefix `yaml:"route-exclude-address" json:"route_exclude_address,omitempty"` - RouteExcludeAddressSet *[]string `yaml:"route-exclude-address-set" json:"route_exclude_address_set,omitempty"` + RouteAddress *[]netip.Prefix `yaml:"route-address" json:"route-address,omitempty"` + RouteAddressSet *[]string `yaml:"route-address-set" json:"route-address-set,omitempty"` + RouteExcludeAddress *[]netip.Prefix `yaml:"route-exclude-address" json:"route-exclude-address,omitempty"` + RouteExcludeAddressSet *[]string `yaml:"route-exclude-address-set" json:"route-exclude-address-set,omitempty"` IncludeInterface *[]string `yaml:"include-interface" json:"include-interface,omitempty"` ExcludeInterface *[]string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` @@ -118,21 +117,13 @@ func getConfigs(w http.ResponseWriter, r *http.Request) { render.JSON(w, r, general) } -func pointerOrDefault(p *int, def int) int { +func pointerOrDefault[T any](p *T, def T) T { if p != nil { return *p } return def } -func pointerOrDefaultString(p *string, def string) string { - if p != nil { - return *p - } - - return def -} - func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun { if p != nil { def.Enable = p.Enable @@ -336,8 +327,8 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tunnel.Tunnel) P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tunnel.Tunnel) P.ReCreateTun(pointerOrDefaultTun(general.Tun, P.LastTunConf), tunnel.Tunnel) - P.ReCreateShadowSocks(pointerOrDefaultString(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel) - P.ReCreateVmess(pointerOrDefaultString(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel) + P.ReCreateShadowSocks(pointerOrDefault(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel) + P.ReCreateVmess(pointerOrDefault(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel) P.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, P.LastTuicConf), tunnel.Tunnel) if general.Mode != nil { diff --git a/clash-meta/listener/config/tun.go b/clash-meta/listener/config/tun.go index cea22bfdc8..3901bb1d6d 100644 --- a/clash-meta/listener/config/tun.go +++ b/clash-meta/listener/config/tun.go @@ -3,7 +3,10 @@ package config import ( "net/netip" + "github.com/metacubex/mihomo/common/nnip" C "github.com/metacubex/mihomo/constant" + + "golang.org/x/exp/slices" ) func StringSliceToNetipPrefixSlice(ss []string) ([]netip.Prefix, error) { @@ -25,23 +28,22 @@ type Tun struct { DNSHijack []string `yaml:"dns-hijack" json:"dns-hijack"` AutoRoute bool `yaml:"auto-route" json:"auto-route"` AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"` - RedirectToTun []string `yaml:"-" json:"-"` MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` GSO bool `yaml:"gso" json:"gso,omitempty"` GSOMaxSize uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2_table_index,omitempty"` - IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2_rule_index,omitempty"` - AutoRedirect bool `yaml:"auto-redirect" json:"auto_redirect,omitempty"` - AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto_redirect_input_mark,omitempty"` - AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto_redirect_output_mark,omitempty"` + IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2-table-index,omitempty"` + IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2-rule-index,omitempty"` + AutoRedirect bool `yaml:"auto-redirect" json:"auto-redirect,omitempty"` + AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto-redirect-input-mark,omitempty"` + AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto-redirect-output-mark,omitempty"` StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` - RouteAddress []netip.Prefix `yaml:"route-address" json:"route_address,omitempty"` - RouteAddressSet []string `yaml:"route-address-set" json:"route_address_set,omitempty"` - RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route_exclude_address,omitempty"` - RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route_exclude_address_set,omitempty"` + RouteAddress []netip.Prefix `yaml:"route-address" json:"route-address,omitempty"` + RouteAddressSet []string `yaml:"route-address-set" json:"route-address-set,omitempty"` + RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route-exclude-address,omitempty"` + RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route-exclude-address-set,omitempty"` IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` @@ -60,3 +62,146 @@ type Tun struct { Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` } + +func (t *Tun) Sort() { + slices.Sort(t.DNSHijack) + + slices.SortFunc(t.Inet4Address, nnip.PrefixCompare) + slices.SortFunc(t.Inet6Address, nnip.PrefixCompare) + slices.SortFunc(t.RouteAddress, nnip.PrefixCompare) + slices.Sort(t.RouteAddressSet) + slices.SortFunc(t.RouteExcludeAddress, nnip.PrefixCompare) + slices.Sort(t.RouteExcludeAddressSet) + slices.Sort(t.IncludeInterface) + slices.Sort(t.ExcludeInterface) + slices.Sort(t.IncludeUID) + slices.Sort(t.IncludeUIDRange) + slices.Sort(t.ExcludeUID) + slices.Sort(t.ExcludeUIDRange) + slices.Sort(t.IncludeAndroidUser) + slices.Sort(t.IncludePackage) + slices.Sort(t.ExcludePackage) + + slices.SortFunc(t.Inet4RouteAddress, nnip.PrefixCompare) + slices.SortFunc(t.Inet6RouteAddress, nnip.PrefixCompare) + slices.SortFunc(t.Inet4RouteExcludeAddress, nnip.PrefixCompare) + slices.SortFunc(t.Inet6RouteExcludeAddress, nnip.PrefixCompare) +} + +func (t *Tun) Equal(other Tun) bool { + if t.Enable != other.Enable { + return false + } + if t.Device != other.Device { + return false + } + if t.Stack != other.Stack { + return false + } + if !slices.Equal(t.DNSHijack, other.DNSHijack) { + return false + } + if t.AutoRoute != other.AutoRoute { + return false + } + if t.AutoDetectInterface != other.AutoDetectInterface { + return false + } + + if t.MTU != other.MTU { + return false + } + if t.GSO != other.GSO { + return false + } + if t.GSOMaxSize != other.GSOMaxSize { + return false + } + if !slices.Equal(t.Inet4Address, other.Inet4Address) { + return false + } + if !slices.Equal(t.Inet6Address, other.Inet6Address) { + return false + } + if t.IPRoute2TableIndex != other.IPRoute2TableIndex { + return false + } + if t.IPRoute2RuleIndex != other.IPRoute2RuleIndex { + return false + } + if t.AutoRedirect != other.AutoRedirect { + return false + } + if t.AutoRedirectInputMark != other.AutoRedirectInputMark { + return false + } + if t.AutoRedirectOutputMark != other.AutoRedirectOutputMark { + return false + } + if t.StrictRoute != other.StrictRoute { + return false + } + if !slices.Equal(t.RouteAddress, other.RouteAddress) { + return false + } + if !slices.Equal(t.RouteAddressSet, other.RouteAddressSet) { + return false + } + if !slices.Equal(t.RouteExcludeAddress, other.RouteExcludeAddress) { + return false + } + if !slices.Equal(t.RouteExcludeAddressSet, other.RouteExcludeAddressSet) { + return false + } + if !slices.Equal(t.IncludeInterface, other.IncludeInterface) { + return false + } + if !slices.Equal(t.ExcludeInterface, other.ExcludeInterface) { + return false + } + if !slices.Equal(t.IncludeUID, other.IncludeUID) { + return false + } + if !slices.Equal(t.IncludeUIDRange, other.IncludeUIDRange) { + return false + } + if !slices.Equal(t.ExcludeUID, other.ExcludeUID) { + return false + } + if !slices.Equal(t.ExcludeUIDRange, other.ExcludeUIDRange) { + return false + } + if !slices.Equal(t.IncludeAndroidUser, other.IncludeAndroidUser) { + return false + } + if !slices.Equal(t.IncludePackage, other.IncludePackage) { + return false + } + if !slices.Equal(t.ExcludePackage, other.ExcludePackage) { + return false + } + if t.EndpointIndependentNat != other.EndpointIndependentNat { + return false + } + if t.UDPTimeout != other.UDPTimeout { + return false + } + if t.FileDescriptor != other.FileDescriptor { + return false + } + + if !slices.Equal(t.Inet4RouteAddress, other.Inet4RouteAddress) { + return false + } + if !slices.Equal(t.Inet6RouteAddress, other.Inet6RouteAddress) { + return false + } + if !slices.Equal(t.Inet4RouteExcludeAddress, other.Inet4RouteExcludeAddress) { + return false + } + if !slices.Equal(t.Inet6RouteExcludeAddress, other.Inet6RouteExcludeAddress) { + return false + } + + return true +} diff --git a/clash-meta/listener/inbound/tun.go b/clash-meta/listener/inbound/tun.go index a950f80db2..77ad6bd61c 100644 --- a/clash-meta/listener/inbound/tun.go +++ b/clash-meta/listener/inbound/tun.go @@ -21,35 +21,35 @@ type TunOption struct { MTU uint32 `inbound:"mtu,omitempty"` GSO bool `inbound:"gso,omitempty"` GSOMaxSize uint32 `inbound:"gso-max-size,omitempty"` - Inet4Address []string `inbound:"inet4_address,omitempty"` - Inet6Address []string `inbound:"inet6_address,omitempty"` + Inet4Address []string `inbound:"inet4-address,omitempty"` + Inet6Address []string `inbound:"inet6-address,omitempty"` IPRoute2TableIndex int `inbound:"iproute2-table-index"` IPRoute2RuleIndex int `inbound:"iproute2-rule-index"` AutoRedirect bool `inbound:"auto-redirect"` AutoRedirectInputMark uint32 `inbound:"auto-redirect-input-mark"` AutoRedirectOutputMark uint32 `inbound:"auto-redirect-output-mark"` - StrictRoute bool `inbound:"strict_route,omitempty"` + StrictRoute bool `inbound:"strict-route,omitempty"` RouteAddress []string `inbound:"route-address"` RouteAddressSet []string `inbound:"route-address-set"` RouteExcludeAddress []string `inbound:"route-exclude-address"` RouteExcludeAddressSet []string `inbound:"route-exclude-address-set"` IncludeInterface []string `inbound:"include-interface,omitempty"` ExcludeInterface []string `inbound:"exclude-interface"` - IncludeUID []uint32 `inbound:"include_uid,omitempty"` - IncludeUIDRange []string `inbound:"include_uid_range,omitempty"` - ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"` - ExcludeUIDRange []string `inbound:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `inbound:"include_android_user,omitempty"` - IncludePackage []string `inbound:"include_package,omitempty"` - ExcludePackage []string `inbound:"exclude_package,omitempty"` - EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `inbound:"udp_timeout,omitempty"` + IncludeUID []uint32 `inbound:"include-uid,omitempty"` + IncludeUIDRange []string `inbound:"include-uid-range,omitempty"` + ExcludeUID []uint32 `inbound:"exclude-uid,omitempty"` + ExcludeUIDRange []string `inbound:"exclude-uid-range,omitempty"` + IncludeAndroidUser []int `inbound:"include-android-user,omitempty"` + IncludePackage []string `inbound:"include-package,omitempty"` + ExcludePackage []string `inbound:"exclude-package,omitempty"` + EndpointIndependentNat bool `inbound:"endpoint-independent-nat,omitempty"` + UDPTimeout int64 `inbound:"udp-timeout,omitempty"` FileDescriptor int `inbound:"file-descriptor,omitempty"` - Inet4RouteAddress []string `inbound:"inet4_route_address,omitempty"` - Inet6RouteAddress []string `inbound:"inet6_route_address,omitempty"` - Inet4RouteExcludeAddress []string `inbound:"inet4_route_exclude_address,omitempty"` - Inet6RouteExcludeAddress []string `inbound:"inet6_route_exclude_address,omitempty"` + Inet4RouteAddress []string `inbound:"inet4-route-address,omitempty"` + Inet6RouteAddress []string `inbound:"inet6-route-address,omitempty"` + Inet4RouteExcludeAddress []string `inbound:"inet4-route-exclude-address,omitempty"` + Inet6RouteExcludeAddress []string `inbound:"inet6-route-exclude-address,omitempty"` } func (o TunOption) Equal(config C.InboundConfig) bool { diff --git a/clash-meta/listener/listener.go b/clash-meta/listener/listener.go index 4d10677812..2e25c8b8f6 100644 --- a/clash-meta/listener/listener.go +++ b/clash-meta/listener/listener.go @@ -2,9 +2,7 @@ package listener import ( "fmt" - "golang.org/x/exp/slices" "net" - "sort" "strconv" "strings" "sync" @@ -49,19 +47,17 @@ var ( tuicListener *tuic.Listener // lock for recreate function - socksMux sync.Mutex - httpMux sync.Mutex - redirMux sync.Mutex - tproxyMux sync.Mutex - mixedMux sync.Mutex - tunnelMux sync.Mutex - inboundMux sync.Mutex - tunMux sync.Mutex - ssMux sync.Mutex - vmessMux sync.Mutex - tuicMux sync.Mutex - autoRedirMux sync.Mutex - tcMux sync.Mutex + socksMux sync.Mutex + httpMux sync.Mutex + redirMux sync.Mutex + tproxyMux sync.Mutex + mixedMux sync.Mutex + tunnelMux sync.Mutex + inboundMux sync.Mutex + tunMux sync.Mutex + ssMux sync.Mutex + vmessMux sync.Mutex + tuicMux sync.Mutex LastTunConf LC.Tun LastTuicConf LC.TuicServer @@ -499,6 +495,8 @@ func ReCreateMixed(port int, tunnel C.Tunnel) { } func ReCreateTun(tunConf LC.Tun, tunnel C.Tunnel) { + tunConf.Sort() + tunMux.Lock() defer func() { LastTunConf = tunConf @@ -513,7 +511,7 @@ func ReCreateTun(tunConf LC.Tun, tunnel C.Tunnel) { } }() - if !hasTunConfigChange(&tunConf) { + if tunConf.Equal(LastTunConf) { if tunLister != nil { tunLister.FlushDefaultInterface() } @@ -717,137 +715,6 @@ func genAddr(host string, port int, allowLan bool) string { return fmt.Sprintf("127.0.0.1:%d", port) } -func hasTunConfigChange(tunConf *LC.Tun) bool { - if LastTunConf.Enable != tunConf.Enable || - LastTunConf.Device != tunConf.Device || - LastTunConf.Stack != tunConf.Stack || - LastTunConf.AutoRoute != tunConf.AutoRoute || - LastTunConf.AutoDetectInterface != tunConf.AutoDetectInterface || - LastTunConf.MTU != tunConf.MTU || - LastTunConf.GSO != tunConf.GSO || - LastTunConf.GSOMaxSize != tunConf.GSOMaxSize || - LastTunConf.IPRoute2TableIndex != tunConf.IPRoute2TableIndex || - LastTunConf.IPRoute2RuleIndex != tunConf.IPRoute2RuleIndex || - LastTunConf.AutoRedirect != tunConf.AutoRedirect || - LastTunConf.AutoRedirectInputMark != tunConf.AutoRedirectInputMark || - LastTunConf.AutoRedirectOutputMark != tunConf.AutoRedirectOutputMark || - LastTunConf.StrictRoute != tunConf.StrictRoute || - LastTunConf.EndpointIndependentNat != tunConf.EndpointIndependentNat || - LastTunConf.UDPTimeout != tunConf.UDPTimeout || - LastTunConf.FileDescriptor != tunConf.FileDescriptor { - return true - } - - if len(LastTunConf.DNSHijack) != len(tunConf.DNSHijack) { - return true - } - - sort.Slice(tunConf.DNSHijack, func(i, j int) bool { - return tunConf.DNSHijack[i] < tunConf.DNSHijack[j] - }) - - sort.Slice(tunConf.RouteAddress, func(i, j int) bool { - return tunConf.RouteAddress[i].String() < tunConf.RouteAddress[j].String() - }) - - sort.Slice(tunConf.RouteAddressSet, func(i, j int) bool { - return tunConf.RouteAddressSet[i] < tunConf.RouteAddressSet[j] - }) - - sort.Slice(tunConf.RouteExcludeAddress, func(i, j int) bool { - return tunConf.RouteExcludeAddress[i].String() < tunConf.RouteExcludeAddress[j].String() - }) - - sort.Slice(tunConf.RouteExcludeAddressSet, func(i, j int) bool { - return tunConf.RouteExcludeAddressSet[i] < tunConf.RouteExcludeAddressSet[j] - }) - - sort.Slice(tunConf.Inet4Address, func(i, j int) bool { - return tunConf.Inet4Address[i].String() < tunConf.Inet4Address[j].String() - }) - - sort.Slice(tunConf.Inet6Address, func(i, j int) bool { - return tunConf.Inet6Address[i].String() < tunConf.Inet6Address[j].String() - }) - - sort.Slice(tunConf.Inet4RouteAddress, func(i, j int) bool { - return tunConf.Inet4RouteAddress[i].String() < tunConf.Inet4RouteAddress[j].String() - }) - - sort.Slice(tunConf.Inet6RouteAddress, func(i, j int) bool { - return tunConf.Inet6RouteAddress[i].String() < tunConf.Inet6RouteAddress[j].String() - }) - - sort.Slice(tunConf.Inet4RouteExcludeAddress, func(i, j int) bool { - return tunConf.Inet4RouteExcludeAddress[i].String() < tunConf.Inet4RouteExcludeAddress[j].String() - }) - - sort.Slice(tunConf.Inet6RouteExcludeAddress, func(i, j int) bool { - return tunConf.Inet6RouteExcludeAddress[i].String() < tunConf.Inet6RouteExcludeAddress[j].String() - }) - - sort.Slice(tunConf.IncludeInterface, func(i, j int) bool { - return tunConf.IncludeInterface[i] < tunConf.IncludeInterface[j] - }) - - sort.Slice(tunConf.ExcludeInterface, func(i, j int) bool { - return tunConf.ExcludeInterface[i] < tunConf.ExcludeInterface[j] - }) - - sort.Slice(tunConf.IncludeUID, func(i, j int) bool { - return tunConf.IncludeUID[i] < tunConf.IncludeUID[j] - }) - - sort.Slice(tunConf.IncludeUIDRange, func(i, j int) bool { - return tunConf.IncludeUIDRange[i] < tunConf.IncludeUIDRange[j] - }) - - sort.Slice(tunConf.ExcludeUID, func(i, j int) bool { - return tunConf.ExcludeUID[i] < tunConf.ExcludeUID[j] - }) - - sort.Slice(tunConf.ExcludeUIDRange, func(i, j int) bool { - return tunConf.ExcludeUIDRange[i] < tunConf.ExcludeUIDRange[j] - }) - - sort.Slice(tunConf.IncludeAndroidUser, func(i, j int) bool { - return tunConf.IncludeAndroidUser[i] < tunConf.IncludeAndroidUser[j] - }) - - sort.Slice(tunConf.IncludePackage, func(i, j int) bool { - return tunConf.IncludePackage[i] < tunConf.IncludePackage[j] - }) - - sort.Slice(tunConf.ExcludePackage, func(i, j int) bool { - return tunConf.ExcludePackage[i] < tunConf.ExcludePackage[j] - }) - - if !slices.Equal(tunConf.DNSHijack, LastTunConf.DNSHijack) || - !slices.Equal(tunConf.RouteAddress, LastTunConf.RouteAddress) || - !slices.Equal(tunConf.RouteAddressSet, LastTunConf.RouteAddressSet) || - !slices.Equal(tunConf.RouteExcludeAddress, LastTunConf.RouteExcludeAddress) || - !slices.Equal(tunConf.RouteExcludeAddressSet, LastTunConf.RouteExcludeAddressSet) || - !slices.Equal(tunConf.Inet4Address, LastTunConf.Inet4Address) || - !slices.Equal(tunConf.Inet6Address, LastTunConf.Inet6Address) || - !slices.Equal(tunConf.Inet4RouteAddress, LastTunConf.Inet4RouteAddress) || - !slices.Equal(tunConf.Inet6RouteAddress, LastTunConf.Inet6RouteAddress) || - !slices.Equal(tunConf.Inet4RouteExcludeAddress, LastTunConf.Inet4RouteExcludeAddress) || - !slices.Equal(tunConf.Inet6RouteExcludeAddress, LastTunConf.Inet6RouteExcludeAddress) || - !slices.Equal(tunConf.IncludeInterface, LastTunConf.IncludeInterface) || - !slices.Equal(tunConf.ExcludeInterface, LastTunConf.ExcludeInterface) || - !slices.Equal(tunConf.IncludeUID, LastTunConf.IncludeUID) || - !slices.Equal(tunConf.IncludeUIDRange, LastTunConf.IncludeUIDRange) || - !slices.Equal(tunConf.ExcludeUID, LastTunConf.ExcludeUID) || - !slices.Equal(tunConf.ExcludeUIDRange, LastTunConf.ExcludeUIDRange) || - !slices.Equal(tunConf.IncludeAndroidUser, LastTunConf.IncludeAndroidUser) || - !slices.Equal(tunConf.IncludePackage, LastTunConf.IncludePackage) || - !slices.Equal(tunConf.ExcludePackage, LastTunConf.ExcludePackage) { - return true - } - - return false -} - func closeTunListener() { if tunLister != nil { tunLister.Close() diff --git a/clash-meta/tunnel/tunnel.go b/clash-meta/tunnel/tunnel.go index 5dd468f3b4..b1b417bee2 100644 --- a/clash-meta/tunnel/tunnel.go +++ b/clash-meta/tunnel/tunnel.go @@ -225,6 +225,10 @@ func SetMode(m TunnelMode) { mode = m } +func FindProcessMode() P.FindProcessMode { + return findProcessMode +} + // SetFindProcessMode replace SetAlwaysFindProcess // always find process info if legacyAlways = true or mode.Always() = true, may be increase many memory func SetFindProcessMode(mode P.FindProcessMode) { diff --git a/clash-nyanpasu/.eslintrc.cjs b/clash-nyanpasu/.eslintrc.cjs index c17de7b28f..298d700767 100644 --- a/clash-nyanpasu/.eslintrc.cjs +++ b/clash-nyanpasu/.eslintrc.cjs @@ -21,7 +21,7 @@ module.exports = { "react/jsx-no-undef": "off", "react/react-in-jsx-scope": "off", "@typescript-eslint/no-namespace": "off", - "react-compiler/react-compiler": "error", + "react-compiler/react-compiler": "warn", // blocked by https://github.com/facebook/react/issues/30782 "react-hooks/rules-of-hooks": "error", "react-hooks/exhaustive-deps": "warn", "react/no-children-prop": "off", diff --git a/clash-nyanpasu/frontend/interface/src/ipc/useClashWS.ts b/clash-nyanpasu/frontend/interface/src/ipc/useClashWS.ts index d53a9d5988..4b8a2bc34e 100644 --- a/clash-nyanpasu/frontend/interface/src/ipc/useClashWS.ts +++ b/clash-nyanpasu/frontend/interface/src/ipc/useClashWS.ts @@ -1,21 +1,24 @@ import { useWebSocket } from "ahooks"; -import { useMemo } from "react"; +import { useCallback, useMemo } from "react"; import { useClash } from "./useClash"; export const useClashWS = () => { const { getClashInfo } = useClash(); - const getBaseUrl = () => { + const getBaseUrl = useCallback(() => { return `ws://${getClashInfo.data?.server}`; - }; + }, [getClashInfo.data?.server]); - const getTokenUrl = () => { + const getTokenUrl = useCallback(() => { return `token=${encodeURIComponent(getClashInfo.data?.secret || "")}`; - }; + }, [getClashInfo.data?.secret]); - const resolveUrl = (path: string) => { - return `${getBaseUrl()}/${path}?${getTokenUrl()}`; - }; + const resolveUrl = useCallback( + (path: string) => { + return `${getBaseUrl()}/${path}?${getTokenUrl()}`; + }, + [getBaseUrl, getTokenUrl], + ); const url = useMemo(() => { if (getClashInfo.data) { @@ -26,7 +29,7 @@ export const useClashWS = () => { memory: resolveUrl("memory"), }; } - }, [getClashInfo.data]); + }, [getClashInfo.data, resolveUrl]); const connections = useWebSocket(url?.connections ?? ""); diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/app/drawer-content.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/app/drawer-content.tsx index 7ebf460a4f..3b18b4af64 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/app/drawer-content.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/app/drawer-content.tsx @@ -17,7 +17,7 @@ export const DrawerContent = ({ className }: { className?: string }) => { const contentRef = useRef(null); - const size = useSize(contentRef.current); + const size = useSize(contentRef); const handleResize = useCallback( (value?: number) => { @@ -39,7 +39,7 @@ export const DrawerContent = ({ className }: { className?: string }) => { useEffect(() => { handleResize(size?.width); - }, [size?.width]); + }, [handleResize, size?.width]); return (
{ unlistenFn.current?.(); }; - }, []); + }, [mutate, t]); return null; } diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.tsx index 12d2b37e28..018bb76f30 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/layout/use-custom-theme.tsx @@ -92,7 +92,7 @@ export const ThemeModeProvider = () => { const chosenThemeMode = nyanpasuConfig?.theme_mode || "light"; setThemeMode(chosenThemeMode); setMode(chosenThemeMode); - }, [nyanpasuConfig?.theme_mode]); + }, [nyanpasuConfig?.theme_mode, setMode, setThemeMode]); return null; }; diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/logs/log-provider.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/logs/log-provider.tsx index 7936db3469..ae42dd16cd 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/logs/log-provider.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/logs/log-provider.tsx @@ -29,7 +29,7 @@ export const LogProvider = () => { return [...prev, { ...data, time }]; }); - }, [latestMessage?.data]); + }, [latestMessage?.data, setLogData]); return null; }; diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/profiles/profile-monaco-view.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/profiles/profile-monaco-view.tsx index 5759ba315f..d9d91d9702 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/profiles/profile-monaco-view.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/profiles/profile-monaco-view.tsx @@ -50,7 +50,7 @@ export const ProfileMonacoView = forwardRef(function ProfileMonacoView( return () => { instanceRef.current?.dispose(); }; - }, [open]); + }, [language, mode, open, value]); useImperativeHandle(ref, () => ({ getValue: () => instanceRef.current?.getValue(), diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-list.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-list.tsx index 37c9e8c90e..65ef2c3494 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-list.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/proxies/node-list.tsx @@ -8,7 +8,6 @@ import { useImperativeHandle, useRef, useState, - useTransition, } from "react"; import { Virtualizer, VListHandle } from "virtua"; import { proxyGroupAtom, proxyGroupSortAtom } from "@/store"; @@ -35,8 +34,6 @@ export const NodeList = forwardRef(function NodeList( getAllProxiesProviders, } = useClashCore(); - const [, startTransition] = useTransition(); - const { getCurrentMode } = useNyanpasu(); const [proxyGroup] = useAtom(proxyGroupAtom); @@ -84,7 +81,7 @@ export const NodeList = forwardRef(function NodeList( const [renderList, setRenderList] = useState([]); - const updateRenderList = () => { + useEffect(() => { if (!group?.all) return; const nodeNames: string[] = []; @@ -118,13 +115,7 @@ export const NodeList = forwardRef(function NodeList( ); setRenderList(list); - }; - - useEffect(() => { - startTransition(() => { - updateRenderList(); - }); - }, [group?.all, column, updateRenderList]); + }, [group?.all, column]); const hendleClick = (node: string) => { if (!getCurrentMode.global) { diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-dialog.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-dialog.tsx index 504f4b9c03..d5ca986250 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-dialog.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/modules/hotkey-dialog.tsx @@ -51,7 +51,7 @@ export default function HotkeyDialog({ setHotkeyMap(map); setDuplicateItems([]); } - }, [open]); + }, [nyanpasuConfig?.hotkeys, open]); const isDuplicated = useMemo(() => !!duplicateItems.length, [duplicateItems]); const onBlurCb = useMemoizedFn( @@ -99,7 +99,7 @@ export default function HotkeyDialog({ if (!isDuplicated && open) { saveState(); } - }, [hotkeyMap, isDuplicated, open]); + }, [hotkeyMap, isDuplicated, open, saveState]); const onSave = () => { saveState().then(() => { diff --git a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-port.tsx b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-port.tsx index 4273873e5c..4069e7d859 100644 --- a/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-port.tsx +++ b/clash-nyanpasu/frontend/nyanpasu/src/components/setting/setting-clash-port.tsx @@ -18,7 +18,7 @@ export const SettingClashPort = () => { nyanpasuConfig?.verge_mixed_port || 7890 ); - }, [getConfigs.data?.["mixed-port"], nyanpasuConfig?.verge_mixed_port]); + }, [getConfigs.data, nyanpasuConfig?.verge_mixed_port]); return ( diff --git a/clash-nyanpasu/frontend/ui/src/chart/sparkline.tsx b/clash-nyanpasu/frontend/ui/src/chart/sparkline.tsx index 8294c73371..4758fea9ca 100644 --- a/clash-nyanpasu/frontend/ui/src/chart/sparkline.tsx +++ b/clash-nyanpasu/frontend/ui/src/chart/sparkline.tsx @@ -106,7 +106,7 @@ export const Sparkline: FC = ({ data, className, style }) => { }; updateChart(); - }, [data]); + }, [data, palette.primary.main]); return ( { return () => { document.removeEventListener("click", updateMousePosition, true); }; - }, []); + }, [setMousePosition]); return mousePosition; }; diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/baseDialog/index.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/baseDialog/index.tsx index e637703a49..1d53b04b06 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/baseDialog/index.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/baseDialog/index.tsx @@ -4,6 +4,7 @@ import { AnimatePresence, motion } from "framer-motion"; import { CSSProperties, ReactNode, + useCallback, useEffect, useLayoutEffect, useState, @@ -77,15 +78,15 @@ export const BaseDialog = ({ } }, // not need clickPosition - [open], + [clickPosition?.x, clickPosition?.y, open], ); - const handleClose = () => { + const handleClose = useCallback(() => { if (onClose) { onClose(); runMounted(); } - }; + }, [onClose, runMounted]); const handleOk = useLockFn(async () => { if (!onOk) return; diff --git a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/numberItem.tsx b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/numberItem.tsx index 80ddbb4e86..b5fbc33b6a 100644 --- a/clash-nyanpasu/frontend/ui/src/materialYou/components/item/numberItem.tsx +++ b/clash-nyanpasu/frontend/ui/src/materialYou/components/item/numberItem.tsx @@ -54,7 +54,10 @@ export const NumberItem = ({ const [input, setInput] = useState(null); - const applyCheck = useMemo(() => checkEvent(input as number), [input]); + const applyCheck = useMemo( + () => checkEvent(input as number), + [checkEvent, input], + ); return ( <> diff --git a/clash-nyanpasu/manifest/version.json b/clash-nyanpasu/manifest/version.json index 1435af305b..379c675c31 100644 --- a/clash-nyanpasu/manifest/version.json +++ b/clash-nyanpasu/manifest/version.json @@ -2,7 +2,7 @@ "manifest_version": 1, "latest": { "mihomo": "v1.18.7", - "mihomo_alpha": "alpha-41efc5e", + "mihomo_alpha": "alpha-16c95fc", "clash_rs": "v0.2.0", "clash_premium": "2023-09-05-gdcc8d87" }, @@ -36,5 +36,5 @@ "darwin-x64": "clash-darwin-amd64-n{}.gz" } }, - "updated_at": "2024-08-22T22:20:28.984Z" + "updated_at": "2024-08-23T22:20:19.190Z" } diff --git a/clash-nyanpasu/package.json b/clash-nyanpasu/package.json index 4be5b05c3a..e4ee1959ee 100644 --- a/clash-nyanpasu/package.json +++ b/clash-nyanpasu/package.json @@ -51,17 +51,17 @@ "prepare:preview": "tsx scripts/prepare-preview.ts" }, "dependencies": { - "husky": "9.1.4", + "husky": "9.1.5", "lodash-es": "4.17.21" }, "devDependencies": { "@commitlint/cli": "19.4.0", "@commitlint/config-conventional": "19.2.2", "@ianvs/prettier-plugin-sort-imports": "4.3.1", - "@tauri-apps/cli": "1.6.0", + "@tauri-apps/cli": "1.6.1", "@types/fs-extra": "11.0.4", "@types/lodash-es": "4.17.12", - "@types/node": "20.16.1", + "@types/node": "22.5.0", "@typescript-eslint/eslint-plugin": "8.2.0", "@typescript-eslint/parser": "8.2.0", "autoprefixer": "10.4.20", @@ -74,13 +74,13 @@ "eslint-import-resolver-alias": "1.1.2", "eslint-plugin-html": "8.1.1", "eslint-plugin-import": "2.29.1", - "eslint-plugin-n": "16.6.2", + "eslint-plugin-n": "17.10.2", "eslint-plugin-prettier": "5.2.1", - "eslint-plugin-promise": "6.6.0", + "eslint-plugin-promise": "7.1.0", "eslint-plugin-react": "7.35.0", - "eslint-plugin-react-compiler": "0.0.0-experimental-eeb1b2a-20240818", + "eslint-plugin-react-compiler": "0.0.0-experimental-72f06b2-20240822", "eslint-plugin-react-hooks": "4.6.2", - "knip": "5.27.2", + "knip": "5.27.3", "lint-staged": "15.2.9", "npm-run-all2": "6.2.2", "postcss": "8.4.41", @@ -93,16 +93,16 @@ "react-devtools": "5.3.1", "stylelint": "16.8.2", "stylelint-config-html": "1.1.0", - "stylelint-config-recess-order": "5.0.1", + "stylelint-config-recess-order": "5.1.0", "stylelint-config-standard": "36.0.1", "stylelint-declaration-block-no-ignored-properties": "2.8.0", "stylelint-order": "6.0.4", "stylelint-scss": "6.5.0", "tailwindcss": "3.4.10", - "tsx": "4.17.0", + "tsx": "4.17.1", "typescript": "5.5.4" }, - "packageManager": "pnpm@9.7.1", + "packageManager": "pnpm@9.8.0", "engines": { "node": "22.6.0" }, diff --git a/clash-nyanpasu/pnpm-lock.yaml b/clash-nyanpasu/pnpm-lock.yaml index 131e49373d..0b2d7bef39 100644 --- a/clash-nyanpasu/pnpm-lock.yaml +++ b/clash-nyanpasu/pnpm-lock.yaml @@ -16,15 +16,15 @@ importers: .: dependencies: husky: - specifier: 9.1.4 - version: 9.1.4 + specifier: 9.1.5 + version: 9.1.5 lodash-es: specifier: 4.17.21 version: 4.17.21 devDependencies: '@commitlint/cli': specifier: 19.4.0 - version: 19.4.0(@types/node@20.16.1)(typescript@5.5.4) + version: 19.4.0(@types/node@22.5.0)(typescript@5.5.4) '@commitlint/config-conventional': specifier: 19.2.2 version: 19.2.2 @@ -32,8 +32,8 @@ importers: specifier: 4.3.1 version: 4.3.1(prettier@3.3.3) '@tauri-apps/cli': - specifier: 1.6.0 - version: 1.6.0 + specifier: 1.6.1 + version: 1.6.1 '@types/fs-extra': specifier: 11.0.4 version: 11.0.4 @@ -41,8 +41,8 @@ importers: specifier: 4.17.12 version: 4.17.12 '@types/node': - specifier: 20.16.1 - version: 20.16.1 + specifier: 22.5.0 + version: 22.5.0 '@typescript-eslint/eslint-plugin': specifier: 8.2.0 version: 8.2.0(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4) @@ -69,7 +69,7 @@ importers: version: 9.1.0(eslint@8.57.0) eslint-config-standard: specifier: 17.1.0 - version: 17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.6.0(eslint@8.57.0))(eslint@8.57.0) + version: 17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint-plugin-n@17.10.2(eslint@8.57.0))(eslint-plugin-promise@7.1.0(eslint@8.57.0))(eslint@8.57.0) eslint-import-resolver-alias: specifier: 1.1.2 version: 1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)) @@ -80,26 +80,26 @@ importers: specifier: 2.29.1 version: 2.29.1(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0) eslint-plugin-n: - specifier: 16.6.2 - version: 16.6.2(eslint@8.57.0) + specifier: 17.10.2 + version: 17.10.2(eslint@8.57.0) eslint-plugin-prettier: specifier: 5.2.1 version: 5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.3) eslint-plugin-promise: - specifier: 6.6.0 - version: 6.6.0(eslint@8.57.0) + specifier: 7.1.0 + version: 7.1.0(eslint@8.57.0) eslint-plugin-react: specifier: 7.35.0 version: 7.35.0(eslint@8.57.0) eslint-plugin-react-compiler: - specifier: 0.0.0-experimental-eeb1b2a-20240818 - version: 0.0.0-experimental-eeb1b2a-20240818(eslint@8.57.0) + specifier: 0.0.0-experimental-72f06b2-20240822 + version: 0.0.0-experimental-72f06b2-20240822(eslint@8.57.0) eslint-plugin-react-hooks: specifier: 4.6.2 version: 4.6.2(eslint@8.57.0) knip: - specifier: 5.27.2 - version: 5.27.2(@types/node@20.16.1)(typescript@5.5.4) + specifier: 5.27.3 + version: 5.27.3(@types/node@22.5.0)(typescript@5.5.4) lint-staged: specifier: 15.2.9 version: 15.2.9 @@ -137,8 +137,8 @@ importers: specifier: 1.1.0 version: 1.1.0(postcss-html@1.7.0)(stylelint@16.8.2(typescript@5.5.4)) stylelint-config-recess-order: - specifier: 5.0.1 - version: 5.0.1(stylelint@16.8.2(typescript@5.5.4)) + specifier: 5.1.0 + version: 5.1.0(stylelint@16.8.2(typescript@5.5.4)) stylelint-config-standard: specifier: 36.0.1 version: 36.0.1(stylelint@16.8.2(typescript@5.5.4)) @@ -155,8 +155,8 @@ importers: specifier: 3.4.10 version: 3.4.10 tsx: - specifier: 4.17.0 - version: 4.17.0 + specifier: 4.17.1 + version: 4.17.1 typescript: specifier: 5.5.4 version: 5.5.4 @@ -199,7 +199,7 @@ importers: version: 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@generouted/react-router': specifier: 1.19.6 - version: 1.19.6(react-router-dom@6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 1.19.6(react-router-dom@6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) '@juggle/resize-observer': specifier: 3.4.0 version: 3.4.0 @@ -208,7 +208,7 @@ importers: version: 0.3.0 '@mui/icons-material': specifier: 5.16.7 - version: 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) + version: 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@mui/lab': specifier: 5.0.0-alpha.173 version: 5.0.0-alpha.173(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) @@ -308,10 +308,10 @@ importers: version: types-react-dom@19.0.0-rc.1 '@vitejs/plugin-react': specifier: 4.3.1 - version: 4.3.1(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 4.3.1(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) '@vitejs/plugin-react-swc': specifier: 3.7.0 - version: 3.7.0(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 3.7.0(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) clsx: specifier: 2.1.1 version: 2.1.1 @@ -332,19 +332,19 @@ importers: version: 0.19.2(@svgr/core@8.1.0(typescript@5.5.4)) vite: specifier: 5.4.1 - version: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + version: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) vite-plugin-monaco-editor: specifier: npm:vite-plugin-monaco-editor-new@1.1.3 version: vite-plugin-monaco-editor-new@1.1.3(monaco-editor@0.50.0) vite-plugin-sass-dts: specifier: 1.3.25 - version: 1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) vite-plugin-svgr: specifier: 4.2.0 - version: 4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) vite-tsconfig-paths: specifier: 5.0.1 - version: 5.0.1(typescript@5.5.4)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 5.0.1(typescript@5.5.4)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) frontend/ui: dependencies: @@ -353,7 +353,7 @@ importers: version: 0.3.0 '@mui/icons-material': specifier: 5.16.7 - version: 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) + version: 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@mui/lab': specifier: 5.0.0-alpha.173 version: 5.0.0-alpha.173(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) @@ -377,7 +377,7 @@ importers: version: types-react@19.0.0-rc.1 '@vitejs/plugin-react': specifier: 4.3.1 - version: 4.3.1(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 4.3.1(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) ahooks: specifier: 3.8.1 version: 3.8.1(react@19.0.0-rc-e948a5ac-20240807) @@ -401,10 +401,10 @@ importers: version: 17.5.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807) vite: specifier: 5.4.1 - version: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + version: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) vite-tsconfig-paths: specifier: 5.0.1 - version: 5.0.1(typescript@5.5.4)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 5.0.1(typescript@5.5.4)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) devDependencies: '@emotion/react': specifier: 11.13.0 @@ -429,7 +429,7 @@ importers: version: 5.1.0(typescript@5.5.4) vite-plugin-dts: specifier: 4.0.3 - version: 4.0.3(@types/node@20.16.1)(rollup@4.17.2)(typescript@5.5.4)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + version: 4.0.3(@types/node@22.5.0)(rollup@4.17.2)(typescript@5.5.4)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) scripts: dependencies: @@ -1958,46 +1958,55 @@ packages: resolution: {integrity: sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.17.2': resolution: {integrity: sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.17.2': resolution: {integrity: sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.17.2': resolution: {integrity: sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-powerpc64le-gnu@4.17.2': resolution: {integrity: sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.17.2': resolution: {integrity: sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.17.2': resolution: {integrity: sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.17.2': resolution: {integrity: sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.17.2': resolution: {integrity: sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.17.2': resolution: {integrity: sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==} @@ -2139,24 +2148,28 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] '@swc/core-linux-arm64-musl@1.6.1': resolution: {integrity: sha512-dr6YbLBg/SsNxs1hDqJhxdcrS8dGMlOXJwXIrUvACiA8jAd6S5BxYCaqsCefLYXtaOmu0bbx1FB/evfodqB70Q==} engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] '@swc/core-linux-x64-gnu@1.6.1': resolution: {integrity: sha512-A0b/3V+yFy4LXh3O9umIE7LXPC7NBWdjl6AQYqymSMcMu0EOb1/iygA6s6uWhz9y3e172Hpb9b/CGsuD8Px/bg==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] '@swc/core-linux-x64-musl@1.6.1': resolution: {integrity: sha512-5dJjlzZXhC87nZZZWbpiDP8kBIO0ibis893F/rtPIQBI5poH+iJuA32EU3wN4/WFHeK4et8z6SGSVghPtWyk4g==} engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] '@swc/core-win32-arm64-msvc@1.6.1': resolution: {integrity: sha512-HBi1ZlwvfcUibLtT3g/lP57FaDPC799AD6InolB2KSgkqyBbZJ9wAXM8/CcH67GLIP0tZ7FqblrJTzGXxetTJQ==} @@ -2229,68 +2242,72 @@ packages: resolution: {integrity: sha512-rqI++FWClU5I2UBp4HXFvl+sBWkdigBkxnpJDQUWttNyG7IZP4FwQGhTNL5EOw0vI8i6eSAJ5frLqO7n7jbJdg==} engines: {node: '>= 14.6.0', npm: '>= 6.6.0', yarn: '>= 1.19.1'} - '@tauri-apps/cli-darwin-arm64@1.6.0': - resolution: {integrity: sha512-SNRwUD9nqGxY47mbY1CGTt/jqyQOU7Ps7Mx/mpgahL0FVUDiCEY/5L9QfEPPhEgccgcelEVn7i6aQHIkHyUtCA==} + '@tauri-apps/cli-darwin-arm64@1.6.1': + resolution: {integrity: sha512-n+16Z9qQksBmY55Xwful8GGrw2dlyeqKPsjuNcwKUgVB5a4gIq6K6uUsbhwMUMUA3gqewQMBn44QXbSe5qNKfA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@tauri-apps/cli-darwin-x64@1.6.0': - resolution: {integrity: sha512-g2/uDR/eeH2arvuawA4WwaEOqv/7jDO/ZLNI3JlBjP5Pk8GGb3Kdy0ro1xQzF94mtk2mOnOXa4dMgAet4sUJ1A==} + '@tauri-apps/cli-darwin-x64@1.6.1': + resolution: {integrity: sha512-OHzm6qiywv0GEwBDowlzLSuztKE85NMxp2loVynQ4vDoVk6V0jMtQy/N9YvYA0BetvfNTuuAiz3hsTkMHMYm+g==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@tauri-apps/cli-linux-arm-gnueabihf@1.6.0': - resolution: {integrity: sha512-EVwf4oRkQyG8BpSrk0gqO7oA0sDM2MdNDtJpMfleYFEgCxLIOGZKNqaOW3M7U+0Y4qikmG3TtRK+ngc8Ymtrjg==} + '@tauri-apps/cli-linux-arm-gnueabihf@1.6.1': + resolution: {integrity: sha512-ZA4ByaiZbrXUbhaoWUVab4lHI2yI1/ucrRO6b9pky6ytgqx37hA/YOWoctD0yaf5giQJQZw160euaBIUOKzRXA==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@tauri-apps/cli-linux-arm64-gnu@1.6.0': - resolution: {integrity: sha512-YdpY17cAySrhK9dX4BUVEmhAxE2o+6skIEFg8iN/xrDwRxhaNPI9I80YXPatUTX54Kx55T5++25VJG9+3iw83A==} + '@tauri-apps/cli-linux-arm64-gnu@1.6.1': + resolution: {integrity: sha512-VBU4GRJPU9jzzeqaEGLHAJzqQhpl7WnRFyHPR8Qby0D17av3CClJ7nBa+CI3ob3JbIERfJM9kwFHdY9eQpfxnw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] - '@tauri-apps/cli-linux-arm64-musl@1.6.0': - resolution: {integrity: sha512-4U628tuf2U8pMr4tIBJhEkrFwt+46dwhXrDlpdyWSZtnop5RJAVKHODm0KbWns4xGKfTW1F3r6sSv+2ZxLcISA==} + '@tauri-apps/cli-linux-arm64-musl@1.6.1': + resolution: {integrity: sha512-gyMgNZ8fwQFYzrIiHwhmKECkbuAZtzsRyl+bi1Ua11XVWYVUpY8+cNp7Y5ilMJ9AwNFI/HFKjzzua9r+e9FNzw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] - '@tauri-apps/cli-linux-x64-gnu@1.6.0': - resolution: {integrity: sha512-AKRzp76fVUaJyXj5KRJT9bJyhwZyUnRQU0RqIRqOtZCT5yr6qGP8rjtQ7YhCIzWrseBlOllc3Qvbgw3Yl0VQcA==} + '@tauri-apps/cli-linux-x64-gnu@1.6.1': + resolution: {integrity: sha512-aYLjLXEBcOf4GUrLBZRQcoLSL3KgCKHwfAyGmTilH4juAw42ZaAYWIZwa59hp2kC4w1XrlmwAzGpi1RESBr5Mw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] - '@tauri-apps/cli-linux-x64-musl@1.6.0': - resolution: {integrity: sha512-0edIdq6aMBTaRMIXddHfyAFL361JqulLLd2Wi2aoOie7DkQ2MYh6gv3hA7NB9gqFwNIGE+xtJ4BkXIP2tSGPlg==} + '@tauri-apps/cli-linux-x64-musl@1.6.1': + resolution: {integrity: sha512-j1M7ovICUrBDbrH8CNUwbMe0zk0/IAR7MXRv5PEanktAZ1w/LG3nlO/AhY5/Cbqqo3ziKTcMpe6x0j3aE8jYOA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] - '@tauri-apps/cli-win32-arm64-msvc@1.6.0': - resolution: {integrity: sha512-QwWpWk4ubcwJ1rljsRAmINgB2AwkyzZhpYbalA+MmzyYMREcdXWGkyixWbRZgqc6fEWEBmq5UG73qz5eBJiIKg==} + '@tauri-apps/cli-win32-arm64-msvc@1.6.1': + resolution: {integrity: sha512-yCGT1jXHvZtu+yYPDmDOJDfgsj5EKdBPvya+kmN03BmLfOF+8EWHA9s6yXUdk9pSr6M9OQS0SXocbGDOu5AkMw==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@tauri-apps/cli-win32-ia32-msvc@1.6.0': - resolution: {integrity: sha512-Vtw0yxO9+aEFuhuxQ57ALG43tjECopRimRuKGbtZYDCriB/ty5TrT3QWMdy0dxBkpDTu3Rqsz30sbDzw6tlP3Q==} + '@tauri-apps/cli-win32-ia32-msvc@1.6.1': + resolution: {integrity: sha512-klAt+KNcczC4gxz9vm6tSvFB4iyXVj4r+TtDVhStLCKkAZOVm0ZsFym1kDzltxrB/3xSjgzsgIiEJydN2cP7xw==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@tauri-apps/cli-win32-x64-msvc@1.6.0': - resolution: {integrity: sha512-h54FHOvGi7+LIfRchzgZYSCHB1HDlP599vWXQQJ/XnwJY+6Rwr2E5bOe/EhqoG8rbGkfK0xX3KPAvXPbUlmggg==} + '@tauri-apps/cli-win32-x64-msvc@1.6.1': + resolution: {integrity: sha512-WEzQzBgcaqjZoA5M/KOupHmt8W3QQ20vwETXpGEMPd7spj4eZsRv/2ZDuCz4ELbai1XlIsTITFNe2LlJjzqISA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@tauri-apps/cli@1.6.0': - resolution: {integrity: sha512-DBBpBl6GhTzm8ImMbKkfaZ4fDTykWrC7Q5OXP4XqD91recmDEn2LExuvuiiS3HYe7uP8Eb5B9NPHhqJb+Zo7qQ==} + '@tauri-apps/cli@1.6.1': + resolution: {integrity: sha512-2S8WGmkz54Z9WxpaFVbUYsTiwx5OIEmdD5DDWRygX9VhaWwZg0y6DctsUtCRVre9I/Un/hTnmqkhZqPamCEx8A==} engines: {node: '>= 10'} hasBin: true @@ -2477,11 +2494,8 @@ packages: '@types/node@16.18.97': resolution: {integrity: sha512-4muilE1Lbfn57unR+/nT9AFjWk0MtWi5muwCEJqnOvfRQDbSfLCUdN7vCIg8TYuaANfhLOV85ve+FNpiUsbSRg==} - '@types/node@20.12.10': - resolution: {integrity: sha512-Eem5pH9pmWBHoGAT8Dr5fdc5rYA+4NAovdM4EktRPVAAiJhmWWfQrA0cFhAbOsQdSfIHjAud6YdkbL69+zSKjw==} - - '@types/node@20.16.1': - resolution: {integrity: sha512-zJDo7wEadFtSyNz5QITDfRcrhqDvQI1xQNQ0VoizPjM/dVAODqqIUWbJPkvsxmTI0MYRGRikcdjMPhOssnPejQ==} + '@types/node@22.5.0': + resolution: {integrity: sha512-DkFrJOe+rfdHTqqMg0bSNlGlQ85hSoh2TPzZyhHsXnMtligRWpxUySiyw8FY14ITt24HVCiQPWxS3KO/QlGmWg==} '@types/parse-json@4.0.2': resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==} @@ -2875,13 +2889,6 @@ packages: resolution: {integrity: sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==} engines: {node: '>=6.14.2'} - builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - - builtins@5.1.0: - resolution: {integrity: sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==} - bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -3713,11 +3720,11 @@ packages: '@typescript-eslint/parser': optional: true - eslint-plugin-n@16.6.2: - resolution: {integrity: sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==} - engines: {node: '>=16.0.0'} + eslint-plugin-n@17.10.2: + resolution: {integrity: sha512-e+s4eAf5NtJaxPhTNu3qMO0Iz40WANS93w9LQgYcvuljgvDmWi/a3rh+OrNyMHeng6aOWGJO0rCg5lH4zi8yTw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: '>=7.0.0' + eslint: '>=8.23.0' eslint-plugin-prettier@5.2.1: resolution: {integrity: sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==} @@ -3733,14 +3740,14 @@ packages: eslint-config-prettier: optional: true - eslint-plugin-promise@6.6.0: - resolution: {integrity: sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-plugin-promise@7.1.0: + resolution: {integrity: sha512-8trNmPxdAy3W620WKDpaS65NlM5yAumod6XeC4LOb+jxlkG4IVcp68c6dXY2ev+uT4U1PtG57YDV6EGAXN0GbQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - eslint-plugin-react-compiler@0.0.0-experimental-eeb1b2a-20240818: - resolution: {integrity: sha512-ZQDW0fM4HraxdKztUv8Q5i4WNZ4m6Cf0vTdfyYKpNFYHIsEW0XgcRFiFyYpmm8cdXJHCQOB7j/IJJ0mCrIJ+cA==} + eslint-plugin-react-compiler@0.0.0-experimental-72f06b2-20240822: + resolution: {integrity: sha512-tmcPYVSeSCktvNgGNE/CKY5Gn29wMMSdHMb/IglSTWoddtDZ5YhAoGgiTAerKN+rmB0bBtjFSRjh1ZjmgH+mhQ==} engines: {node: ^14.17.0 || ^16.0.0 || >= 18.0.0} peerDependencies: eslint: '>=7' @@ -4006,9 +4013,6 @@ packages: resolution: {integrity: sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==} engines: {node: '>= 0.4'} - get-tsconfig@4.7.4: - resolution: {integrity: sha512-ofbkKj+0pjXjhejr007J/fLf+sW+8H7K5GCm+msC8q3IpvgjobpyPqSRFemNyIMxklC0zeJpi7VDFna19FacvQ==} - get-tsconfig@4.7.5: resolution: {integrity: sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==} @@ -4062,6 +4066,10 @@ packages: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} + globals@15.9.0: + resolution: {integrity: sha512-SmSKyLLKFbSr6rptvP8izbyxJL4ILwqO9Jg23UA0sDlGlu58V59D1//I3vlc0KJphVdUR7vMjHIplYnzBxorQA==} + engines: {node: '>=18'} + globalthis@1.0.4: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} @@ -4184,8 +4192,8 @@ packages: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} - husky@9.1.4: - resolution: {integrity: sha512-bho94YyReb4JV7LYWRWxZ/xr6TtOTt8cMfmQ39MQYJ7f/YE268s3GdghGwi+y4zAeqewE5zYLvuhV0M0ijsDEA==} + husky@9.1.5: + resolution: {integrity: sha512-rowAVRUBfI0b4+niA4SJMhfQwc107VLkBUgEYYAOQAbqDCnra1nYh83hF/MDmhYs9t9n1E3DuKOrs2LYNC+0Ag==} engines: {node: '>=18'} hasBin: true @@ -4329,10 +4337,6 @@ packages: resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} engines: {node: '>= 0.4'} - is-builtin-module@3.2.1: - resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} - engines: {node: '>=6'} - is-callable@1.2.7: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} @@ -4618,8 +4622,8 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - knip@5.27.2: - resolution: {integrity: sha512-Mya1XEDq1oygibQf0uocQd02Fil8RtvNVhcFAcxypjcc6zakT7wsJtS0xvuwEitilfI0tiFC9PghmJQ3DMKuTg==} + knip@5.27.3: + resolution: {integrity: sha512-X0zYs0viwENUtp+FZE2Ig6vQZYvKOz8TvuQkWSWMOXiEDoiMAF+NuDczVD9Dhupicfew0YKpYamHhKtNP+f8+g==} engines: {node: '>=18.6.0'} hasBin: true peerDependencies: @@ -6117,8 +6121,8 @@ packages: postcss-html: ^1.0.0 stylelint: '>=14.0.0' - stylelint-config-recess-order@5.0.1: - resolution: {integrity: sha512-rKbGkoa3h0rINrGln9TFVowvSCLgPJC5O0EuPiqlqWcJMb1lImEtXktcjFCVz+hwtSUiHD3ijJc3vP9muFOgJg==} + stylelint-config-recess-order@5.1.0: + resolution: {integrity: sha512-ddapCF6B/kEtQYIFhQFReQ0dvK1ZdgJDM/SGFtIyeooYDbqaJqcOlGkRRGaVErCQYJY/bPSPsLRS2LdQtLJUVQ==} peerDependencies: stylelint: '>=16' @@ -6330,8 +6334,8 @@ packages: tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - tsx@4.17.0: - resolution: {integrity: sha512-eN4mnDA5UMKDt4YZixo9tBioibaMBpoxBkD+rIPAjVmYERSG0/dWEY1CEFuV89CgASlKL499q8AhmkMnnjtOJg==} + tsx@4.17.1: + resolution: {integrity: sha512-s+poJ84lg23SPBvxQbPmyJd/tlpeBKbOnOYmhKO54L6CR/NyCF8Sw7dqLUWLuscDnKkD31h1qqX0A4FIa9ysaA==} engines: {node: '>=18.0.0'} hasBin: true @@ -6404,9 +6408,6 @@ packages: unbox-primitive@1.0.2: resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - undici-types@6.19.6: resolution: {integrity: sha512-e/vggGopEfTKSvj4ihnOLTsqhrKRN3LeO6qSN/GxohhuRv8qH9bNQ4B8W7e/vFL+0XTnmHPB4/kegunZGA4Org==} @@ -7123,11 +7124,11 @@ snapshots: '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 - '@commitlint/cli@19.4.0(@types/node@20.16.1)(typescript@5.5.4)': + '@commitlint/cli@19.4.0(@types/node@22.5.0)(typescript@5.5.4)': dependencies: '@commitlint/format': 19.3.0 '@commitlint/lint': 19.2.2 - '@commitlint/load': 19.4.0(@types/node@20.16.1)(typescript@5.5.4) + '@commitlint/load': 19.4.0(@types/node@22.5.0)(typescript@5.5.4) '@commitlint/read': 19.4.0 '@commitlint/types': 19.0.3 execa: 8.0.1 @@ -7174,7 +7175,7 @@ snapshots: '@commitlint/rules': 19.0.3 '@commitlint/types': 19.0.3 - '@commitlint/load@19.4.0(@types/node@20.16.1)(typescript@5.5.4)': + '@commitlint/load@19.4.0(@types/node@22.5.0)(typescript@5.5.4)': dependencies: '@commitlint/config-validator': 19.0.3 '@commitlint/execute-rule': 19.0.0 @@ -7182,7 +7183,7 @@ snapshots: '@commitlint/types': 19.0.3 chalk: 5.3.0 cosmiconfig: 9.0.0(typescript@5.5.4) - cosmiconfig-typescript-loader: 5.0.0(@types/node@20.16.1)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4) + cosmiconfig-typescript-loader: 5.0.0(@types/node@22.5.0)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -7628,13 +7629,13 @@ snapshots: postcss: 7.0.32 purgecss: 2.3.0 - '@generouted/react-router@1.19.6(react-router-dom@6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))': + '@generouted/react-router@1.19.6(react-router-dom@6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))': dependencies: fast-glob: 3.3.2 - generouted: 1.19.6(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) + generouted: 1.19.6(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)) react: 19.0.0-rc-e948a5ac-20240807 react-router-dom: 6.26.1(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807) - vite: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + vite: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) '@humanwhocodes/config-array@0.11.14': dependencies: @@ -7720,23 +7721,23 @@ snapshots: '@material/material-color-utilities@0.3.0': {} - '@microsoft/api-extractor-model@7.29.4(@types/node@20.16.1)': + '@microsoft/api-extractor-model@7.29.4(@types/node@22.5.0)': dependencies: '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.5.1(@types/node@20.16.1) + '@rushstack/node-core-library': 5.5.1(@types/node@22.5.0) transitivePeerDependencies: - '@types/node' - '@microsoft/api-extractor@7.47.4(@types/node@20.16.1)': + '@microsoft/api-extractor@7.47.4(@types/node@22.5.0)': dependencies: - '@microsoft/api-extractor-model': 7.29.4(@types/node@20.16.1) + '@microsoft/api-extractor-model': 7.29.4(@types/node@22.5.0) '@microsoft/tsdoc': 0.15.0 '@microsoft/tsdoc-config': 0.17.0 - '@rushstack/node-core-library': 5.5.1(@types/node@20.16.1) + '@rushstack/node-core-library': 5.5.1(@types/node@22.5.0) '@rushstack/rig-package': 0.5.3 - '@rushstack/terminal': 0.13.3(@types/node@20.16.1) - '@rushstack/ts-command-line': 4.22.3(@types/node@20.16.1) + '@rushstack/terminal': 0.13.3(@types/node@22.5.0) + '@rushstack/ts-command-line': 4.22.3(@types/node@22.5.0) lodash: 4.17.21 minimatch: 3.0.8 resolve: 1.22.8 @@ -7771,7 +7772,7 @@ snapshots: '@mui/core-downloads-tracker@5.16.7': {} - '@mui/icons-material@5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1)': + '@mui/icons-material@5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1)': dependencies: '@babel/runtime': 7.24.8 '@mui/material': 5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) @@ -8292,7 +8293,7 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.17.2': optional: true - '@rushstack/node-core-library@5.5.1(@types/node@20.16.1)': + '@rushstack/node-core-library@5.5.1(@types/node@22.5.0)': dependencies: ajv: 8.13.0 ajv-draft-04: 1.0.0(ajv@8.13.0) @@ -8303,23 +8304,23 @@ snapshots: resolve: 1.22.8 semver: 7.5.4 optionalDependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.0 '@rushstack/rig-package@0.5.3': dependencies: resolve: 1.22.8 strip-json-comments: 3.1.1 - '@rushstack/terminal@0.13.3(@types/node@20.16.1)': + '@rushstack/terminal@0.13.3(@types/node@22.5.0)': dependencies: - '@rushstack/node-core-library': 5.5.1(@types/node@20.16.1) + '@rushstack/node-core-library': 5.5.1(@types/node@22.5.0) supports-color: 8.1.1 optionalDependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.0 - '@rushstack/ts-command-line@4.22.3(@types/node@20.16.1)': + '@rushstack/ts-command-line@4.22.3(@types/node@22.5.0)': dependencies: - '@rushstack/terminal': 0.13.3(@types/node@20.16.1) + '@rushstack/terminal': 0.13.3(@types/node@22.5.0) '@types/argparse': 1.0.38 argparse: 1.0.10 string-argv: 0.3.2 @@ -8335,7 +8336,7 @@ snapshots: '@snyk/github-codeowners@1.1.0': dependencies: commander: 4.1.1 - ignore: 5.3.1 + ignore: 5.3.2 p-map: 4.0.0 '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.24.5)': @@ -8395,7 +8396,7 @@ snapshots: '@svgr/hast-util-to-babel-ast@8.0.0': dependencies: - '@babel/types': 7.24.5 + '@babel/types': 7.25.2 entities: 4.5.0 '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.5.4))': @@ -8492,48 +8493,48 @@ snapshots: '@tauri-apps/api@1.6.0': {} - '@tauri-apps/cli-darwin-arm64@1.6.0': + '@tauri-apps/cli-darwin-arm64@1.6.1': optional: true - '@tauri-apps/cli-darwin-x64@1.6.0': + '@tauri-apps/cli-darwin-x64@1.6.1': optional: true - '@tauri-apps/cli-linux-arm-gnueabihf@1.6.0': + '@tauri-apps/cli-linux-arm-gnueabihf@1.6.1': optional: true - '@tauri-apps/cli-linux-arm64-gnu@1.6.0': + '@tauri-apps/cli-linux-arm64-gnu@1.6.1': optional: true - '@tauri-apps/cli-linux-arm64-musl@1.6.0': + '@tauri-apps/cli-linux-arm64-musl@1.6.1': optional: true - '@tauri-apps/cli-linux-x64-gnu@1.6.0': + '@tauri-apps/cli-linux-x64-gnu@1.6.1': optional: true - '@tauri-apps/cli-linux-x64-musl@1.6.0': + '@tauri-apps/cli-linux-x64-musl@1.6.1': optional: true - '@tauri-apps/cli-win32-arm64-msvc@1.6.0': + '@tauri-apps/cli-win32-arm64-msvc@1.6.1': optional: true - '@tauri-apps/cli-win32-ia32-msvc@1.6.0': + '@tauri-apps/cli-win32-ia32-msvc@1.6.1': optional: true - '@tauri-apps/cli-win32-x64-msvc@1.6.0': + '@tauri-apps/cli-win32-x64-msvc@1.6.1': optional: true - '@tauri-apps/cli@1.6.0': + '@tauri-apps/cli@1.6.1': optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 1.6.0 - '@tauri-apps/cli-darwin-x64': 1.6.0 - '@tauri-apps/cli-linux-arm-gnueabihf': 1.6.0 - '@tauri-apps/cli-linux-arm64-gnu': 1.6.0 - '@tauri-apps/cli-linux-arm64-musl': 1.6.0 - '@tauri-apps/cli-linux-x64-gnu': 1.6.0 - '@tauri-apps/cli-linux-x64-musl': 1.6.0 - '@tauri-apps/cli-win32-arm64-msvc': 1.6.0 - '@tauri-apps/cli-win32-ia32-msvc': 1.6.0 - '@tauri-apps/cli-win32-x64-msvc': 1.6.0 + '@tauri-apps/cli-darwin-arm64': 1.6.1 + '@tauri-apps/cli-darwin-x64': 1.6.1 + '@tauri-apps/cli-linux-arm-gnueabihf': 1.6.1 + '@tauri-apps/cli-linux-arm64-gnu': 1.6.1 + '@tauri-apps/cli-linux-arm64-musl': 1.6.1 + '@tauri-apps/cli-linux-x64-gnu': 1.6.1 + '@tauri-apps/cli-linux-x64-musl': 1.6.1 + '@tauri-apps/cli-win32-arm64-msvc': 1.6.1 + '@tauri-apps/cli-win32-ia32-msvc': 1.6.1 + '@tauri-apps/cli-win32-x64-msvc': 1.6.1 '@trivago/prettier-plugin-sort-imports@4.3.0(prettier@3.3.3)': dependencies: @@ -8550,7 +8551,7 @@ snapshots: '@types/adm-zip@0.5.5': dependencies: - '@types/node': 20.12.10 + '@types/node': 22.5.0 '@types/argparse@1.0.38': {} @@ -8581,12 +8582,12 @@ snapshots: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 20.16.1 + '@types/node': 22.5.0 '@types/responselike': 1.0.3 '@types/conventional-commits-parser@5.0.0': dependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.0 '@types/d3-array@3.2.1': {} @@ -8722,7 +8723,7 @@ snapshots: '@types/fs-extra@11.0.4': dependencies: '@types/jsonfile': 6.1.4 - '@types/node': 20.16.1 + '@types/node': 22.5.0 '@types/geojson@7946.0.14': {} @@ -8738,11 +8739,11 @@ snapshots: '@types/jsonfile@6.1.4': dependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.0 '@types/keyv@3.1.4': dependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.0 '@types/lodash-es@4.17.12': dependencies: @@ -8758,11 +8759,7 @@ snapshots: '@types/node@16.18.97': {} - '@types/node@20.12.10': - dependencies: - undici-types: 5.26.5 - - '@types/node@20.16.1': + '@types/node@22.5.0': dependencies: undici-types: 6.19.6 @@ -8784,7 +8781,7 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.0 '@types/unist@2.0.10': {} @@ -8792,7 +8789,7 @@ snapshots: '@types/yauzl@2.10.3': dependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.0 optional: true '@typescript-eslint/eslint-plugin@8.2.0(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)(typescript@5.5.4)': @@ -8878,21 +8875,21 @@ snapshots: '@ungap/structured-clone@1.2.0': {} - '@vitejs/plugin-react-swc@3.7.0(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))': + '@vitejs/plugin-react-swc@3.7.0(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))': dependencies: '@swc/core': 1.6.1 - vite: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + vite: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) transitivePeerDependencies: - '@swc/helpers' - '@vitejs/plugin-react@4.3.1(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))': + '@vitejs/plugin-react@4.3.1(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0))': dependencies: '@babel/core': 7.24.5 '@babel/plugin-transform-react-jsx-self': 7.24.5(@babel/core@7.24.5) '@babel/plugin-transform-react-jsx-source': 7.24.1(@babel/core@7.24.5) '@types/babel__core': 7.20.5 react-refresh: 0.14.2 - vite: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + vite: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) transitivePeerDependencies: - supports-color @@ -9250,12 +9247,6 @@ snapshots: dependencies: node-gyp-build: 4.8.1 - builtin-modules@3.3.0: {} - - builtins@5.1.0: - dependencies: - semver: 7.6.1 - bytes@3.1.2: {} cacheable-lookup@5.0.4: {} @@ -9462,9 +9453,9 @@ snapshots: dependencies: toggle-selection: 1.0.6 - cosmiconfig-typescript-loader@5.0.0(@types/node@20.16.1)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4): + cosmiconfig-typescript-loader@5.0.0(@types/node@22.5.0)(cosmiconfig@9.0.0(typescript@5.5.4))(typescript@5.5.4): dependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.0 cosmiconfig: 9.0.0(typescript@5.5.4) jiti: 1.21.6 typescript: 5.5.4 @@ -10143,12 +10134,12 @@ snapshots: dependencies: eslint: 8.57.0 - eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint-plugin-n@16.6.2(eslint@8.57.0))(eslint-plugin-promise@6.6.0(eslint@8.57.0))(eslint@8.57.0): + eslint-config-standard@17.1.0(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0))(eslint-plugin-n@17.10.2(eslint@8.57.0))(eslint-plugin-promise@7.1.0(eslint@8.57.0))(eslint@8.57.0): dependencies: eslint: 8.57.0 eslint-plugin-import: 2.29.1(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0) - eslint-plugin-n: 16.6.2(eslint@8.57.0) - eslint-plugin-promise: 6.6.0(eslint@8.57.0) + eslint-plugin-n: 17.10.2(eslint@8.57.0) + eslint-plugin-promise: 7.1.0(eslint@8.57.0) eslint-import-resolver-alias@1.1.2(eslint-plugin-import@2.29.1(@typescript-eslint/parser@8.2.0(eslint@8.57.0)(typescript@5.5.4))(eslint@8.57.0)): dependencies: @@ -10210,20 +10201,17 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-n@16.6.2(eslint@8.57.0): + eslint-plugin-n@17.10.2(eslint@8.57.0): dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0) - builtins: 5.1.0 + enhanced-resolve: 5.17.1 eslint: 8.57.0 eslint-plugin-es-x: 7.6.0(eslint@8.57.0) - get-tsconfig: 4.7.4 - globals: 13.24.0 - ignore: 5.3.1 - is-builtin-module: 3.2.1 - is-core-module: 2.13.1 - minimatch: 3.1.2 - resolve: 1.22.8 - semver: 7.6.1 + get-tsconfig: 4.7.5 + globals: 15.9.0 + ignore: 5.3.2 + minimatch: 9.0.5 + semver: 7.6.3 eslint-plugin-prettier@5.2.1(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.3.3): dependencies: @@ -10234,11 +10222,11 @@ snapshots: optionalDependencies: eslint-config-prettier: 9.1.0(eslint@8.57.0) - eslint-plugin-promise@6.6.0(eslint@8.57.0): + eslint-plugin-promise@7.1.0(eslint@8.57.0): dependencies: eslint: 8.57.0 - eslint-plugin-react-compiler@0.0.0-experimental-eeb1b2a-20240818(eslint@8.57.0): + eslint-plugin-react-compiler@0.0.0-experimental-72f06b2-20240822(eslint@8.57.0): dependencies: '@babel/core': 7.24.5 '@babel/parser': 7.25.3 @@ -10548,9 +10536,9 @@ snapshots: functions-have-names@1.2.3: {} - generouted@1.19.6(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): + generouted@1.19.6(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): dependencies: - vite: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + vite: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) gensync@1.0.0-beta.2: {} @@ -10582,10 +10570,6 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.2.4 - get-tsconfig@4.7.4: - dependencies: - resolve-pkg-maps: 1.0.0 - get-tsconfig@4.7.5: dependencies: resolve-pkg-maps: 1.0.0 @@ -10655,6 +10639,8 @@ snapshots: dependencies: type-fest: 0.20.2 + globals@15.9.0: {} + globalthis@1.0.4: dependencies: define-properties: 1.2.1 @@ -10818,7 +10804,7 @@ snapshots: human-signals@5.0.0: {} - husky@9.1.4: {} + husky@9.1.5: {} hyphenate-style-name@1.1.0: {} @@ -10938,10 +10924,6 @@ snapshots: call-bind: 1.0.7 has-tostringtag: 1.0.2 - is-builtin-module@3.2.1: - dependencies: - builtin-modules: 3.3.0 - is-callable@1.2.7: {} is-ci@1.2.1: @@ -11167,11 +11149,11 @@ snapshots: kind-of@6.0.3: {} - knip@5.27.2(@types/node@20.16.1)(typescript@5.5.4): + knip@5.27.3(@types/node@22.5.0)(typescript@5.5.4): dependencies: '@nodelib/fs.walk': 1.2.8 '@snyk/github-codeowners': 1.1.0 - '@types/node': 20.16.1 + '@types/node': 22.5.0 easy-table: 1.2.0 enhanced-resolve: 5.17.1 fast-glob: 3.3.2 @@ -11348,7 +11330,7 @@ snapshots: dependencies: '@emotion/react': 11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@emotion/styled': 11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) - '@mui/icons-material': 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) + '@mui/icons-material': 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@mui/material': 5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@mui/x-date-pickers': 7.9.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(dayjs@1.11.12)(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@tanstack/match-sorter-utils': 8.15.1 @@ -12239,7 +12221,7 @@ snapshots: react: 19.0.0-rc-e948a5ac-20240807 react-hook-form: 7.52.1(react@19.0.0-rc-e948a5ac-20240807) optionalDependencies: - '@mui/icons-material': 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) + '@mui/icons-material': 5.16.7(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) '@mui/x-date-pickers': 7.9.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@mui/material@5.16.7(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(@emotion/styled@11.13.0(@emotion/react@11.13.0(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1))(dayjs@1.11.12)(react-dom@19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807))(react@19.0.0-rc-e948a5ac-20240807)(types-react@19.0.0-rc.1) react-hook-form@7.52.1(react@19.0.0-rc-e948a5ac-20240807): @@ -12779,7 +12761,7 @@ snapshots: postcss-html: 1.7.0 stylelint: 16.8.2(typescript@5.5.4) - stylelint-config-recess-order@5.0.1(stylelint@16.8.2(typescript@5.5.4)): + stylelint-config-recess-order@5.1.0(stylelint@16.8.2(typescript@5.5.4)): dependencies: stylelint: 16.8.2(typescript@5.5.4) stylelint-order: 6.0.4(stylelint@16.8.2(typescript@5.5.4)) @@ -13091,7 +13073,7 @@ snapshots: tslib@2.6.2: {} - tsx@4.17.0: + tsx@4.17.1: dependencies: esbuild: 0.23.0 get-tsconfig: 4.7.5 @@ -13193,8 +13175,6 @@ snapshots: has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - undici-types@5.26.5: {} - undici-types@6.19.6: {} undici@5.28.4: @@ -13376,9 +13356,9 @@ snapshots: react: 19.0.0-rc-e948a5ac-20240807 react-dom: 19.0.0-rc-e948a5ac-20240807(react@19.0.0-rc-e948a5ac-20240807) - vite-plugin-dts@4.0.3(@types/node@20.16.1)(rollup@4.17.2)(typescript@5.5.4)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): + vite-plugin-dts@4.0.3(@types/node@22.5.0)(rollup@4.17.2)(typescript@5.5.4)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): dependencies: - '@microsoft/api-extractor': 7.47.4(@types/node@20.16.1) + '@microsoft/api-extractor': 7.47.4(@types/node@22.5.0) '@rollup/pluginutils': 5.1.0(rollup@4.17.2) '@volar/typescript': 2.4.0 '@vue/language-core': 2.0.29(typescript@5.5.4) @@ -13390,7 +13370,7 @@ snapshots: typescript: 5.5.4 vue-tsc: 2.0.29(typescript@5.5.4) optionalDependencies: - vite: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + vite: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) transitivePeerDependencies: - '@types/node' - rollup @@ -13401,43 +13381,43 @@ snapshots: esbuild: 0.19.12 monaco-editor: 0.50.0 - vite-plugin-sass-dts@1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): + vite-plugin-sass-dts@1.3.25(postcss@8.4.41)(prettier@3.3.3)(sass@1.77.8)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): dependencies: postcss: 8.4.41 postcss-js: 4.0.1(postcss@8.4.41) prettier: 3.3.3 sass: 1.77.8 - vite: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + vite: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) - vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): + vite-plugin-svgr@4.2.0(rollup@4.17.2)(typescript@5.5.4)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): dependencies: '@rollup/pluginutils': 5.1.0(rollup@4.17.2) '@svgr/core': 8.1.0(typescript@5.5.4) '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.5.4)) - vite: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + vite: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) transitivePeerDependencies: - rollup - supports-color - typescript - vite-tsconfig-paths@5.0.1(typescript@5.5.4)(vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): + vite-tsconfig-paths@5.0.1(typescript@5.5.4)(vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0)): dependencies: debug: 4.3.6 globrex: 0.1.2 tsconfck: 3.0.3(typescript@5.5.4) optionalDependencies: - vite: 5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) + vite: 5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0) transitivePeerDependencies: - supports-color - typescript - vite@5.4.1(@types/node@20.16.1)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0): + vite@5.4.1(@types/node@22.5.0)(less@4.2.0)(sass@1.77.8)(stylus@0.62.0): dependencies: esbuild: 0.21.5 postcss: 8.4.41 rollup: 4.17.2 optionalDependencies: - '@types/node': 20.16.1 + '@types/node': 22.5.0 fsevents: 2.3.3 less: 4.2.0 sass: 1.77.8 diff --git a/echo/go.mod b/echo/go.mod index bc13027df3..d65d65f76e 100644 --- a/echo/go.mod +++ b/echo/go.mod @@ -12,19 +12,19 @@ require ( github.com/hashicorp/go-retryablehttp v0.7.7 github.com/juju/ratelimit v1.0.2 github.com/labstack/echo/v4 v4.12.0 - github.com/prometheus/client_golang v1.19.1 + github.com/prometheus/client_golang v1.20.0 github.com/prometheus/client_model v0.6.1 github.com/prometheus/common v0.55.0 - github.com/prometheus/node_exporter v1.8.1 - github.com/sagernet/sing v0.4.1 - github.com/sagernet/sing-box v1.9.3 + github.com/prometheus/node_exporter v1.8.2 + github.com/sagernet/sing v0.4.2 + github.com/sagernet/sing-box v1.9.4 github.com/stretchr/testify v1.9.0 - github.com/urfave/cli/v2 v2.27.2 - github.com/xtls/xray-core v1.8.16 + github.com/urfave/cli/v2 v2.27.4 + github.com/xtls/xray-core v1.8.23 go.uber.org/atomic v1.11.0 go.uber.org/zap v1.27.0 - golang.org/x/sync v0.7.0 - golang.org/x/time v0.5.0 + golang.org/x/sync v0.8.0 + golang.org/x/time v0.6.0 google.golang.org/grpc v1.65.0 gopkg.in/yaml.v3 v3.0.1 ) @@ -66,7 +66,7 @@ require ( github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973 // indirect github.com/josharian/native v1.1.0 // indirect github.com/jsimonetti/rtnetlink v1.4.2 // indirect - github.com/klauspost/compress v1.17.8 // indirect + github.com/klauspost/compress v1.17.9 // indirect github.com/klauspost/cpuid/v2 v2.2.7 // indirect github.com/labstack/gommon v0.4.2 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect @@ -89,33 +89,34 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus-community/go-runit v0.1.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect - github.com/quic-go/quic-go v0.45.0 // indirect - github.com/refraction-networking/utls v1.6.6 // indirect + github.com/quic-go/qpack v0.4.0 // indirect + github.com/quic-go/quic-go v0.45.1 // indirect + github.com/refraction-networking/utls v1.6.7 // indirect github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/safchain/ethtool v0.3.0 // indirect github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f // indirect github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect - github.com/sagernet/sing-dns v0.2.0 // indirect - github.com/sagernet/sing-shadowsocks v0.2.6 // indirect + github.com/sagernet/sing-dns v0.2.3 // indirect + github.com/sagernet/sing-shadowsocks v0.2.7 // indirect github.com/sagernet/sing-tun v0.3.2 // indirect - github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb // indirect + github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 // indirect github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e // indirect github.com/valyala/bytebufferpool v1.0.0 // indirect github.com/valyala/fasttemplate v1.2.2 // indirect github.com/vishvananda/netlink v1.2.1-beta.2.0.20230316163032-ced5aaba43e3 // indirect github.com/vishvananda/netns v0.0.4 // indirect github.com/xhit/go-str2duration/v2 v2.1.0 // indirect - github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 // indirect - github.com/xtls/reality v0.0.0-20240429224917-ecc4401070cc // indirect + github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect + github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d // indirect go.uber.org/mock v0.4.0 // indirect go.uber.org/multierr v1.11.0 // indirect go4.org/netipx v0.0.0-20231129151722-fdeea329fbba // indirect - golang.org/x/crypto v0.24.0 // indirect + golang.org/x/crypto v0.25.0 // indirect golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc // indirect golang.org/x/mod v0.18.0 // indirect - golang.org/x/net v0.26.0 // indirect - golang.org/x/sys v0.21.0 // indirect + golang.org/x/net v0.27.0 // indirect + golang.org/x/sys v0.22.0 // indirect golang.org/x/text v0.16.0 // indirect golang.org/x/tools v0.22.0 // indirect golang.zx2c4.com/wintun v0.0.0-20230126152724-0fa3db229ce2 // indirect diff --git a/echo/go.sum b/echo/go.sum index eefaef7d47..e85edcbcc4 100644 --- a/echo/go.sum +++ b/echo/go.sum @@ -143,8 +143,8 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/juju/ratelimit v1.0.2 h1:sRxmtRiajbvrcLQT7S+JbqU0ntsb9W2yhSdNN8tWfaI= github.com/juju/ratelimit v1.0.2/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.8 h1:YcnTYrq7MikUT7k0Yb5eceMmALQPYBW/Xltxn0NAMnU= -github.com/klauspost/compress v1.17.8/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= @@ -155,6 +155,8 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/labstack/echo/v4 v4.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0= github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM= github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0= @@ -215,16 +217,16 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/prometheus-community/go-runit v0.1.0 h1:uTWEj/Fn2RoLdfg/etSqwzgYNOYPrARx1BHUN052tGA= github.com/prometheus-community/go-runit v0.1.0/go.mod h1:AvJ9Jo3gAFu2lbM4+qfjdpq30FfiLDJZKbQ015u08IQ= github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI= +github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= -github.com/prometheus/node_exporter v1.8.1 h1:qYIN+ghn7kEggHe4pcIRp9oXkljU8ARWyEHBr286RPY= -github.com/prometheus/node_exporter v1.8.1/go.mod h1:rJMoAQMglUjAZ7nggHnRuwfJ0hKUVW6+Gv+IaMxh6js= +github.com/prometheus/node_exporter v1.8.2 h1:G8NryhgftPSXTnD+DuaNZTHDqmHF3zLWgPeG5RUtcHg= +github.com/prometheus/node_exporter v1.8.2/go.mod h1:rJMoAQMglUjAZ7nggHnRuwfJ0hKUVW6+Gv+IaMxh6js= github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= @@ -232,10 +234,10 @@ github.com/quic-go/qpack v0.4.0 h1:Cr9BXA1sQS2SmDUWjSofMPNKmvF6IiIfDRmgU0w1ZCo= github.com/quic-go/qpack v0.4.0/go.mod h1:UZVnYIfi5GRk+zI9UMaCPsmZ2xKJP7XBUvVyT1Knj9A= github.com/quic-go/qtls-go1-20 v0.4.1 h1:D33340mCNDAIKBqXuAvexTNMUByrYmFYVfKfDN5nfFs= github.com/quic-go/qtls-go1-20 v0.4.1/go.mod h1:X9Nh97ZL80Z+bX/gUXMbipO6OxdiDi58b/fMC9mAL+k= -github.com/quic-go/quic-go v0.45.0 h1:OHmkQGM37luZITyTSu6ff03HP/2IrwDX1ZFiNEhSFUE= -github.com/quic-go/quic-go v0.45.0/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= -github.com/refraction-networking/utls v1.6.6 h1:igFsYBUJPYM8Rno9xUuDoM5GQrVEqY4llzEXOkL43Ig= -github.com/refraction-networking/utls v1.6.6/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= +github.com/quic-go/quic-go v0.45.1 h1:tPfeYCk+uZHjmDRwHHQmvHRYL2t44ROTujLeFVBmjCA= +github.com/quic-go/quic-go v0.45.1/go.mod h1:1dLehS7TIR64+vxGR70GDcatWTOtMX2PUtnKsjbTurI= +github.com/refraction-networking/utls v1.6.7 h1:zVJ7sP1dJx/WtVuITug3qYUq034cDq9B2MR1K67ULZM= +github.com/refraction-networking/utls v1.6.7/go.mod h1:BC3O4vQzye5hqpmDTWUqi4P5DDhzJfkV1tdqtawQIH0= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3 h1:f/FNXud6gA3MNr8meMVVGxhp+QBTqY91tM8HjEuMjGg= github.com/riobard/go-bloom v0.0.0-20200614022211-cdc8013cb5b3/go.mod h1:HgjTstvQsPGkxUsCd2KWxErBblirPizecHcpD3ffK+s= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= @@ -249,20 +251,20 @@ github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0= github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk= github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM= -github.com/sagernet/quic-go v0.43.1-beta.2 h1:6YRCE9t1Q3UbNX1/dJGqpwFQbh6DXC6XBrQr2xp6hXY= -github.com/sagernet/quic-go v0.43.1-beta.2/go.mod h1:BkrQYeop7Jx3hN3TW8/76CXcdhYiNPyYEBL/BVJ1ifc= -github.com/sagernet/sing v0.4.1 h1:zVlpE+7k7AFoC2pv6ReqLf0PIHjihL/jsBl5k05PQFk= -github.com/sagernet/sing v0.4.1/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls= -github.com/sagernet/sing-box v1.9.3 h1:jXiAqQRzBeXCSLTTl0Z92OLs5GkVotsdiNRVATZWpoY= -github.com/sagernet/sing-box v1.9.3/go.mod h1:6Rx5nzbqIfN7HlUaHgO/IdkP7fDPPQ/U/TAC5asEjSM= -github.com/sagernet/sing-dns v0.2.0 h1:dka3weRX6+CrYO3v+hrTy2z68rCOCZXNBiNXpLZ6JNs= -github.com/sagernet/sing-dns v0.2.0/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg= -github.com/sagernet/sing-shadowsocks v0.2.6 h1:xr7ylAS/q1cQYS8oxKKajhuQcchd5VJJ4K4UZrrpp0s= -github.com/sagernet/sing-shadowsocks v0.2.6/go.mod h1:j2YZBIpWIuElPFL/5sJAj470bcn/3QQ5lxZUNKLDNAM= +github.com/sagernet/quic-go v0.46.0-beta.4 h1:k9f7VSKaM47AY6MPND0Qf1KRN7HwimPg9zdOFTXTiCk= +github.com/sagernet/quic-go v0.46.0-beta.4/go.mod h1:zJmVdJUNqEDXfubf4KtIOUHHerggjBduiGRLNzJspcM= +github.com/sagernet/sing v0.4.2 h1:jzGNJdZVRI0xlAfFugsIQUPvyB9SuWvbJK7zQCXc4QM= +github.com/sagernet/sing v0.4.2/go.mod h1:ieZHA/+Y9YZfXs2I3WtuwgyCZ6GPsIR7HdKb1SdEnls= +github.com/sagernet/sing-box v1.9.4 h1:Sf2JffjKvcG2a2+YWPOP0NiCOqpu2iPU12RkpZ0PhaM= +github.com/sagernet/sing-box v1.9.4/go.mod h1:DGX0xLYqlQa36DX1PTWJBh6EnChI1hUyzwoJUObhlW4= +github.com/sagernet/sing-dns v0.2.3 h1:YzeBUn2tR38F7HtvGEQ0kLRLmZWMEgi/+7wqa4Twb1k= +github.com/sagernet/sing-dns v0.2.3/go.mod h1:BJpJv6XLnrUbSyIntOT6DG9FW0f4fETmPAHvNjOprLg= +github.com/sagernet/sing-shadowsocks v0.2.7 h1:zaopR1tbHEw5Nk6FAkM05wCslV6ahVegEZaKMv9ipx8= +github.com/sagernet/sing-shadowsocks v0.2.7/go.mod h1:0rIKJZBR65Qi0zwdKezt4s57y/Tl1ofkaq6NlkzVuyE= github.com/sagernet/sing-tun v0.3.2 h1:z0bLUT/YXH9RrJS9DsIpB0Bb9afl2hVJOmHd0zA3HJY= github.com/sagernet/sing-tun v0.3.2/go.mod h1:DxLIyhjWU/HwGYoX0vNGg2c5QgTQIakphU1MuERR5tQ= -github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb h1:XfLJSPIOUX+osiMraVgIrMR27uMXnRJWGm1+GL8/63U= -github.com/seiflotfy/cuckoofilter v0.0.0-20220411075957-e3b120b3f5fb/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg= +github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771 h1:emzAzMZ1L9iaKCTxdy3Em8Wv4ChIAGnfiz18Cda70g4= +github.com/seiflotfy/cuckoofilter v0.0.0-20240715131351-a2f2c23f1771/go.mod h1:bR6DqgcAl1zTcOX8/pE2Qkj9XO00eCNqmKb7lXP8EAg= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/shurcooL/component v0.0.0-20170202220835-f88ec8f54cc4/go.mod h1:XhFIlyj5a1fBNx5aJTbKoIq0mNaPvOagO+HjB3EtxrY= github.com/shurcooL/events v0.0.0-20181021180414-410e4ca65f48/go.mod h1:5u70Mqkb5O5cxEA8nxTsgrgLehJeAw6Oc4Ab1c/P1HM= @@ -298,8 +300,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= -github.com/urfave/cli/v2 v2.27.2 h1:6e0H+AkS+zDckwPCUrZkKX38mRaau4nL2uipkJpbkcI= -github.com/urfave/cli/v2 v2.27.2/go.mod h1:g0+79LmHHATl7DAcHO99smiR/T7uGLw84w8Y42x+4eM= +github.com/urfave/cli/v2 v2.27.4 h1:o1owoI+02Eb+K107p27wEX9Bb8eqIoZCfLXloLUSWJ8= +github.com/urfave/cli/v2 v2.27.4/go.mod h1:m4QzxcD2qpra4z7WhzEGn74WZLViBnMpb1ToCAKdGRQ= github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e h1:5QefA066A1tF8gHIiADmOVOV5LS43gt3ONnlEl3xkwI= github.com/v2fly/ss-bloomring v0.0.0-20210312155135-28617310f63e/go.mod h1:5t19P9LBIrNamL6AcMQOncg/r10y3Pc01AbHeMhwlpU= github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= @@ -315,12 +317,12 @@ github.com/vishvananda/netns v0.0.4 h1:Oeaw1EM2JMxD51g9uhtC0D7erkIjgmj8+JZc26m1Y github.com/vishvananda/netns v0.0.4/go.mod h1:SpkAiCQRtJ6TvvxPnOSyH3BMl6unz3xZlaprSwhNNJM= github.com/xhit/go-str2duration/v2 v2.1.0 h1:lxklc02Drh6ynqX+DdPyp5pCKLUQpRT8bp8Ydu2Bstc= github.com/xhit/go-str2duration/v2 v2.1.0/go.mod h1:ohY8p+0f07DiV6Em5LKB0s2YpLtXVyJfNt1+BlmyAsU= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913 h1:+qGGcbkzsfDQNPPe9UDgpxAWQrhbbBXOYJFQDq/dtJw= -github.com/xrash/smetrics v0.0.0-20240312152122-5f08fbb34913/go.mod h1:4aEEwZQutDLsQv2Deui4iYQ6DWTxR14g6m8Wv88+Xqk= -github.com/xtls/reality v0.0.0-20240429224917-ecc4401070cc h1:0Nj8T1n7F7+v4vRVroaJIvY6R0vNABLfPH+lzPHRJvI= -github.com/xtls/reality v0.0.0-20240429224917-ecc4401070cc/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE= -github.com/xtls/xray-core v1.8.16 h1:PhbpdREAIvDS7xmxR6Sdpkx0h5ugmf6wIoWECWtJ0kE= -github.com/xtls/xray-core v1.8.16/go.mod h1:tjzDQQJpFORuhf7fBsiswiexLVEeJpAfMsD0NE5xV7M= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d h1:+B97uD9uHLgAAulhigmys4BVwZZypzK7gPN3WtpgRJg= +github.com/xtls/reality v0.0.0-20240712055506-48f0b2d5ed6d/go.mod h1:dm4y/1QwzjGaK17ofi0Vs6NpKAHegZky8qk6J2JJZAE= +github.com/xtls/xray-core v1.8.23 h1:A8Wr50ildMYLpaNu3EiK+Stg/tps6i0h7z5Hr4f9H2k= +github.com/xtls/xray-core v1.8.23/go.mod h1:0CwyMPNA5Cs+ukPXHbYQGgne/ug0PuXOSVqBu7zyXOc= go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -341,8 +343,8 @@ golang.org/x/build v0.0.0-20190111050920-041ab4dc3f9d/go.mod h1:OWs+y06UdEOHN4y+ golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI= -golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM= +golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= +golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc h1:O9NuF4s+E/PvMIy+9IUZB9znFwUIXEWSstNjek6VpVg= golang.org/x/exp v0.0.0-20240531132922-fd00a4e0eefc/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= @@ -360,8 +362,8 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190313220215-9f648a60d977/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= -golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= -golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/net v0.27.0 h1:5K3Njcw06/l2y9vpGCSdcxWOYHOUk3dVNGDXN+FvAys= +golang.org/x/net v0.27.0/go.mod h1:dDi0PyhWNoiUOrAS8uXv/vnScO4wnHQO4mj9fn/RytE= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -372,8 +374,8 @@ golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -388,8 +390,8 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -398,8 +400,8 @@ golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -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/time v0.6.0 h1:eTDhh4ZXt5Qf0augr54TN6suAUudPcawVZeIAPU7D4U= +golang.org/x/time v0.6.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030000716-a0a13e073c7b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/echo/internal/cli/config.go b/echo/internal/cli/config.go index f5b025bea5..8dacc750e8 100644 --- a/echo/internal/cli/config.go +++ b/echo/internal/cli/config.go @@ -38,8 +38,8 @@ func loadConfig() (cfg *config.Config, err error) { }, }, } - if TCPRemoteAddr != "" { - cfg.RelayConfigs[0].TCPRemotes = []string{TCPRemoteAddr} + if RemoteAddr != "" { + cfg.RelayConfigs[0].Remotes = []string{RemoteAddr} } if err := cfg.Adjust(); err != nil { return nil, err diff --git a/echo/internal/cli/flags.go b/echo/internal/cli/flags.go index b78a2b1820..51c425c438 100644 --- a/echo/internal/cli/flags.go +++ b/echo/internal/cli/flags.go @@ -9,7 +9,7 @@ import ( var ( LocalAddr string ListenType constant.RelayType - TCPRemoteAddr string + RemoteAddr string TransportType constant.RelayType ConfigPath string WebPort int @@ -40,7 +40,7 @@ var RootFlags = []cli.Flag{ Name: "r,remote", Usage: "转发地址,例如 0.0.0.0:5201,通过 ws 隧道转发时应为 ws://0.0.0.0:2443", EnvVars: []string{"EHCO_REMOTE_ADDR"}, - Destination: &TCPRemoteAddr, + Destination: &RemoteAddr, }, &cli.StringFlag{ Name: "tt,transport_type", diff --git a/echo/internal/conn/relay_conn.go b/echo/internal/conn/relay_conn.go index 74d1bd3594..6415ba5dc3 100644 --- a/echo/internal/conn/relay_conn.go +++ b/echo/internal/conn/relay_conn.go @@ -9,14 +9,22 @@ import ( "net" "time" - "github.com/Ehco1996/ehco/internal/constant" "github.com/Ehco1996/ehco/internal/lb" "github.com/Ehco1996/ehco/internal/metrics" + "github.com/Ehco1996/ehco/internal/relay/conf" "github.com/Ehco1996/ehco/pkg/buffer" "github.com/Ehco1996/ehco/pkg/bytes" "go.uber.org/zap" ) +const ( + shortHashLength = 7 +) + +var ( + ErrIdleTimeout = errors.New("connection closed due to idle timeout") +) + // RelayConn is the interface that represents a relay connection. // it contains two connections: clientConn and remoteConn // clientConn is the connection from the client to the relay server @@ -63,6 +71,7 @@ type relayConnImpl struct { HandshakeDuration time.Duration RelayLabel string `json:"relay_label"` ConnType string `json:"conn_type"` + Options *conf.Options } func WithRelayLabel(relayLabel string) RelayConnOption { @@ -95,18 +104,31 @@ func WithLogger(l *zap.SugaredLogger) RelayConnOption { } } +func WithRelayOptions(opts *conf.Options) RelayConnOption { + return func(rci *relayConnImpl) { + rci.Options = opts + } +} + func (rc *relayConnImpl) Transport() error { - defer rc.Close() // nolint: errcheck - cl := rc.l.Named(shortHashSHA256(rc.GetFlow())) - cl.Debugf("transport start, stats: %s", rc.Stats.String()) + defer func() { + err := rc.Close() + if err != nil { + rc.l.Errorf("error closing relay connection: %s", err.Error()) + } + }() + rc.l = rc.l.Named(shortHashSHA256(rc.GetFlow())) + rc.l.Debugf("transport start") c1 := newInnerConn(rc.clientConn, rc) + c1.l = rc.l.Named("client") c2 := newInnerConn(rc.remoteConn, rc) + c2.l = rc.l.Named("remote") rc.StartTime = time.Now().Local() err := copyConn(c1, c2) if err != nil { - cl.Errorf("transport error: %s", err.Error()) + rc.l.Errorf("transport error: %s", err.Error()) } - cl.Debugf("transport end, stats: %s", rc.Stats.String()) + rc.l.Debugf("transport end: stats: %s", rc.Stats.String()) rc.EndTime = time.Now().Local() return err } @@ -115,7 +137,7 @@ func (rc *relayConnImpl) Close() error { err1 := rc.clientConn.Close() err2 := rc.remoteConn.Close() rc.Closed = true - return combineErrorsAndMuteEOF(err1, err2) + return combineErrorsAndMuteIDLE(err1, err2) } // functions that for web ui @@ -142,11 +164,11 @@ func (rc *relayConnImpl) GetConnType() string { return rc.ConnType } -func combineErrorsAndMuteEOF(err1, err2 error) error { - if err1 == io.EOF { +func combineErrorsAndMuteIDLE(err1, err2 error) error { + if err1 == ErrIdleTimeout { err1 = nil } - if err2 == io.EOF { + if err2 == ErrIdleTimeout { return nil } if err1 != nil && err2 != nil { @@ -180,13 +202,14 @@ func (s *Stats) String() string { // note that innerConn is a wrapper around net.Conn to allow io.Copy to be used type innerConn struct { net.Conn - lastActive time.Time - rc *relayConnImpl + lastActive time.Time + rc *relayConnImpl + l *zap.SugaredLogger } func newInnerConn(conn net.Conn, rc *relayConnImpl) *innerConn { - return &innerConn{Conn: conn, rc: rc, lastActive: time.Now()} + return &innerConn{Conn: conn, rc: rc, lastActive: time.Now().Local()} } func (c *innerConn) recordStats(n int, isRead bool) { @@ -208,37 +231,35 @@ func (c *innerConn) recordStats(n int, isRead bool) { func (c *innerConn) Read(p []byte) (n int, err error) { for { - deadline := time.Now().Add(constant.ReadTimeOut) + deadline := time.Now().Add(c.rc.Options.ReadTimeout) if err := c.Conn.SetReadDeadline(deadline); err != nil { return 0, err } n, err = c.Conn.Read(p) if err == nil { c.recordStats(n, true) - c.lastActive = time.Now() - return + c.lastActive = time.Now().Local() + return n, err } else { if netErr, ok := err.(net.Error); ok && netErr.Timeout() { - if time.Since(c.lastActive) > constant.IdleTimeOut { - c.rc.l.Debugf("read idle,close remote: %s", c.rc.remote.Label) - return 0, io.EOF + since := time.Since(c.lastActive) + if since > c.rc.Options.IdleTimeout { + c.l.Debugf("Read idle, close remote: %s", c.rc.remote.Label) + return 0, ErrIdleTimeout } continue } - return n, err + return 0, err } } } func (c *innerConn) Write(p []byte) (n int, err error) { - if time.Since(c.lastActive) > constant.IdleTimeOut { - c.rc.l.Debugf("write idle,close remote: %s", c.rc.remote.Label) - return 0, io.EOF - } n, err = c.Conn.Write(p) - c.recordStats(n, false) // false for write operation - if err != nil { - c.lastActive = time.Now() + if err == nil { + c.recordStats(n, false) + now := time.Now().Local() + c.lastActive = now } return } @@ -265,28 +286,29 @@ func shortHashSHA256(input string) string { hasher := sha256.New() hasher.Write([]byte(input)) hash := hasher.Sum(nil) - return hex.EncodeToString(hash)[:7] + return hex.EncodeToString(hash)[:shortHashLength] } func copyConn(conn1, conn2 *innerConn) error { - buf := buffer.BufferPool.Get() - defer buffer.BufferPool.Put(buf) + buf1 := buffer.BufferPool.Get() + defer buffer.BufferPool.Put(buf1) + buf2 := buffer.BufferPool.Get() + defer buffer.BufferPool.Put(buf2) + errCH := make(chan error, 1) // copy conn1 to conn2,read from conn1 and write to conn2 go func() { - _, err := io.CopyBuffer(conn2, conn1, buf) + _, err := io.CopyBuffer(conn2, conn1, buf1) _ = conn2.CloseWrite() // all data is written to conn2 now, so close the write side of conn2 to send eof errCH <- err }() // reverse copy conn2 to conn1,read from conn2 and write to conn1 - buf2 := buffer.BufferPool.Get() - defer buffer.BufferPool.Put(buf2) _, err := io.CopyBuffer(conn1, conn2, buf2) _ = conn1.CloseWrite() err2 := <-errCH _ = conn1.CloseRead() _ = conn2.CloseRead() - return combineErrorsAndMuteEOF(err, err2) + return combineErrorsAndMuteIDLE(err, err2) } diff --git a/echo/internal/conn/relay_conn_test.go b/echo/internal/conn/relay_conn_test.go index c76b417c0d..22f3d683f7 100644 --- a/echo/internal/conn/relay_conn_test.go +++ b/echo/internal/conn/relay_conn_test.go @@ -8,18 +8,23 @@ import ( "time" "github.com/Ehco1996/ehco/internal/lb" + "github.com/Ehco1996/ehco/internal/relay/conf" "github.com/stretchr/testify/assert" ) func TestInnerConn_ReadWrite(t *testing.T) { testData := []byte("hello") + testOptions := conf.Options{ + IdleTimeout: time.Second, + ReadTimeout: time.Second, + } clientConn, serverConn := net.Pipe() clientConn.SetDeadline(time.Now().Add(1 * time.Second)) serverConn.SetDeadline(time.Now().Add(1 * time.Second)) defer clientConn.Close() defer serverConn.Close() - rc := relayConnImpl{Stats: &Stats{}, remote: &lb.Node{Label: "client"}} + rc := relayConnImpl{Stats: &Stats{}, remote: &lb.Node{Label: "client"}, Options: &testOptions} innerC := newInnerConn(clientConn, &rc) errChan := make(chan error, 1) go func() { @@ -94,8 +99,8 @@ func TestCopyTCPConn(t *testing.T) { remoteConn, err := net.Dial("tcp", echoServer.Addr().String()) assert.NoError(t, err) defer remoteConn.Close() - - rc := relayConnImpl{Stats: &Stats{}, remote: &lb.Node{Label: "client"}} + testOptions := conf.Options{IdleTimeout: time.Second, ReadTimeout: time.Second} + rc := relayConnImpl{Stats: &Stats{}, remote: &lb.Node{Label: "client"}, Options: &testOptions} c1 := newInnerConn(clientConn, &rc) c2 := newInnerConn(remoteConn, &rc) @@ -155,7 +160,8 @@ func TestCopyUDPConn(t *testing.T) { assert.NoError(t, err) defer remoteConn.Close() - rc := relayConnImpl{Stats: &Stats{}, remote: &lb.Node{Label: "client"}} + testOptions := conf.Options{IdleTimeout: time.Second, ReadTimeout: time.Second} + rc := relayConnImpl{Stats: &Stats{}, remote: &lb.Node{Label: "client"}, Options: &testOptions} c1 := newInnerConn(clientConn, &rc) c2 := newInnerConn(remoteConn, &rc) diff --git a/echo/internal/conn/udp_listener.go b/echo/internal/conn/udp_listener.go index 0385e0e340..e572d017a8 100644 --- a/echo/internal/conn/udp_listener.go +++ b/echo/internal/conn/udp_listener.go @@ -9,7 +9,7 @@ import ( "sync/atomic" "time" - "github.com/Ehco1996/ehco/internal/constant" + "github.com/Ehco1996/ehco/internal/relay/conf" "github.com/Ehco1996/ehco/pkg/buffer" ) @@ -33,7 +33,7 @@ func (c *uc) Read(b []byte) (int, error) { c.lastActivity.Store(time.Now()) return n, nil default: - if time.Since(c.lastActivity.Load().(time.Time)) > constant.IdleTimeOut { + if time.Since(c.lastActivity.Load().(time.Time)) > c.listener.cfg.Options.IdleTimeout { return 0, io.EOF } return 0, nil @@ -75,6 +75,7 @@ func (c *uc) SetWriteDeadline(t time.Time) error { } type UDPListener struct { + cfg *conf.Config listenAddr *net.UDPAddr listenConn *net.UDPConn @@ -90,8 +91,8 @@ type UDPListener struct { closed atomic.Bool } -func NewUDPListener(ctx context.Context, addr string) (*UDPListener, error) { - udpAddr, err := net.ResolveUDPAddr("udp", addr) +func NewUDPListener(ctx context.Context, cfg *conf.Config) (*UDPListener, error) { + udpAddr, err := net.ResolveUDPAddr("udp", cfg.Listen) if err != nil { return nil, err } @@ -104,6 +105,7 @@ func NewUDPListener(ctx context.Context, addr string) (*UDPListener, error) { ctx, cancel := context.WithCancel(ctx) l := &UDPListener{ + cfg: cfg, listenConn: conn, listenAddr: udpAddr, diff --git a/echo/internal/constant/constant.go b/echo/internal/constant/constant.go index 0b20503622..917113eafa 100644 --- a/echo/internal/constant/constant.go +++ b/echo/internal/constant/constant.go @@ -5,11 +5,6 @@ import "time" type RelayType string var ( - // allow change in test - // TODO Set to Relay Config - ReadTimeOut = 5 * time.Second - IdleTimeOut = 30 * time.Second - Version = "1.1.5-dev" GitBranch string GitRevision string @@ -18,9 +13,10 @@ var ( ) const ( - DialTimeOut = 3 * time.Second - - SniffTimeOut = 300 * time.Millisecond + DefaultDialTimeOut = 3 * time.Second + DefaultReadTimeOut = 5 * time.Second + DefaultIdleTimeOut = 10 * time.Second + DefaultSniffTimeOut = 300 * time.Millisecond // todo,support config in relay config BUFFER_POOL_SIZE = 1024 // support 512 connections diff --git a/echo/internal/metrics/ping.go b/echo/internal/metrics/ping.go index 9c9434742f..5a37ff6b2e 100644 --- a/echo/internal/metrics/ping.go +++ b/echo/internal/metrics/ping.go @@ -64,7 +64,7 @@ func NewPingGroup(cfg *config.Config) *PingGroup { // parse addr from rule for _, relayCfg := range cfg.RelayConfigs { // NOTE for (https/ws/wss)://xxx.com -> xxx.com - for _, remote := range relayCfg.TCPRemotes { + for _, remote := range relayCfg.Remotes { addr, err := extractHost(remote) if err != nil { pg.logger.Error("try parse host error", zap.Error(err)) diff --git a/echo/internal/relay/conf/cfg.go b/echo/internal/relay/conf/cfg.go index b04eb12bb1..b387bf396b 100644 --- a/echo/internal/relay/conf/cfg.go +++ b/echo/internal/relay/conf/cfg.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "net/url" + "time" "github.com/Ehco1996/ehco/internal/constant" "github.com/Ehco1996/ehco/internal/lb" @@ -31,13 +32,27 @@ func (w *WSConfig) Clone() *WSConfig { } type Options struct { - WSConfig *WSConfig `json:"ws_config,omitempty"` - EnableUDP bool `json:"enable_udp,omitempty"` - EnableMultipathTCP bool `json:"enable_multipath_tcp,omitempty"` + EnableUDP bool `json:"enable_udp,omitempty"` + EnableMultipathTCP bool `json:"enable_multipath_tcp,omitempty"` + // connection limit MaxConnection int `json:"max_connection,omitempty"` BlockedProtocols []string `json:"blocked_protocols,omitempty"` MaxReadRateKbps int64 `json:"max_read_rate_kbps,omitempty"` + + // ws related + WSConfig *WSConfig `json:"ws_config,omitempty"` + + DialTimeoutSec int `json:"dial_timeout_sec,omitempty"` + IdleTimeoutSec int `json:"idle_timeout_sec,omitempty"` + ReadTimeoutSec int `json:"read_timeout_sec,omitempty"` + SniffTimeoutSec int `json:"sniff_timeout_sec,omitempty"` + + // timeout in duration + DialTimeout time.Duration + IdleTimeout time.Duration + ReadTimeout time.Duration + SniffTimeout time.Duration } func (o *Options) Clone() *Options { @@ -60,9 +75,12 @@ type Config struct { Listen string `json:"listen"` ListenType constant.RelayType `json:"listen_type"` TransportType constant.RelayType `json:"transport_type"` - TCPRemotes []string `json:"tcp_remotes"` // TODO rename to remotes + Remotes []string `json:"remotes"` Options *Options `json:"options,omitempty"` + + // deprecated + TCPRemotes []string `json:"tcp_remotes"` } func (r *Config) GetWSHandShakePath() string { @@ -83,12 +101,29 @@ func (r *Config) GetWSRemoteAddr(baseAddr string) (string, error) { return addr, nil } -func (r *Config) GetTCPRemotes() string { - return fmt.Sprintf("%v", r.TCPRemotes) +func (r *Config) Adjust() error { + if r.Label == "" { + r.Label = r.DefaultLabel() + zap.S().Debugf("label is empty, set default label:%s", r.Label) + } + if len(r.Remotes) == 0 && len(r.TCPRemotes) != 0 { + zap.S().Warnf("tcp remotes is deprecated, use remotes instead") + r.Remotes = r.TCPRemotes + } + + if r.Options == nil { + r.Options = newDefaultOptions() + } else { + r.Options.DialTimeout = getDuration(r.Options.DialTimeoutSec, r.Options.DialTimeout) + r.Options.IdleTimeout = getDuration(r.Options.IdleTimeoutSec, r.Options.IdleTimeout) + r.Options.ReadTimeout = getDuration(r.Options.ReadTimeoutSec, r.Options.ReadTimeout) + r.Options.SniffTimeout = getDuration(r.Options.SniffTimeoutSec, r.Options.SniffTimeout) + } + return nil } func (r *Config) Validate() error { - if r.Adjust() != nil { + if err := r.Adjust(); err != nil { return errors.New("adjust config failed") } @@ -97,18 +132,18 @@ func (r *Config) Validate() error { } if r.Listen == "" { - return fmt.Errorf("invalid listen:%s", r.Listen) + return fmt.Errorf("invalid listen: %s", r.Listen) } - for _, addr := range r.TCPRemotes { + for _, addr := range r.Remotes { if addr == "" { - return fmt.Errorf("invalid tcp remote addr:%s", addr) + return fmt.Errorf("invalid remote addr: %s", addr) } } for _, protocol := range r.Options.BlockedProtocols { if protocol != ProtocolHTTP && protocol != ProtocolTLS { - return fmt.Errorf("invalid blocked protocol:%s", protocol) + return fmt.Errorf("invalid blocked protocol: %s", protocol) } } return nil @@ -122,8 +157,8 @@ func (r *Config) Clone() *Config { Label: r.Label, Options: r.Options.Clone(), } - new.TCPRemotes = make([]string, len(r.TCPRemotes)) - copy(new.TCPRemotes, r.TCPRemotes) + new.Remotes = make([]string, len(r.Remotes)) + copy(new.Remotes, r.Remotes) return new } @@ -134,11 +169,11 @@ func (r *Config) Different(new *Config) bool { r.Label != new.Label { return true } - if len(r.TCPRemotes) != len(new.TCPRemotes) { + if len(r.Remotes) != len(new.Remotes) { return true } - for i, addr := range r.TCPRemotes { - if addr != new.TCPRemotes[i] { + for i, addr := range r.Remotes { + if addr != new.Remotes[i] { return true } } @@ -147,28 +182,14 @@ func (r *Config) Different(new *Config) bool { // todo make this shorter and more readable func (r *Config) DefaultLabel() string { - defaultLabel := fmt.Sprintf("", - r.Listen, r.TCPRemotes, r.TransportType) + defaultLabel := fmt.Sprintf("", + r.Listen, r.Remotes, r.TransportType) return defaultLabel } -func (r *Config) Adjust() error { - if r.Label == "" { - r.Label = r.DefaultLabel() - zap.S().Debugf("label is empty, set default label:%s", r.Label) - } - if r.Options == nil { - r.Options = &Options{ - WSConfig: &WSConfig{}, - EnableMultipathTCP: true, // default enable multipath tcp - } - } - return nil -} - -func (r *Config) ToTCPRemotes() lb.RoundRobin { - tcpNodeList := make([]*lb.Node, len(r.TCPRemotes)) - for idx, addr := range r.TCPRemotes { +func (r *Config) ToRemotesLB() lb.RoundRobin { + tcpNodeList := make([]*lb.Node, len(r.Remotes)) + for idx, addr := range r.Remotes { tcpNodeList[idx] = &lb.Node{ Address: addr, Label: fmt.Sprintf("%s-%s", r.Label, addr), @@ -195,3 +216,21 @@ func (r *Config) validateType() error { } return nil } + +func getDuration(seconds int, defaultDuration time.Duration) time.Duration { + if seconds > 0 { + return time.Duration(seconds) * time.Second + } + return defaultDuration +} + +func newDefaultOptions() *Options { + return &Options{ + EnableMultipathTCP: true, + WSConfig: &WSConfig{}, + DialTimeout: constant.DefaultDialTimeOut, + IdleTimeout: constant.DefaultIdleTimeOut, + ReadTimeout: constant.DefaultReadTimeOut, + SniffTimeout: constant.DefaultSniffTimeOut, + } +} diff --git a/echo/internal/relay/relay.go b/echo/internal/relay/relay.go index 48eaeca957..c6e1a0fa3b 100644 --- a/echo/internal/relay/relay.go +++ b/echo/internal/relay/relay.go @@ -38,15 +38,12 @@ func NewRelay(cfg *conf.Config, cmgr cmgr.Cmgr) (*Relay, error) { func (r *Relay) ListenAndServe(ctx context.Context) error { errCh := make(chan error) go func() { - r.l.Infof("Start Relay Server(%s):%s", r.cfg.ListenType, r.cfg.DefaultLabel()) + r.l.Infof("Start Relay Server: %s", r.cfg.DefaultLabel()) errCh <- r.relayServer.ListenAndServe(ctx) }() return <-errCh } -func (r *Relay) Close() { - r.l.Infof("Close Relay Server:%s", r.cfg.DefaultLabel()) - if err := r.relayServer.Close(); err != nil { - r.l.Errorf(err.Error()) - } +func (r *Relay) Stop() error { + return r.relayServer.Close() } diff --git a/echo/internal/relay/server.go b/echo/internal/relay/server.go index 022be14ca0..799c2dab28 100644 --- a/echo/internal/relay/server.go +++ b/echo/internal/relay/server.go @@ -57,7 +57,7 @@ func (s *Server) startOneRelay(ctx context.Context, r *Relay) { } func (s *Server) stopOneRelay(r *Relay) { - r.Close() + _ = r.Stop() s.relayM.Delete(r.UniqueID()) } @@ -85,23 +85,20 @@ func (s *Server) Start(ctx context.Context) error { return err case <-ctx.Done(): s.l.Info("ctx cancelled start to stop all relay servers") - s.relayM.Range(func(key, value interface{}) bool { - r := value.(*Relay) - r.Close() - return true - }) - return nil + return s.Stop() } } func (s *Server) Stop() error { - s.l.Info("relay server stop now") + var err error s.relayM.Range(func(key, value interface{}) bool { r := value.(*Relay) - r.Close() + if e := r.Stop(); e != nil { + err = errors.Join(err, e) + } return true }) - return nil + return err } func (s *Server) TriggerReload() { diff --git a/echo/internal/transporter/base.go b/echo/internal/transporter/base.go index 84efdfa12b..268167f9cb 100644 --- a/echo/internal/transporter/base.go +++ b/echo/internal/transporter/base.go @@ -38,7 +38,7 @@ func newBaseRelayServer(cfg *conf.Config, cmgr cmgr.Cmgr) (*BaseRelayServer, err relayer: relayer, cfg: cfg, cmgr: cmgr, - remotes: cfg.ToTCPRemotes(), + remotes: cfg.ToRemotesLB(), l: zap.S().Named(cfg.GetLoggerName()), }, nil } @@ -98,10 +98,10 @@ func (b *BaseRelayServer) sniffAndBlockProtocol(c net.Conn) (net.Conn, error) { buffer := buf.NewPacket() - ctx, cancel := context.WithTimeout(context.Background(), constant.SniffTimeOut) + ctx, cancel := context.WithTimeout(context.Background(), b.cfg.Options.SniffTimeout) defer cancel() - sniffMetadata, err := sniff.PeekStream(ctx, c, buffer, constant.SniffTimeOut, sniff.TLSClientHello, sniff.HTTPHost) + sniffMetadata, err := sniff.PeekStream(ctx, c, buffer, b.cfg.Options.SniffTimeout, sniff.TLSClientHello, sniff.HTTPHost) if err != nil { b.l.Debugf("sniff error: %s", err) return c, nil @@ -137,6 +137,7 @@ func (b *BaseRelayServer) handleRelayConn(c, rc net.Conn, remote *lb.Node, connT conn.WithRemote(remote), conn.WithConnType(connType), conn.WithRelayLabel(b.cfg.Label), + conn.WithRelayOptions(b.cfg.Options), conn.WithHandshakeDuration(remote.HandShakeDuration), } relayConn := conn.NewRelayConn(c, rc, opts...) @@ -161,7 +162,7 @@ func (b *BaseRelayServer) ListenAndServe(ctx context.Context) error { } func NewNetDialer(cfg *conf.Config) *net.Dialer { - dialer := &net.Dialer{Timeout: constant.DialTimeOut} + dialer := &net.Dialer{Timeout: constant.DefaultDialTimeOut} dialer.SetMultipathTCP(cfg.Options.EnableMultipathTCP) return dialer } diff --git a/echo/internal/transporter/raw.go b/echo/internal/transporter/raw.go index 90531d263f..539a140d39 100644 --- a/echo/internal/transporter/raw.go +++ b/echo/internal/transporter/raw.go @@ -82,7 +82,7 @@ func (s *RawServer) ListenAndServe(ctx context.Context) error { s.tcpLis = ts if s.cfg.Options != nil && s.cfg.Options.EnableUDP { - udpLis, err := conn.NewUDPListener(ctx, s.cfg.Listen) + udpLis, err := conn.NewUDPListener(ctx, s.cfg) if err != nil { return err } @@ -107,10 +107,13 @@ func (s *RawServer) ListenAndServe(ctx context.Context) error { } func (s *RawServer) listenUDP(ctx context.Context) error { - s.l.Infof("Start UDP server at %s", s.cfg.Listen) for { c, err := s.udpLis.Accept() if err != nil { + // Check if the error is due to context cancellation + if errors.Is(err, context.Canceled) { + return nil // Return without logging the error + } s.l.Errorf("UDP accept error: %v", err) return err } diff --git a/echo/pkg/sub/clash.go b/echo/pkg/sub/clash.go index f22cac1718..3ea35dfa50 100644 --- a/echo/pkg/sub/clash.go +++ b/echo/pkg/sub/clash.go @@ -174,10 +174,10 @@ func (c *ClashSub) ToRelayConfigs(listenHost string) ([]*relay_cfg.Config, error // add other proxies address in group to relay config for _, proxy := range proxies[1:] { remote := net.JoinHostPort(proxy.rawServer, proxy.rawPort) - if strInArray(remote, rc.TCPRemotes) { + if strInArray(remote, rc.Remotes) { continue } - rc.TCPRemotes = append(rc.TCPRemotes, remote) + rc.Remotes = append(rc.Remotes, remote) if proxy.UDP { rc.Options = &relay_cfg.Options{ EnableUDP: true, diff --git a/echo/pkg/sub/clash_types.go b/echo/pkg/sub/clash_types.go index 543d521342..1761663758 100644 --- a/echo/pkg/sub/clash_types.go +++ b/echo/pkg/sub/clash_types.go @@ -136,7 +136,7 @@ func (p *Proxies) ToRelayConfig(listenHost string, listenPort string, newName st ListenType: constant.RelayTypeRaw, TransportType: constant.RelayTypeRaw, Listen: net.JoinHostPort(listenHost, listenPort), - TCPRemotes: []string{remoteAddr}, + Remotes: []string{remoteAddr}, } if p.UDP { r.Options = &relay_cfg.Options{ diff --git a/echo/test/relay_test.go b/echo/test/relay_test.go index 2bb57df705..487ba36e4b 100644 --- a/echo/test/relay_test.go +++ b/echo/test/relay_test.go @@ -40,11 +40,6 @@ const ( func TestMain(m *testing.M) { // Setup - - // change the idle timeout to 1 second to make connection close faster in test - constant.IdleTimeOut = time.Second - constant.ReadTimeOut = time.Second - _ = log.InitGlobalLogger("debug") _ = tls.InitTlsCfg() @@ -61,66 +56,67 @@ func TestMain(m *testing.M) { // Cleanup echoServer.Stop() for _, server := range relayServers { - server.Close() + server.Stop() } os.Exit(code) } func startRelayServers() []*relay.Relay { + options := conf.Options{ + EnableUDP: true, + IdleTimeoutSec: 1, + ReadTimeoutSec: 1, + } cfg := config.Config{ RelayConfigs: []*conf.Config{ // raw { + Label: "raw", Listen: RAW_LISTEN, ListenType: constant.RelayTypeRaw, - TCPRemotes: []string{ECHO_SERVER}, + Remotes: []string{ECHO_SERVER}, TransportType: constant.RelayTypeRaw, - Options: &conf.Options{ - EnableUDP: true, - }, + Options: &options, }, // ws { + Label: "ws-in", Listen: WS_LISTEN, ListenType: constant.RelayTypeRaw, - TCPRemotes: []string{WS_REMOTE}, + Remotes: []string{WS_REMOTE}, TransportType: constant.RelayTypeWS, - Options: &conf.Options{ - EnableUDP: true, - }, + Options: &options, }, { + Label: "ws-out", Listen: WS_SERVER, ListenType: constant.RelayTypeWS, - TCPRemotes: []string{ECHO_SERVER}, + Remotes: []string{ECHO_SERVER}, TransportType: constant.RelayTypeRaw, - Options: &conf.Options{ - EnableUDP: true, - }, + Options: &options, }, // wss { + Label: "wss-in", Listen: WSS_LISTEN, ListenType: constant.RelayTypeRaw, - TCPRemotes: []string{WSS_REMOTE}, + Remotes: []string{WSS_REMOTE}, TransportType: constant.RelayTypeWSS, - Options: &conf.Options{ - EnableUDP: true, - }, + Options: &options, }, { + Label: "wss-out", Listen: WSS_SERVER, ListenType: constant.RelayTypeWSS, - TCPRemotes: []string{ECHO_SERVER}, + Remotes: []string{ECHO_SERVER}, TransportType: constant.RelayTypeRaw, - Options: &conf.Options{ - EnableUDP: true, - }, + Options: &options, }, }, } + cfg.Adjust() var servers []*relay.Relay for _, c := range cfg.RelayConfigs { @@ -252,6 +248,6 @@ func testUDPRelay(t *testing.T, address string, concurrent bool, concurrency ... } func TestRelayIdleTimeout(t *testing.T) { - err := echo.EchoTcpMsgLong([]byte("hello"), time.Second, RAW_LISTEN) + err := echo.EchoTcpMsgLong([]byte("hello"), time.Second*2, RAW_LISTEN) require.Error(t, err, "Connection should be rejected") } diff --git a/mihomo/adapter/inbound/listen.go b/mihomo/adapter/inbound/listen.go index 18dc1bc242..1b86c811a7 100644 --- a/mihomo/adapter/inbound/listen.go +++ b/mihomo/adapter/inbound/listen.go @@ -17,10 +17,18 @@ func SetTfo(open bool) { lc.DisableTFO = !open } +func Tfo() bool { + return !lc.DisableTFO +} + func SetMPTCP(open bool) { setMultiPathTCP(&lc.ListenConfig, open) } +func MPTCP() bool { + return getMultiPathTCP(&lc.ListenConfig) +} + func ListenContext(ctx context.Context, network, address string) (net.Listener, error) { return lc.Listen(ctx, network, address) } diff --git a/mihomo/adapter/inbound/mptcp_go120.go b/mihomo/adapter/inbound/mptcp_go120.go index f9b22533d2..faae6ec5d8 100644 --- a/mihomo/adapter/inbound/mptcp_go120.go +++ b/mihomo/adapter/inbound/mptcp_go120.go @@ -8,3 +8,7 @@ const multipathTCPAvailable = false func setMultiPathTCP(listenConfig *net.ListenConfig, open bool) { } + +func getMultiPathTCP(listenConfig *net.ListenConfig) bool { + return false +} diff --git a/mihomo/adapter/inbound/mptcp_go121.go b/mihomo/adapter/inbound/mptcp_go121.go index 6b35d1a83a..9163878a70 100644 --- a/mihomo/adapter/inbound/mptcp_go121.go +++ b/mihomo/adapter/inbound/mptcp_go121.go @@ -9,3 +9,7 @@ const multipathTCPAvailable = true func setMultiPathTCP(listenConfig *net.ListenConfig, open bool) { listenConfig.SetMultipathTCP(open) } + +func getMultiPathTCP(listenConfig *net.ListenConfig) bool { + return listenConfig.MultipathTCP() +} diff --git a/mihomo/common/nnip/netip.go b/mihomo/common/nnip/netip.go index e456613888..b987bb457f 100644 --- a/mihomo/common/nnip/netip.go +++ b/mihomo/common/nnip/netip.go @@ -51,3 +51,23 @@ func UnMasked(p netip.Prefix) netip.Addr { } return addr } + +// PrefixCompare returns an integer comparing two prefixes. +// The result will be 0 if p == p2, -1 if p < p2, and +1 if p > p2. +// modify from https://github.com/golang/go/issues/61642#issuecomment-1848587909 +func PrefixCompare(p, p2 netip.Prefix) int { + // compare by validity, address family and prefix base address + if c := p.Masked().Addr().Compare(p2.Masked().Addr()); c != 0 { + return c + } + // compare by prefix length + f1, f2 := p.Bits(), p2.Bits() + if f1 < f2 { + return -1 + } + if f1 > f2 { + return 1 + } + // compare by prefix address + return p.Addr().Compare(p2.Addr()) +} diff --git a/mihomo/config/config.go b/mihomo/config/config.go index 788f227b85..f1ffbce1fd 100644 --- a/mihomo/config/config.go +++ b/mihomo/config/config.go @@ -50,13 +50,12 @@ import ( // General config type General struct { Inbound - Controller - Mode T.TunnelMode `json:"mode"` - UnifiedDelay bool + Mode T.TunnelMode `json:"mode"` + UnifiedDelay bool `json:"unified-delay"` LogLevel log.LogLevel `json:"log-level"` IPv6 bool `json:"ipv6"` Interface string `json:"interface-name"` - RoutingMark int `json:"-"` + RoutingMark int `json:"routing-mark"` GeoXUrl GeoXUrl `json:"geox-url"` GeoAutoUpdate bool `json:"geo-auto-update"` GeoUpdateInterval int `json:"geo-update-interval"` @@ -91,24 +90,48 @@ type Inbound struct { InboundMPTCP bool `json:"inbound-mptcp"` } +// GeoXUrl config +type GeoXUrl struct { + GeoIp string `json:"geo-ip"` + Mmdb string `json:"mmdb"` + ASN string `json:"asn"` + GeoSite string `json:"geo-site"` +} + // Controller config type Controller struct { - ExternalController string `json:"-"` - ExternalControllerTLS string `json:"-"` - ExternalControllerUnix string `json:"-"` - ExternalUI string `json:"-"` - ExternalDohServer string `json:"-"` - Secret string `json:"-"` + ExternalController string + ExternalControllerTLS string + ExternalControllerUnix string + ExternalUI string + ExternalDohServer string + Secret string +} + +// Experimental config +type Experimental struct { + Fingerprints []string + QUICGoDisableGSO bool + QUICGoDisableECN bool + IP4PEnable bool +} + +// IPTables config +type IPTables struct { + Enable bool + InboundInterface string + Bypass []string + DnsRedirect bool } // NTP config type NTP struct { - Enable bool `yaml:"enable"` - Server string `yaml:"server"` - Port int `yaml:"port"` - Interval int `yaml:"interval"` - DialerProxy string `yaml:"dialer-proxy"` - WriteToSystem bool `yaml:"write-to-system"` + Enable bool + Server string + Port int + Interval int + DialerProxy string + WriteToSystem bool } // DNS config @@ -134,24 +157,11 @@ type DNS struct { // Profile config type Profile struct { - StoreSelected bool `yaml:"store-selected"` - StoreFakeIP bool `yaml:"store-fake-ip"` -} - -type TLS struct { - Certificate string `yaml:"certificate"` - PrivateKey string `yaml:"private-key"` - CustomTrustCert []string `yaml:"custom-certifactes"` -} - -// IPTables config -type IPTables struct { - Enable bool `yaml:"enable" json:"enable"` - InboundInterface string `yaml:"inbound-interface" json:"inbound-interface"` - Bypass []string `yaml:"bypass" json:"bypass"` - DnsRedirect bool `yaml:"dns-redirect" json:"dns-redirect"` + StoreSelected bool + StoreFakeIP bool } +// Sniffer config type Sniffer struct { Enable bool Sniffers map[snifferTypes.Type]SNIFF.SnifferConfig @@ -161,21 +171,21 @@ type Sniffer struct { ParsePureIp bool } -// Experimental config -type Experimental struct { - Fingerprints []string `yaml:"fingerprints"` - QUICGoDisableGSO bool `yaml:"quic-go-disable-gso"` - QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"` - IP4PEnable bool `yaml:"dialer-ip4p-convert"` +// TLS config +type TLS struct { + Certificate string + PrivateKey string + CustomTrustCert []string } // Config is mihomo config manager type Config struct { General *General + Controller *Controller + Experimental *Experimental IPTables *IPTables NTP *NTP DNS *DNS - Experimental *Experimental Hosts *trie.DomainTrie[resolver.HostValue] Profile *Profile Rules []C.Rule @@ -190,15 +200,6 @@ type Config struct { TLS *TLS } -type RawNTP struct { - Enable bool `yaml:"enable"` - Server string `yaml:"server"` - ServerPort int `yaml:"server-port"` - Interval int `yaml:"interval"` - DialerProxy string `yaml:"dialer-proxy"` - WriteToSystem bool `yaml:"write-to-system"` -} - type RawDNS struct { Enable bool `yaml:"enable" json:"enable"` PreferH3 bool `yaml:"prefer-h3" json:"prefer-h3"` @@ -233,6 +234,15 @@ type RawClashForAndroid struct { UiSubtitlePattern string `yaml:"ui-subtitle-pattern" json:"ui-subtitle-pattern"` } +type RawNTP struct { + Enable bool `yaml:"enable" json:"enable"` + Server string `yaml:"server" json:"server"` + Port int `yaml:"port" json:"port"` + Interval int `yaml:"interval" json:"interval"` + DialerProxy string `yaml:"dialer-proxy" json:"dialer-proxy"` + WriteToSystem bool `yaml:"write-to-system" json:"write-to-system"` +} + type RawTun struct { Enable bool `yaml:"enable" json:"enable"` Device string `yaml:"device" json:"device"` @@ -244,35 +254,35 @@ type RawTun struct { MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` GSO bool `yaml:"gso" json:"gso,omitempty"` GSOMaxSize uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` - //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4_address,omitempty"` - Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6_address,omitempty"` - IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2_table_index,omitempty"` - IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2_rule_index,omitempty"` - AutoRedirect bool `yaml:"auto-redirect" json:"auto_redirect,omitempty"` - AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto_redirect_input_mark,omitempty"` - AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto_redirect_output_mark,omitempty"` - StrictRoute bool `yaml:"strict-route" json:"strict_route,omitempty"` - RouteAddress []netip.Prefix `yaml:"route-address" json:"route_address,omitempty"` - RouteAddressSet []string `yaml:"route-address-set" json:"route_address_set,omitempty"` - RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route_exclude_address,omitempty"` - RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route_exclude_address_set,omitempty"` + //Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` + Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` + IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2-table-index,omitempty"` + IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2-rule-index,omitempty"` + AutoRedirect bool `yaml:"auto-redirect" json:"auto-redirect,omitempty"` + AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto-redirect-input-mark,omitempty"` + AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto-redirect-output-mark,omitempty"` + StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` + RouteAddress []netip.Prefix `yaml:"route-address" json:"route-address,omitempty"` + RouteAddressSet []string `yaml:"route-address-set" json:"route-address-set,omitempty"` + RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route-exclude-address,omitempty"` + RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route-exclude-address-set,omitempty"` IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` - IncludeUID []uint32 `yaml:"include-uid" json:"include_uid,omitempty"` - IncludeUIDRange []string `yaml:"include-uid-range" json:"include_uid_range,omitempty"` - ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude_uid,omitempty"` - ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `yaml:"include-android-user" json:"include_android_user,omitempty"` - IncludePackage []string `yaml:"include-package" json:"include_package,omitempty"` - ExcludePackage []string `yaml:"exclude-package" json:"exclude_package,omitempty"` - EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `yaml:"udp-timeout" json:"udp_timeout,omitempty"` + IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` + IncludeUIDRange []string `yaml:"include-uid-range" json:"include-uid-range,omitempty"` + ExcludeUID []uint32 `yaml:"exclude-uid" json:"exclude-uid,omitempty"` + ExcludeUIDRange []string `yaml:"exclude-uid-range" json:"exclude-uid-range,omitempty"` + IncludeAndroidUser []int `yaml:"include-android-user" json:"include-android-user,omitempty"` + IncludePackage []string `yaml:"include-package" json:"include-package,omitempty"` + ExcludePackage []string `yaml:"exclude-package" json:"exclude-package,omitempty"` + EndpointIndependentNat bool `yaml:"endpoint-independent-nat" json:"endpoint-independent-nat,omitempty"` + UDPTimeout int64 `yaml:"udp-timeout" json:"udp-timeout,omitempty"` FileDescriptor int `yaml:"file-descriptor" json:"file-descriptor"` - Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4_route_address,omitempty"` - Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6_route_address,omitempty"` - Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4_route_exclude_address,omitempty"` - Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6_route_exclude_address,omitempty"` + Inet4RouteAddress []netip.Prefix `yaml:"inet4-route-address" json:"inet4-route-address,omitempty"` + Inet6RouteAddress []netip.Prefix `yaml:"inet6-route-address" json:"inet6-route-address,omitempty"` + Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` + Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` } type RawTuicServer struct { @@ -290,73 +300,26 @@ type RawTuicServer struct { CWND int `yaml:"cwnd" json:"cwnd,omitempty"` } -type RawConfig struct { - Port int `yaml:"port" json:"port"` - SocksPort int `yaml:"socks-port" json:"socks-port"` - RedirPort int `yaml:"redir-port" json:"redir-port"` - TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"` - MixedPort int `yaml:"mixed-port" json:"mixed-port"` - ShadowSocksConfig string `yaml:"ss-config"` - VmessConfig string `yaml:"vmess-config"` - InboundTfo bool `yaml:"inbound-tfo"` - InboundMPTCP bool `yaml:"inbound-mptcp"` - Authentication []string `yaml:"authentication" json:"authentication"` - SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes"` - LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips"` - LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips"` - AllowLan bool `yaml:"allow-lan" json:"allow-lan"` - BindAddress string `yaml:"bind-address" json:"bind-address"` - Mode T.TunnelMode `yaml:"mode" json:"mode"` - UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"` - LogLevel log.LogLevel `yaml:"log-level" json:"log-level"` - IPv6 bool `yaml:"ipv6" json:"ipv6"` - ExternalController string `yaml:"external-controller"` - ExternalControllerUnix string `yaml:"external-controller-unix"` - ExternalControllerTLS string `yaml:"external-controller-tls"` - ExternalUI string `yaml:"external-ui"` - ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"` - ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"` - ExternalDohServer string `yaml:"external-doh-server"` - Secret string `yaml:"secret"` - Interface string `yaml:"interface-name"` - RoutingMark int `yaml:"routing-mark"` - Tunnels []LC.Tunnel `yaml:"tunnels"` - GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"` - GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"` - GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"` - GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"` - GeositeMatcher string `yaml:"geosite-matcher" json:"geosite-matcher"` - TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` - FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` - GlobalClientFingerprint string `yaml:"global-client-fingerprint"` - GlobalUA string `yaml:"global-ua"` - KeepAliveIdle int `yaml:"keep-alive-idle"` - KeepAliveInterval int `yaml:"keep-alive-interval"` - DisableKeepAlive bool `yaml:"disable-keep-alive"` - - Sniffer RawSniffer `yaml:"sniffer" json:"sniffer"` - ProxyProvider map[string]map[string]any `yaml:"proxy-providers"` - RuleProvider map[string]map[string]any `yaml:"rule-providers"` - Hosts map[string]any `yaml:"hosts" json:"hosts"` - NTP RawNTP `yaml:"ntp" json:"ntp"` - DNS RawDNS `yaml:"dns" json:"dns"` - Tun RawTun `yaml:"tun"` - TuicServer RawTuicServer `yaml:"tuic-server"` - IPTables IPTables `yaml:"iptables"` - Experimental Experimental `yaml:"experimental"` - Profile Profile `yaml:"profile"` - GeoXUrl GeoXUrl `yaml:"geox-url"` - Proxy []map[string]any `yaml:"proxies"` - ProxyGroup []map[string]any `yaml:"proxy-groups"` - Rule []string `yaml:"rules"` - SubRules map[string][]string `yaml:"sub-rules"` - RawTLS TLS `yaml:"tls"` - Listeners []map[string]any `yaml:"listeners"` - - ClashForAndroid RawClashForAndroid `yaml:"clash-for-android" json:"clash-for-android"` +type RawIPTables struct { + Enable bool `yaml:"enable" json:"enable"` + InboundInterface string `yaml:"inbound-interface" json:"inbound-interface"` + Bypass []string `yaml:"bypass" json:"bypass"` + DnsRedirect bool `yaml:"dns-redirect" json:"dns-redirect"` } -type GeoXUrl struct { +type RawExperimental struct { + Fingerprints []string `yaml:"fingerprints"` + QUICGoDisableGSO bool `yaml:"quic-go-disable-gso"` + QUICGoDisableECN bool `yaml:"quic-go-disable-ecn"` + IP4PEnable bool `yaml:"dialer-ip4p-convert"` +} + +type RawProfile struct { + StoreSelected bool `yaml:"store-selected" json:"store-selected"` + StoreFakeIP bool `yaml:"store-fake-ip" json:"store-fake-ip"` +} + +type RawGeoXUrl struct { GeoIp string `yaml:"geoip" json:"geoip"` Mmdb string `yaml:"mmdb" json:"mmdb"` ASN string `yaml:"asn" json:"asn"` @@ -380,6 +343,78 @@ type RawSniffingConfig struct { OverrideDest *bool `yaml:"override-destination" json:"override-destination"` } +type RawTLS struct { + Certificate string `yaml:"certificate" json:"certificate"` + PrivateKey string `yaml:"private-key" json:"private-key"` + CustomTrustCert []string `yaml:"custom-certifactes" json:"custom-certifactes"` +} + +type RawConfig struct { + Port int `yaml:"port" json:"port"` + SocksPort int `yaml:"socks-port" json:"socks-port"` + RedirPort int `yaml:"redir-port" json:"redir-port"` + TProxyPort int `yaml:"tproxy-port" json:"tproxy-port"` + MixedPort int `yaml:"mixed-port" json:"mixed-port"` + ShadowSocksConfig string `yaml:"ss-config" json:"ss-config"` + VmessConfig string `yaml:"vmess-config" json:"vmess-config"` + InboundTfo bool `yaml:"inbound-tfo" json:"inbound-tfo"` + InboundMPTCP bool `yaml:"inbound-mptcp" json:"inbound-mptcp"` + Authentication []string `yaml:"authentication" json:"authentication"` + SkipAuthPrefixes []netip.Prefix `yaml:"skip-auth-prefixes" json:"skip-auth-prefixes"` + LanAllowedIPs []netip.Prefix `yaml:"lan-allowed-ips" json:"lan-allowed-ips"` + LanDisAllowedIPs []netip.Prefix `yaml:"lan-disallowed-ips" json:"lan-disallowed-ips"` + AllowLan bool `yaml:"allow-lan" json:"allow-lan"` + BindAddress string `yaml:"bind-address" json:"bind-address"` + Mode T.TunnelMode `yaml:"mode" json:"mode"` + UnifiedDelay bool `yaml:"unified-delay" json:"unified-delay"` + LogLevel log.LogLevel `yaml:"log-level" json:"log-level"` + IPv6 bool `yaml:"ipv6" json:"ipv6"` + ExternalController string `yaml:"external-controller" json:"external-controller"` + ExternalControllerUnix string `yaml:"external-controller-unix" json:"external-controller-unix"` + ExternalControllerTLS string `yaml:"external-controller-tls" json:"external-controller-tls"` + ExternalUI string `yaml:"external-ui" json:"external-ui"` + ExternalUIURL string `yaml:"external-ui-url" json:"external-ui-url"` + ExternalUIName string `yaml:"external-ui-name" json:"external-ui-name"` + ExternalDohServer string `yaml:"external-doh-server" json:"external-doh-server"` + Secret string `yaml:"secret" json:"secret"` + Interface string `yaml:"interface-name" json:"interface-name"` + RoutingMark int `yaml:"routing-mark" json:"routing-mark"` + Tunnels []LC.Tunnel `yaml:"tunnels" json:"tunnels"` + GeoAutoUpdate bool `yaml:"geo-auto-update" json:"geo-auto-update"` + GeoUpdateInterval int `yaml:"geo-update-interval" json:"geo-update-interval"` + GeodataMode bool `yaml:"geodata-mode" json:"geodata-mode"` + GeodataLoader string `yaml:"geodata-loader" json:"geodata-loader"` + GeositeMatcher string `yaml:"geosite-matcher" json:"geosite-matcher"` + TCPConcurrent bool `yaml:"tcp-concurrent" json:"tcp-concurrent"` + FindProcessMode P.FindProcessMode `yaml:"find-process-mode" json:"find-process-mode"` + GlobalClientFingerprint string `yaml:"global-client-fingerprint" json:"global-client-fingerprint"` + GlobalUA string `yaml:"global-ua" json:"global-ua"` + KeepAliveIdle int `yaml:"keep-alive-idle" json:"keep-alive-idle"` + KeepAliveInterval int `yaml:"keep-alive-interval" json:"keep-alive-interval"` + DisableKeepAlive bool `yaml:"disable-keep-alive" json:"disable-keep-alive"` + + ProxyProvider map[string]map[string]any `yaml:"proxy-providers" json:"proxy-providers"` + RuleProvider map[string]map[string]any `yaml:"rule-providers" json:"rule-providers"` + Proxy []map[string]any `yaml:"proxies" json:"proxies"` + ProxyGroup []map[string]any `yaml:"proxy-groups" json:"proxy-groups"` + Rule []string `yaml:"rules" json:"rule"` + SubRules map[string][]string `yaml:"sub-rules" json:"sub-rules"` + Listeners []map[string]any `yaml:"listeners" json:"listeners"` + Hosts map[string]any `yaml:"hosts" json:"hosts"` + DNS RawDNS `yaml:"dns" json:"dns"` + NTP RawNTP `yaml:"ntp" json:"ntp"` + Tun RawTun `yaml:"tun" json:"tun"` + TuicServer RawTuicServer `yaml:"tuic-server" json:"tuic-server"` + IPTables RawIPTables `yaml:"iptables" json:"iptables"` + Experimental RawExperimental `yaml:"experimental" json:"experimental"` + Profile RawProfile `yaml:"profile" json:"profile"` + GeoXUrl RawGeoXUrl `yaml:"geox-url" json:"geox-url"` + Sniffer RawSniffer `yaml:"sniffer" json:"sniffer"` + TLS RawTLS `yaml:"tls" json:"tls"` + + ClashForAndroid RawClashForAndroid `yaml:"clash-for-android" json:"clash-for-android"` +} + var ( GroupsList = list.New() ProxiesList = list.New() @@ -418,41 +453,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { TCPConcurrent: false, FindProcessMode: P.FindProcessStrict, GlobalUA: "clash.meta/" + C.Version, - Tun: RawTun{ - Enable: false, - Device: "", - Stack: C.TunGvisor, - DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query - AutoRoute: true, - AutoDetectInterface: true, - Inet6Address: []netip.Prefix{netip.MustParsePrefix("fdfe:dcba:9876::1/126")}, - }, - TuicServer: RawTuicServer{ - Enable: false, - Token: nil, - Users: nil, - Certificate: "", - PrivateKey: "", - Listen: "", - CongestionController: "", - MaxIdleTime: 15000, - AuthenticationTimeout: 1000, - ALPN: []string{"h3"}, - MaxUdpRelayPacketSize: 1500, - }, - IPTables: IPTables{ - Enable: false, - InboundInterface: "lo", - Bypass: []string{}, - DnsRedirect: true, - }, - NTP: RawNTP{ - Enable: false, - WriteToSystem: false, - Server: "time.apple.com", - ServerPort: 123, - Interval: 30, - }, DNS: RawDNS{ Enable: false, IPv6: false, @@ -483,11 +483,55 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { "www.msftconnecttest.com", }, }, - Experimental: Experimental{ + NTP: RawNTP{ + Enable: false, + WriteToSystem: false, + Server: "time.apple.com", + Port: 123, + Interval: 30, + }, + Tun: RawTun{ + Enable: false, + Device: "", + Stack: C.TunGvisor, + DNSHijack: []string{"0.0.0.0:53"}, // default hijack all dns query + AutoRoute: true, + AutoDetectInterface: true, + Inet6Address: []netip.Prefix{netip.MustParsePrefix("fdfe:dcba:9876::1/126")}, + }, + TuicServer: RawTuicServer{ + Enable: false, + Token: nil, + Users: nil, + Certificate: "", + PrivateKey: "", + Listen: "", + CongestionController: "", + MaxIdleTime: 15000, + AuthenticationTimeout: 1000, + ALPN: []string{"h3"}, + MaxUdpRelayPacketSize: 1500, + }, + IPTables: RawIPTables{ + Enable: false, + InboundInterface: "lo", + Bypass: []string{}, + DnsRedirect: true, + }, + Experimental: RawExperimental{ // https://github.com/quic-go/quic-go/issues/4178 // Quic-go currently cannot automatically fall back on platforms that do not support ecn, so this feature is turned off by default. QUICGoDisableECN: true, }, + Profile: RawProfile{ + StoreSelected: true, + }, + GeoXUrl: RawGeoXUrl{ + Mmdb: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", + ASN: "https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb", + GeoIp: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", + GeoSite: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat", + }, Sniffer: RawSniffer{ Enable: false, Sniff: map[string]RawSniffingConfig{}, @@ -498,15 +542,6 @@ func UnmarshalRawConfig(buf []byte) (*RawConfig, error) { ParsePureIp: true, OverrideDest: true, }, - Profile: Profile{ - StoreSelected: true, - }, - GeoXUrl: GeoXUrl{ - Mmdb: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb", - ASN: "https://github.com/xishang0128/geoip/releases/download/latest/GeoLite2-ASN.mmdb", - GeoIp: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.dat", - GeoSite: "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat", - }, ExternalUIURL: "https://github.com/MetaCubeX/metacubexd/archive/refs/heads/gh-pages.zip", } @@ -521,10 +556,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { config := &Config{} log.Infoln("Start initial configuration in progress") //Segment finished in xxm startTime := time.Now() - config.Experimental = &rawCfg.Experimental - config.Profile = &rawCfg.Profile - config.IPTables = &rawCfg.IPTables - config.TLS = &rawCfg.RawTLS general, err := parseGeneral(rawCfg) if err != nil { @@ -537,6 +568,42 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { tlsC.SetGlobalUtlsClient(config.General.GlobalClientFingerprint) } + controller, err := parseController(rawCfg) + if err != nil { + return nil, err + } + config.Controller = controller + + experimental, err := parseExperimental(rawCfg) + if err != nil { + return nil, err + } + config.Experimental = experimental + + iptables, err := parseIPTables(rawCfg) + if err != nil { + return nil, err + } + config.IPTables = iptables + + ntpCfg, err := parseNTP(rawCfg) + if err != nil { + return nil, err + } + config.NTP = ntpCfg + + profile, err := parseProfile(rawCfg) + if err != nil { + return nil, err + } + config.Profile = profile + + tlsCfg, err := parseTLS(rawCfg) + if err != nil { + return nil, err + } + config.TLS = tlsCfg + proxies, providers, err := parseProxies(rawCfg) if err != nil { return nil, err @@ -576,9 +643,6 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { } config.Hosts = hosts - ntpCfg := paresNTP(rawCfg) - config.NTP = ntpCfg - dnsCfg, err := parseDNS(rawCfg, hosts, rules, ruleProviders) if err != nil { return nil, err @@ -687,21 +751,18 @@ func parseGeneral(cfg *RawConfig) (*General, error) { InboundTfo: cfg.InboundTfo, InboundMPTCP: cfg.InboundMPTCP, }, - Controller: Controller{ - ExternalController: cfg.ExternalController, - ExternalUI: cfg.ExternalUI, - Secret: cfg.Secret, - ExternalControllerUnix: cfg.ExternalControllerUnix, - ExternalControllerTLS: cfg.ExternalControllerTLS, - ExternalDohServer: cfg.ExternalDohServer, + UnifiedDelay: cfg.UnifiedDelay, + Mode: cfg.Mode, + LogLevel: cfg.LogLevel, + IPv6: cfg.IPv6, + Interface: cfg.Interface, + RoutingMark: cfg.RoutingMark, + GeoXUrl: GeoXUrl{ + GeoIp: cfg.GeoXUrl.GeoIp, + Mmdb: cfg.GeoXUrl.Mmdb, + ASN: cfg.GeoXUrl.ASN, + GeoSite: cfg.GeoXUrl.GeoSite, }, - UnifiedDelay: cfg.UnifiedDelay, - Mode: cfg.Mode, - LogLevel: cfg.LogLevel, - IPv6: cfg.IPv6, - Interface: cfg.Interface, - RoutingMark: cfg.RoutingMark, - GeoXUrl: cfg.GeoXUrl, GeoAutoUpdate: cfg.GeoAutoUpdate, GeoUpdateInterval: cfg.GeoUpdateInterval, GeodataMode: cfg.GeodataMode, @@ -713,6 +774,61 @@ func parseGeneral(cfg *RawConfig) (*General, error) { }, nil } +func parseController(cfg *RawConfig) (*Controller, error) { + return &Controller{ + ExternalController: cfg.ExternalController, + ExternalUI: cfg.ExternalUI, + Secret: cfg.Secret, + ExternalControllerUnix: cfg.ExternalControllerUnix, + ExternalControllerTLS: cfg.ExternalControllerTLS, + ExternalDohServer: cfg.ExternalDohServer, + }, nil +} + +func parseExperimental(cfg *RawConfig) (*Experimental, error) { + return &Experimental{ + Fingerprints: cfg.Experimental.Fingerprints, + QUICGoDisableGSO: cfg.Experimental.QUICGoDisableGSO, + QUICGoDisableECN: cfg.Experimental.QUICGoDisableECN, + IP4PEnable: cfg.Experimental.IP4PEnable, + }, nil +} + +func parseIPTables(cfg *RawConfig) (*IPTables, error) { + return &IPTables{ + Enable: cfg.IPTables.Enable, + InboundInterface: cfg.IPTables.InboundInterface, + Bypass: cfg.IPTables.Bypass, + DnsRedirect: cfg.IPTables.DnsRedirect, + }, nil +} + +func parseNTP(cfg *RawConfig) (*NTP, error) { + return &NTP{ + Enable: cfg.NTP.Enable, + Server: cfg.NTP.Server, + Port: cfg.NTP.Port, + Interval: cfg.NTP.Interval, + DialerProxy: cfg.NTP.DialerProxy, + WriteToSystem: cfg.NTP.WriteToSystem, + }, nil +} + +func parseProfile(cfg *RawConfig) (*Profile, error) { + return &Profile{ + StoreSelected: cfg.Profile.StoreSelected, + StoreFakeIP: cfg.Profile.StoreFakeIP, + }, nil +} + +func parseTLS(cfg *RawConfig) (*TLS, error) { + return &TLS{ + Certificate: cfg.TLS.Certificate, + PrivateKey: cfg.TLS.PrivateKey, + CustomTrustCert: cfg.TLS.CustomTrustCert, + }, nil +} + func parseProxies(cfg *RawConfig) (proxies map[string]C.Proxy, providersMap map[string]providerTypes.ProxyProvider, err error) { proxies = make(map[string]C.Proxy) providersMap = make(map[string]providerTypes.ProxyProvider) @@ -1259,19 +1375,6 @@ func parseNameServerPolicy(nsPolicy *orderedmap.OrderedMap[string, any], rules [ return policy, nil } -func paresNTP(rawCfg *RawConfig) *NTP { - cfg := rawCfg.NTP - ntpCfg := &NTP{ - Enable: cfg.Enable, - Server: cfg.Server, - Port: cfg.ServerPort, - Interval: cfg.Interval, - DialerProxy: cfg.DialerProxy, - WriteToSystem: cfg.WriteToSystem, - } - return ntpCfg -} - func parseDNS(rawCfg *RawConfig, hosts *trie.DomainTrie[resolver.HostValue], rules []C.Rule, ruleProviders map[string]providerTypes.RuleProvider) (*DNS, error) { cfg := rawCfg.DNS if cfg.Enable && len(cfg.NameServer) == 0 { diff --git a/mihomo/hub/executor/executor.go b/mihomo/hub/executor/executor.go index 891452412f..d54d55b752 100644 --- a/mihomo/hub/executor/executor.go +++ b/mihomo/hub/executor/executor.go @@ -22,6 +22,7 @@ import ( "github.com/metacubex/mihomo/component/profile/cachefile" "github.com/metacubex/mihomo/component/resolver" SNI "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" "github.com/metacubex/mihomo/config" @@ -90,6 +91,7 @@ func ApplyConfig(cfg *config.Config, force bool) { } } + updateExperimental(cfg.Experimental) updateUsers(cfg.Users) updateProxies(cfg.Proxies, cfg.Providers) updateRules(cfg.Rules, cfg.SubRules, cfg.RuleProviders) @@ -100,8 +102,6 @@ func ApplyConfig(cfg *config.Config, force bool) { updateDNS(cfg.DNS, cfg.General.IPv6) updateListeners(cfg.General, cfg.Listeners, force) updateIPTables(cfg) - updateTun(cfg.General) - updateExperimental(cfg) updateTunnels(cfg.Tunnels) tunnel.OnInnerLoading() @@ -146,19 +146,31 @@ func GetGeneral() *config.General { LanDisAllowedIPs: inbound.DisAllowedIPs(), AllowLan: listener.AllowLan(), BindAddress: listener.BindAddress(), + InboundTfo: inbound.Tfo(), + InboundMPTCP: inbound.MPTCP(), }, - Controller: config.Controller{}, - Mode: tunnel.Mode(), - LogLevel: log.Level(), - IPv6: !resolver.DisableIPv6, - GeodataMode: G.GeodataMode(), - GeoAutoUpdate: G.GeoAutoUpdate(), - GeoUpdateInterval: G.GeoUpdateInterval(), - GeodataLoader: G.LoaderName(), - GeositeMatcher: G.SiteMatcherName(), - Interface: dialer.DefaultInterface.Load(), - Sniffing: tunnel.IsSniffing(), - TCPConcurrent: dialer.GetTcpConcurrent(), + Mode: tunnel.Mode(), + UnifiedDelay: adapter.UnifiedDelay.Load(), + LogLevel: log.Level(), + IPv6: !resolver.DisableIPv6, + Interface: dialer.DefaultInterface.Load(), + RoutingMark: int(dialer.DefaultRoutingMark.Load()), + GeoXUrl: config.GeoXUrl{ + GeoIp: C.GeoIpUrl, + Mmdb: C.MmdbUrl, + ASN: C.ASNUrl, + GeoSite: C.GeoSiteUrl, + }, + GeoAutoUpdate: G.GeoAutoUpdate(), + GeoUpdateInterval: G.GeoUpdateInterval(), + GeodataMode: G.GeodataMode(), + GeodataLoader: G.LoaderName(), + GeositeMatcher: G.SiteMatcherName(), + TCPConcurrent: dialer.GetTcpConcurrent(), + FindProcessMode: tunnel.FindProcessMode(), + Sniffing: tunnel.IsSniffing(), + GlobalClientFingerprint: tlsC.GetGlobalFingerprint(), + GlobalUA: C.UA, } return general @@ -186,16 +198,17 @@ func updateListeners(general *config.General, listeners map[string]C.InboundList listener.ReCreateShadowSocks(general.ShadowSocksConfig, tunnel.Tunnel) listener.ReCreateVmess(general.VmessConfig, tunnel.Tunnel) listener.ReCreateTuic(general.TuicServer, tunnel.Tunnel) + listener.ReCreateTun(general.Tun, tunnel.Tunnel) } -func updateExperimental(c *config.Config) { - if c.Experimental.QUICGoDisableGSO { +func updateExperimental(c *config.Experimental) { + if c.QUICGoDisableGSO { _ = os.Setenv("QUIC_GO_DISABLE_GSO", strconv.FormatBool(true)) } - if c.Experimental.QUICGoDisableECN { + if c.QUICGoDisableECN { _ = os.Setenv("QUIC_GO_DISABLE_ECN", strconv.FormatBool(true)) } - dialer.GetIP4PEnable(c.Experimental.IP4PEnable) + dialer.GetIP4PEnable(c.IP4PEnable) } func updateNTP(c *config.NTP) { @@ -343,12 +356,6 @@ func hcCompatibleProvider(proxyProviders map[string]provider.ProxyProvider) { } } -func updateTun(general *config.General) { - if general == nil { - return - } - listener.ReCreateTun(general.Tun, tunnel.Tunnel) -} func updateSniffer(sniffer *config.Sniffer) { if sniffer.Enable { diff --git a/mihomo/hub/hub.go b/mihomo/hub/hub.go index 57c91aaef9..2a53b19793 100644 --- a/mihomo/hub/hub.go +++ b/mihomo/hub/hub.go @@ -11,25 +11,25 @@ type Option func(*config.Config) func WithExternalUI(externalUI string) Option { return func(cfg *config.Config) { - cfg.General.ExternalUI = externalUI + cfg.Controller.ExternalUI = externalUI } } func WithExternalController(externalController string) Option { return func(cfg *config.Config) { - cfg.General.ExternalController = externalController + cfg.Controller.ExternalController = externalController } } func WithExternalControllerUnix(externalControllerUnix string) Option { return func(cfg *config.Config) { - cfg.General.ExternalControllerUnix = externalControllerUnix + cfg.Controller.ExternalControllerUnix = externalControllerUnix } } func WithSecret(secret string) Option { return func(cfg *config.Config) { - cfg.General.Secret = secret + cfg.Controller.Secret = secret } } @@ -44,18 +44,18 @@ func Parse(options ...Option) error { option(cfg) } - if cfg.General.ExternalUI != "" { - route.SetUIPath(cfg.General.ExternalUI) + if cfg.Controller.ExternalUI != "" { + route.SetUIPath(cfg.Controller.ExternalUI) } - if cfg.General.ExternalController != "" { - go route.Start(cfg.General.ExternalController, cfg.General.ExternalControllerTLS, - cfg.General.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.General.ExternalDohServer, + if cfg.Controller.ExternalController != "" { + go route.Start(cfg.Controller.ExternalController, cfg.Controller.ExternalControllerTLS, + cfg.Controller.Secret, cfg.TLS.Certificate, cfg.TLS.PrivateKey, cfg.Controller.ExternalDohServer, cfg.General.LogLevel == log.DEBUG) } - if cfg.General.ExternalControllerUnix != "" { - go route.StartUnix(cfg.General.ExternalControllerUnix, cfg.General.ExternalDohServer, cfg.General.LogLevel == log.DEBUG) + if cfg.Controller.ExternalControllerUnix != "" { + go route.StartUnix(cfg.Controller.ExternalControllerUnix, cfg.Controller.ExternalDohServer, cfg.General.LogLevel == log.DEBUG) } executor.ApplyConfig(cfg, true) diff --git a/mihomo/hub/route/configs.go b/mihomo/hub/route/configs.go index c7b340c603..d4bda2bf4c 100644 --- a/mihomo/hub/route/configs.go +++ b/mihomo/hub/route/configs.go @@ -62,23 +62,22 @@ type tunSchema struct { DNSHijack *[]string `yaml:"dns-hijack" json:"dns-hijack"` AutoRoute *bool `yaml:"auto-route" json:"auto-route"` AutoDetectInterface *bool `yaml:"auto-detect-interface" json:"auto-detect-interface"` - //RedirectToTun []string `yaml:"-" json:"-"` MTU *uint32 `yaml:"mtu" json:"mtu,omitempty"` GSO *bool `yaml:"gso" json:"gso,omitempty"` GSOMaxSize *uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` //Inet4Address *[]netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` Inet6Address *[]netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - IPRoute2TableIndex *int `yaml:"iproute2-table-index" json:"iproute2_table_index,omitempty"` - IPRoute2RuleIndex *int `yaml:"iproute2-rule-index" json:"iproute2_rule_index,omitempty"` - AutoRedirect *bool `yaml:"auto-redirect" json:"auto_redirect,omitempty"` - AutoRedirectInputMark *uint32 `yaml:"auto-redirect-input-mark" json:"auto_redirect_input_mark,omitempty"` - AutoRedirectOutputMark *uint32 `yaml:"auto-redirect-output-mark" json:"auto_redirect_output_mark,omitempty"` + IPRoute2TableIndex *int `yaml:"iproute2-table-index" json:"iproute2-table-index,omitempty"` + IPRoute2RuleIndex *int `yaml:"iproute2-rule-index" json:"iproute2-rule-index,omitempty"` + AutoRedirect *bool `yaml:"auto-redirect" json:"auto-redirect,omitempty"` + AutoRedirectInputMark *uint32 `yaml:"auto-redirect-input-mark" json:"auto-redirect-input-mark,omitempty"` + AutoRedirectOutputMark *uint32 `yaml:"auto-redirect-output-mark" json:"auto-redirect-output-mark,omitempty"` StrictRoute *bool `yaml:"strict-route" json:"strict-route,omitempty"` - RouteAddress *[]netip.Prefix `yaml:"route-address" json:"route_address,omitempty"` - RouteAddressSet *[]string `yaml:"route-address-set" json:"route_address_set,omitempty"` - RouteExcludeAddress *[]netip.Prefix `yaml:"route-exclude-address" json:"route_exclude_address,omitempty"` - RouteExcludeAddressSet *[]string `yaml:"route-exclude-address-set" json:"route_exclude_address_set,omitempty"` + RouteAddress *[]netip.Prefix `yaml:"route-address" json:"route-address,omitempty"` + RouteAddressSet *[]string `yaml:"route-address-set" json:"route-address-set,omitempty"` + RouteExcludeAddress *[]netip.Prefix `yaml:"route-exclude-address" json:"route-exclude-address,omitempty"` + RouteExcludeAddressSet *[]string `yaml:"route-exclude-address-set" json:"route-exclude-address-set,omitempty"` IncludeInterface *[]string `yaml:"include-interface" json:"include-interface,omitempty"` ExcludeInterface *[]string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` IncludeUID *[]uint32 `yaml:"include-uid" json:"include-uid,omitempty"` @@ -118,21 +117,13 @@ func getConfigs(w http.ResponseWriter, r *http.Request) { render.JSON(w, r, general) } -func pointerOrDefault(p *int, def int) int { +func pointerOrDefault[T any](p *T, def T) T { if p != nil { return *p } return def } -func pointerOrDefaultString(p *string, def string) string { - if p != nil { - return *p - } - - return def -} - func pointerOrDefaultTun(p *tunSchema, def LC.Tun) LC.Tun { if p != nil { def.Enable = p.Enable @@ -336,8 +327,8 @@ func patchConfigs(w http.ResponseWriter, r *http.Request) { P.ReCreateTProxy(pointerOrDefault(general.TProxyPort, ports.TProxyPort), tunnel.Tunnel) P.ReCreateMixed(pointerOrDefault(general.MixedPort, ports.MixedPort), tunnel.Tunnel) P.ReCreateTun(pointerOrDefaultTun(general.Tun, P.LastTunConf), tunnel.Tunnel) - P.ReCreateShadowSocks(pointerOrDefaultString(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel) - P.ReCreateVmess(pointerOrDefaultString(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel) + P.ReCreateShadowSocks(pointerOrDefault(general.ShadowSocksConfig, ports.ShadowSocksConfig), tunnel.Tunnel) + P.ReCreateVmess(pointerOrDefault(general.VmessConfig, ports.VmessConfig), tunnel.Tunnel) P.ReCreateTuic(pointerOrDefaultTuicServer(general.TuicServer, P.LastTuicConf), tunnel.Tunnel) if general.Mode != nil { diff --git a/mihomo/listener/config/tun.go b/mihomo/listener/config/tun.go index cea22bfdc8..3901bb1d6d 100644 --- a/mihomo/listener/config/tun.go +++ b/mihomo/listener/config/tun.go @@ -3,7 +3,10 @@ package config import ( "net/netip" + "github.com/metacubex/mihomo/common/nnip" C "github.com/metacubex/mihomo/constant" + + "golang.org/x/exp/slices" ) func StringSliceToNetipPrefixSlice(ss []string) ([]netip.Prefix, error) { @@ -25,23 +28,22 @@ type Tun struct { DNSHijack []string `yaml:"dns-hijack" json:"dns-hijack"` AutoRoute bool `yaml:"auto-route" json:"auto-route"` AutoDetectInterface bool `yaml:"auto-detect-interface" json:"auto-detect-interface"` - RedirectToTun []string `yaml:"-" json:"-"` MTU uint32 `yaml:"mtu" json:"mtu,omitempty"` GSO bool `yaml:"gso" json:"gso,omitempty"` GSOMaxSize uint32 `yaml:"gso-max-size" json:"gso-max-size,omitempty"` Inet4Address []netip.Prefix `yaml:"inet4-address" json:"inet4-address,omitempty"` Inet6Address []netip.Prefix `yaml:"inet6-address" json:"inet6-address,omitempty"` - IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2_table_index,omitempty"` - IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2_rule_index,omitempty"` - AutoRedirect bool `yaml:"auto-redirect" json:"auto_redirect,omitempty"` - AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto_redirect_input_mark,omitempty"` - AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto_redirect_output_mark,omitempty"` + IPRoute2TableIndex int `yaml:"iproute2-table-index" json:"iproute2-table-index,omitempty"` + IPRoute2RuleIndex int `yaml:"iproute2-rule-index" json:"iproute2-rule-index,omitempty"` + AutoRedirect bool `yaml:"auto-redirect" json:"auto-redirect,omitempty"` + AutoRedirectInputMark uint32 `yaml:"auto-redirect-input-mark" json:"auto-redirect-input-mark,omitempty"` + AutoRedirectOutputMark uint32 `yaml:"auto-redirect-output-mark" json:"auto-redirect-output-mark,omitempty"` StrictRoute bool `yaml:"strict-route" json:"strict-route,omitempty"` - RouteAddress []netip.Prefix `yaml:"route-address" json:"route_address,omitempty"` - RouteAddressSet []string `yaml:"route-address-set" json:"route_address_set,omitempty"` - RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route_exclude_address,omitempty"` - RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route_exclude_address_set,omitempty"` + RouteAddress []netip.Prefix `yaml:"route-address" json:"route-address,omitempty"` + RouteAddressSet []string `yaml:"route-address-set" json:"route-address-set,omitempty"` + RouteExcludeAddress []netip.Prefix `yaml:"route-exclude-address" json:"route-exclude-address,omitempty"` + RouteExcludeAddressSet []string `yaml:"route-exclude-address-set" json:"route-exclude-address-set,omitempty"` IncludeInterface []string `yaml:"include-interface" json:"include-interface,omitempty"` ExcludeInterface []string `yaml:"exclude-interface" json:"exclude-interface,omitempty"` IncludeUID []uint32 `yaml:"include-uid" json:"include-uid,omitempty"` @@ -60,3 +62,146 @@ type Tun struct { Inet4RouteExcludeAddress []netip.Prefix `yaml:"inet4-route-exclude-address" json:"inet4-route-exclude-address,omitempty"` Inet6RouteExcludeAddress []netip.Prefix `yaml:"inet6-route-exclude-address" json:"inet6-route-exclude-address,omitempty"` } + +func (t *Tun) Sort() { + slices.Sort(t.DNSHijack) + + slices.SortFunc(t.Inet4Address, nnip.PrefixCompare) + slices.SortFunc(t.Inet6Address, nnip.PrefixCompare) + slices.SortFunc(t.RouteAddress, nnip.PrefixCompare) + slices.Sort(t.RouteAddressSet) + slices.SortFunc(t.RouteExcludeAddress, nnip.PrefixCompare) + slices.Sort(t.RouteExcludeAddressSet) + slices.Sort(t.IncludeInterface) + slices.Sort(t.ExcludeInterface) + slices.Sort(t.IncludeUID) + slices.Sort(t.IncludeUIDRange) + slices.Sort(t.ExcludeUID) + slices.Sort(t.ExcludeUIDRange) + slices.Sort(t.IncludeAndroidUser) + slices.Sort(t.IncludePackage) + slices.Sort(t.ExcludePackage) + + slices.SortFunc(t.Inet4RouteAddress, nnip.PrefixCompare) + slices.SortFunc(t.Inet6RouteAddress, nnip.PrefixCompare) + slices.SortFunc(t.Inet4RouteExcludeAddress, nnip.PrefixCompare) + slices.SortFunc(t.Inet6RouteExcludeAddress, nnip.PrefixCompare) +} + +func (t *Tun) Equal(other Tun) bool { + if t.Enable != other.Enable { + return false + } + if t.Device != other.Device { + return false + } + if t.Stack != other.Stack { + return false + } + if !slices.Equal(t.DNSHijack, other.DNSHijack) { + return false + } + if t.AutoRoute != other.AutoRoute { + return false + } + if t.AutoDetectInterface != other.AutoDetectInterface { + return false + } + + if t.MTU != other.MTU { + return false + } + if t.GSO != other.GSO { + return false + } + if t.GSOMaxSize != other.GSOMaxSize { + return false + } + if !slices.Equal(t.Inet4Address, other.Inet4Address) { + return false + } + if !slices.Equal(t.Inet6Address, other.Inet6Address) { + return false + } + if t.IPRoute2TableIndex != other.IPRoute2TableIndex { + return false + } + if t.IPRoute2RuleIndex != other.IPRoute2RuleIndex { + return false + } + if t.AutoRedirect != other.AutoRedirect { + return false + } + if t.AutoRedirectInputMark != other.AutoRedirectInputMark { + return false + } + if t.AutoRedirectOutputMark != other.AutoRedirectOutputMark { + return false + } + if t.StrictRoute != other.StrictRoute { + return false + } + if !slices.Equal(t.RouteAddress, other.RouteAddress) { + return false + } + if !slices.Equal(t.RouteAddressSet, other.RouteAddressSet) { + return false + } + if !slices.Equal(t.RouteExcludeAddress, other.RouteExcludeAddress) { + return false + } + if !slices.Equal(t.RouteExcludeAddressSet, other.RouteExcludeAddressSet) { + return false + } + if !slices.Equal(t.IncludeInterface, other.IncludeInterface) { + return false + } + if !slices.Equal(t.ExcludeInterface, other.ExcludeInterface) { + return false + } + if !slices.Equal(t.IncludeUID, other.IncludeUID) { + return false + } + if !slices.Equal(t.IncludeUIDRange, other.IncludeUIDRange) { + return false + } + if !slices.Equal(t.ExcludeUID, other.ExcludeUID) { + return false + } + if !slices.Equal(t.ExcludeUIDRange, other.ExcludeUIDRange) { + return false + } + if !slices.Equal(t.IncludeAndroidUser, other.IncludeAndroidUser) { + return false + } + if !slices.Equal(t.IncludePackage, other.IncludePackage) { + return false + } + if !slices.Equal(t.ExcludePackage, other.ExcludePackage) { + return false + } + if t.EndpointIndependentNat != other.EndpointIndependentNat { + return false + } + if t.UDPTimeout != other.UDPTimeout { + return false + } + if t.FileDescriptor != other.FileDescriptor { + return false + } + + if !slices.Equal(t.Inet4RouteAddress, other.Inet4RouteAddress) { + return false + } + if !slices.Equal(t.Inet6RouteAddress, other.Inet6RouteAddress) { + return false + } + if !slices.Equal(t.Inet4RouteExcludeAddress, other.Inet4RouteExcludeAddress) { + return false + } + if !slices.Equal(t.Inet6RouteExcludeAddress, other.Inet6RouteExcludeAddress) { + return false + } + + return true +} diff --git a/mihomo/listener/inbound/tun.go b/mihomo/listener/inbound/tun.go index a950f80db2..77ad6bd61c 100644 --- a/mihomo/listener/inbound/tun.go +++ b/mihomo/listener/inbound/tun.go @@ -21,35 +21,35 @@ type TunOption struct { MTU uint32 `inbound:"mtu,omitempty"` GSO bool `inbound:"gso,omitempty"` GSOMaxSize uint32 `inbound:"gso-max-size,omitempty"` - Inet4Address []string `inbound:"inet4_address,omitempty"` - Inet6Address []string `inbound:"inet6_address,omitempty"` + Inet4Address []string `inbound:"inet4-address,omitempty"` + Inet6Address []string `inbound:"inet6-address,omitempty"` IPRoute2TableIndex int `inbound:"iproute2-table-index"` IPRoute2RuleIndex int `inbound:"iproute2-rule-index"` AutoRedirect bool `inbound:"auto-redirect"` AutoRedirectInputMark uint32 `inbound:"auto-redirect-input-mark"` AutoRedirectOutputMark uint32 `inbound:"auto-redirect-output-mark"` - StrictRoute bool `inbound:"strict_route,omitempty"` + StrictRoute bool `inbound:"strict-route,omitempty"` RouteAddress []string `inbound:"route-address"` RouteAddressSet []string `inbound:"route-address-set"` RouteExcludeAddress []string `inbound:"route-exclude-address"` RouteExcludeAddressSet []string `inbound:"route-exclude-address-set"` IncludeInterface []string `inbound:"include-interface,omitempty"` ExcludeInterface []string `inbound:"exclude-interface"` - IncludeUID []uint32 `inbound:"include_uid,omitempty"` - IncludeUIDRange []string `inbound:"include_uid_range,omitempty"` - ExcludeUID []uint32 `inbound:"exclude_uid,omitempty"` - ExcludeUIDRange []string `inbound:"exclude_uid_range,omitempty"` - IncludeAndroidUser []int `inbound:"include_android_user,omitempty"` - IncludePackage []string `inbound:"include_package,omitempty"` - ExcludePackage []string `inbound:"exclude_package,omitempty"` - EndpointIndependentNat bool `inbound:"endpoint_independent_nat,omitempty"` - UDPTimeout int64 `inbound:"udp_timeout,omitempty"` + IncludeUID []uint32 `inbound:"include-uid,omitempty"` + IncludeUIDRange []string `inbound:"include-uid-range,omitempty"` + ExcludeUID []uint32 `inbound:"exclude-uid,omitempty"` + ExcludeUIDRange []string `inbound:"exclude-uid-range,omitempty"` + IncludeAndroidUser []int `inbound:"include-android-user,omitempty"` + IncludePackage []string `inbound:"include-package,omitempty"` + ExcludePackage []string `inbound:"exclude-package,omitempty"` + EndpointIndependentNat bool `inbound:"endpoint-independent-nat,omitempty"` + UDPTimeout int64 `inbound:"udp-timeout,omitempty"` FileDescriptor int `inbound:"file-descriptor,omitempty"` - Inet4RouteAddress []string `inbound:"inet4_route_address,omitempty"` - Inet6RouteAddress []string `inbound:"inet6_route_address,omitempty"` - Inet4RouteExcludeAddress []string `inbound:"inet4_route_exclude_address,omitempty"` - Inet6RouteExcludeAddress []string `inbound:"inet6_route_exclude_address,omitempty"` + Inet4RouteAddress []string `inbound:"inet4-route-address,omitempty"` + Inet6RouteAddress []string `inbound:"inet6-route-address,omitempty"` + Inet4RouteExcludeAddress []string `inbound:"inet4-route-exclude-address,omitempty"` + Inet6RouteExcludeAddress []string `inbound:"inet6-route-exclude-address,omitempty"` } func (o TunOption) Equal(config C.InboundConfig) bool { diff --git a/mihomo/listener/listener.go b/mihomo/listener/listener.go index 4d10677812..2e25c8b8f6 100644 --- a/mihomo/listener/listener.go +++ b/mihomo/listener/listener.go @@ -2,9 +2,7 @@ package listener import ( "fmt" - "golang.org/x/exp/slices" "net" - "sort" "strconv" "strings" "sync" @@ -49,19 +47,17 @@ var ( tuicListener *tuic.Listener // lock for recreate function - socksMux sync.Mutex - httpMux sync.Mutex - redirMux sync.Mutex - tproxyMux sync.Mutex - mixedMux sync.Mutex - tunnelMux sync.Mutex - inboundMux sync.Mutex - tunMux sync.Mutex - ssMux sync.Mutex - vmessMux sync.Mutex - tuicMux sync.Mutex - autoRedirMux sync.Mutex - tcMux sync.Mutex + socksMux sync.Mutex + httpMux sync.Mutex + redirMux sync.Mutex + tproxyMux sync.Mutex + mixedMux sync.Mutex + tunnelMux sync.Mutex + inboundMux sync.Mutex + tunMux sync.Mutex + ssMux sync.Mutex + vmessMux sync.Mutex + tuicMux sync.Mutex LastTunConf LC.Tun LastTuicConf LC.TuicServer @@ -499,6 +495,8 @@ func ReCreateMixed(port int, tunnel C.Tunnel) { } func ReCreateTun(tunConf LC.Tun, tunnel C.Tunnel) { + tunConf.Sort() + tunMux.Lock() defer func() { LastTunConf = tunConf @@ -513,7 +511,7 @@ func ReCreateTun(tunConf LC.Tun, tunnel C.Tunnel) { } }() - if !hasTunConfigChange(&tunConf) { + if tunConf.Equal(LastTunConf) { if tunLister != nil { tunLister.FlushDefaultInterface() } @@ -717,137 +715,6 @@ func genAddr(host string, port int, allowLan bool) string { return fmt.Sprintf("127.0.0.1:%d", port) } -func hasTunConfigChange(tunConf *LC.Tun) bool { - if LastTunConf.Enable != tunConf.Enable || - LastTunConf.Device != tunConf.Device || - LastTunConf.Stack != tunConf.Stack || - LastTunConf.AutoRoute != tunConf.AutoRoute || - LastTunConf.AutoDetectInterface != tunConf.AutoDetectInterface || - LastTunConf.MTU != tunConf.MTU || - LastTunConf.GSO != tunConf.GSO || - LastTunConf.GSOMaxSize != tunConf.GSOMaxSize || - LastTunConf.IPRoute2TableIndex != tunConf.IPRoute2TableIndex || - LastTunConf.IPRoute2RuleIndex != tunConf.IPRoute2RuleIndex || - LastTunConf.AutoRedirect != tunConf.AutoRedirect || - LastTunConf.AutoRedirectInputMark != tunConf.AutoRedirectInputMark || - LastTunConf.AutoRedirectOutputMark != tunConf.AutoRedirectOutputMark || - LastTunConf.StrictRoute != tunConf.StrictRoute || - LastTunConf.EndpointIndependentNat != tunConf.EndpointIndependentNat || - LastTunConf.UDPTimeout != tunConf.UDPTimeout || - LastTunConf.FileDescriptor != tunConf.FileDescriptor { - return true - } - - if len(LastTunConf.DNSHijack) != len(tunConf.DNSHijack) { - return true - } - - sort.Slice(tunConf.DNSHijack, func(i, j int) bool { - return tunConf.DNSHijack[i] < tunConf.DNSHijack[j] - }) - - sort.Slice(tunConf.RouteAddress, func(i, j int) bool { - return tunConf.RouteAddress[i].String() < tunConf.RouteAddress[j].String() - }) - - sort.Slice(tunConf.RouteAddressSet, func(i, j int) bool { - return tunConf.RouteAddressSet[i] < tunConf.RouteAddressSet[j] - }) - - sort.Slice(tunConf.RouteExcludeAddress, func(i, j int) bool { - return tunConf.RouteExcludeAddress[i].String() < tunConf.RouteExcludeAddress[j].String() - }) - - sort.Slice(tunConf.RouteExcludeAddressSet, func(i, j int) bool { - return tunConf.RouteExcludeAddressSet[i] < tunConf.RouteExcludeAddressSet[j] - }) - - sort.Slice(tunConf.Inet4Address, func(i, j int) bool { - return tunConf.Inet4Address[i].String() < tunConf.Inet4Address[j].String() - }) - - sort.Slice(tunConf.Inet6Address, func(i, j int) bool { - return tunConf.Inet6Address[i].String() < tunConf.Inet6Address[j].String() - }) - - sort.Slice(tunConf.Inet4RouteAddress, func(i, j int) bool { - return tunConf.Inet4RouteAddress[i].String() < tunConf.Inet4RouteAddress[j].String() - }) - - sort.Slice(tunConf.Inet6RouteAddress, func(i, j int) bool { - return tunConf.Inet6RouteAddress[i].String() < tunConf.Inet6RouteAddress[j].String() - }) - - sort.Slice(tunConf.Inet4RouteExcludeAddress, func(i, j int) bool { - return tunConf.Inet4RouteExcludeAddress[i].String() < tunConf.Inet4RouteExcludeAddress[j].String() - }) - - sort.Slice(tunConf.Inet6RouteExcludeAddress, func(i, j int) bool { - return tunConf.Inet6RouteExcludeAddress[i].String() < tunConf.Inet6RouteExcludeAddress[j].String() - }) - - sort.Slice(tunConf.IncludeInterface, func(i, j int) bool { - return tunConf.IncludeInterface[i] < tunConf.IncludeInterface[j] - }) - - sort.Slice(tunConf.ExcludeInterface, func(i, j int) bool { - return tunConf.ExcludeInterface[i] < tunConf.ExcludeInterface[j] - }) - - sort.Slice(tunConf.IncludeUID, func(i, j int) bool { - return tunConf.IncludeUID[i] < tunConf.IncludeUID[j] - }) - - sort.Slice(tunConf.IncludeUIDRange, func(i, j int) bool { - return tunConf.IncludeUIDRange[i] < tunConf.IncludeUIDRange[j] - }) - - sort.Slice(tunConf.ExcludeUID, func(i, j int) bool { - return tunConf.ExcludeUID[i] < tunConf.ExcludeUID[j] - }) - - sort.Slice(tunConf.ExcludeUIDRange, func(i, j int) bool { - return tunConf.ExcludeUIDRange[i] < tunConf.ExcludeUIDRange[j] - }) - - sort.Slice(tunConf.IncludeAndroidUser, func(i, j int) bool { - return tunConf.IncludeAndroidUser[i] < tunConf.IncludeAndroidUser[j] - }) - - sort.Slice(tunConf.IncludePackage, func(i, j int) bool { - return tunConf.IncludePackage[i] < tunConf.IncludePackage[j] - }) - - sort.Slice(tunConf.ExcludePackage, func(i, j int) bool { - return tunConf.ExcludePackage[i] < tunConf.ExcludePackage[j] - }) - - if !slices.Equal(tunConf.DNSHijack, LastTunConf.DNSHijack) || - !slices.Equal(tunConf.RouteAddress, LastTunConf.RouteAddress) || - !slices.Equal(tunConf.RouteAddressSet, LastTunConf.RouteAddressSet) || - !slices.Equal(tunConf.RouteExcludeAddress, LastTunConf.RouteExcludeAddress) || - !slices.Equal(tunConf.RouteExcludeAddressSet, LastTunConf.RouteExcludeAddressSet) || - !slices.Equal(tunConf.Inet4Address, LastTunConf.Inet4Address) || - !slices.Equal(tunConf.Inet6Address, LastTunConf.Inet6Address) || - !slices.Equal(tunConf.Inet4RouteAddress, LastTunConf.Inet4RouteAddress) || - !slices.Equal(tunConf.Inet6RouteAddress, LastTunConf.Inet6RouteAddress) || - !slices.Equal(tunConf.Inet4RouteExcludeAddress, LastTunConf.Inet4RouteExcludeAddress) || - !slices.Equal(tunConf.Inet6RouteExcludeAddress, LastTunConf.Inet6RouteExcludeAddress) || - !slices.Equal(tunConf.IncludeInterface, LastTunConf.IncludeInterface) || - !slices.Equal(tunConf.ExcludeInterface, LastTunConf.ExcludeInterface) || - !slices.Equal(tunConf.IncludeUID, LastTunConf.IncludeUID) || - !slices.Equal(tunConf.IncludeUIDRange, LastTunConf.IncludeUIDRange) || - !slices.Equal(tunConf.ExcludeUID, LastTunConf.ExcludeUID) || - !slices.Equal(tunConf.ExcludeUIDRange, LastTunConf.ExcludeUIDRange) || - !slices.Equal(tunConf.IncludeAndroidUser, LastTunConf.IncludeAndroidUser) || - !slices.Equal(tunConf.IncludePackage, LastTunConf.IncludePackage) || - !slices.Equal(tunConf.ExcludePackage, LastTunConf.ExcludePackage) { - return true - } - - return false -} - func closeTunListener() { if tunLister != nil { tunLister.Close() diff --git a/mihomo/tunnel/tunnel.go b/mihomo/tunnel/tunnel.go index 5dd468f3b4..b1b417bee2 100644 --- a/mihomo/tunnel/tunnel.go +++ b/mihomo/tunnel/tunnel.go @@ -225,6 +225,10 @@ func SetMode(m TunnelMode) { mode = m } +func FindProcessMode() P.FindProcessMode { + return findProcessMode +} + // SetFindProcessMode replace SetAlwaysFindProcess // always find process info if legacyAlways = true or mode.Always() = true, may be increase many memory func SetFindProcessMode(mode P.FindProcessMode) { diff --git a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/subscribe.lua b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/subscribe.lua index e423a67a13..4229d607dd 100755 --- a/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/subscribe.lua +++ b/openwrt-passwall/luci-app-passwall/root/usr/share/passwall/subscribe.lua @@ -488,6 +488,10 @@ local function processData(szType, content, add_mode, add_from) if info.net == 'grpc' then result.grpc_serviceName = info.path end + if info.net == 'splithttp' then + result.splithttp_host = info.host + result.splithttp_path = info.path + end if not info.security then result.security = "auto" end if info.tls == "tls" or info.tls == "1" then result.tls = "1" @@ -496,6 +500,11 @@ local function processData(szType, content, add_mode, add_from) else result.tls = "0" end + + if result.type == "sing-box" and (result.transport == "mkcp" or result.transport == "splithttp") then + log("跳过节点:" .. result.remarks ..",因Sing-Box不支持" .. szType .. "协议的" .. result.transport .. "传输方式,需更换Xray。") + return nil + end elseif szType == "ss" then result.type = "SS" @@ -821,11 +830,19 @@ local function processData(szType, content, add_mode, add_from) if params.serviceName then result.grpc_serviceName = params.serviceName end result.grpc_mode = params.mode end + if params.type == 'splithttp' then + result.splithttp_host = params.host + result.splithttp_path = params.path + end result.encryption = params.encryption or "none" result.flow = params.flow or nil + if result.type == "sing-box" and (result.transport == "mkcp" or result.transport == "splithttp") then + log("跳过节点:" .. result.remarks ..",因Sing-Box不支持" .. szType .. "协议的" .. result.transport .. "传输方式,需更换Xray。") + return nil + end end elseif szType == "ssd" then @@ -971,6 +988,11 @@ local function processData(szType, content, add_mode, add_from) result.port = port result.tls_allowInsecure = allowInsecure_default and "1" or "0" + + if result.type == "sing-box" and (result.transport == "mkcp" or result.transport == "splithttp") then + log("跳过节点:" .. result.remarks ..",因Sing-Box不支持" .. szType .. "协议的" .. result.transport .. "传输方式,需更换Xray。") + return nil + end end elseif szType == 'hysteria' then local alias = "" diff --git a/small/luci-app-passwall/root/usr/share/passwall/subscribe.lua b/small/luci-app-passwall/root/usr/share/passwall/subscribe.lua index e423a67a13..4229d607dd 100755 --- a/small/luci-app-passwall/root/usr/share/passwall/subscribe.lua +++ b/small/luci-app-passwall/root/usr/share/passwall/subscribe.lua @@ -488,6 +488,10 @@ local function processData(szType, content, add_mode, add_from) if info.net == 'grpc' then result.grpc_serviceName = info.path end + if info.net == 'splithttp' then + result.splithttp_host = info.host + result.splithttp_path = info.path + end if not info.security then result.security = "auto" end if info.tls == "tls" or info.tls == "1" then result.tls = "1" @@ -496,6 +500,11 @@ local function processData(szType, content, add_mode, add_from) else result.tls = "0" end + + if result.type == "sing-box" and (result.transport == "mkcp" or result.transport == "splithttp") then + log("跳过节点:" .. result.remarks ..",因Sing-Box不支持" .. szType .. "协议的" .. result.transport .. "传输方式,需更换Xray。") + return nil + end elseif szType == "ss" then result.type = "SS" @@ -821,11 +830,19 @@ local function processData(szType, content, add_mode, add_from) if params.serviceName then result.grpc_serviceName = params.serviceName end result.grpc_mode = params.mode end + if params.type == 'splithttp' then + result.splithttp_host = params.host + result.splithttp_path = params.path + end result.encryption = params.encryption or "none" result.flow = params.flow or nil + if result.type == "sing-box" and (result.transport == "mkcp" or result.transport == "splithttp") then + log("跳过节点:" .. result.remarks ..",因Sing-Box不支持" .. szType .. "协议的" .. result.transport .. "传输方式,需更换Xray。") + return nil + end end elseif szType == "ssd" then @@ -971,6 +988,11 @@ local function processData(szType, content, add_mode, add_from) result.port = port result.tls_allowInsecure = allowInsecure_default and "1" or "0" + + if result.type == "sing-box" and (result.transport == "mkcp" or result.transport == "splithttp") then + log("跳过节点:" .. result.remarks ..",因Sing-Box不支持" .. szType .. "协议的" .. result.transport .. "传输方式,需更换Xray。") + return nil + end end elseif szType == 'hysteria' then local alias = "" diff --git a/small/v2ray-core/Makefile b/small/v2ray-core/Makefile index b2f471b953..2b06194c8e 100644 --- a/small/v2ray-core/Makefile +++ b/small/v2ray-core/Makefile @@ -5,12 +5,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=v2ray-core -PKG_VERSION:=5.16.1 +PKG_VERSION:=5.17.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/v2fly/v2ray-core/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=e5d61b97168ebdf6da3d672ab40abe5b22951d46997072ca1ee497a3aa47ba05 +PKG_HASH:=a321b60e215885393283a6e61c257b0d6218311acdb330dd9cb36726f2961e37 PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE diff --git a/small/v2ray-plugin/Makefile b/small/v2ray-plugin/Makefile index 71a869974b..702e5a011a 100644 --- a/small/v2ray-plugin/Makefile +++ b/small/v2ray-plugin/Makefile @@ -6,12 +6,12 @@ include $(TOPDIR)/rules.mk PKG_NAME:=v2ray-plugin -PKG_VERSION:=5.15.1 +PKG_VERSION:=5.17.0 PKG_RELEASE:=1 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz PKG_SOURCE_URL:=https://codeload.github.com/teddysun/v2ray-plugin/tar.gz/v$(PKG_VERSION)? -PKG_HASH:=833c2ee956ca054865ede20029a92b1eaf821c22cdbc5ec4ed4108e1f493ad1f +PKG_HASH:=035823fa70d0c7e6afa6cced6b9d6f8b29c05a5f28852ad5954e957b61337c9e PKG_LICENSE:=MIT PKG_LICENSE_FILES:=LICENSE diff --git a/v2ray-core/core.go b/v2ray-core/core.go index 1b8c4b8c78..e810c75d05 100644 --- a/v2ray-core/core.go +++ b/v2ray-core/core.go @@ -18,7 +18,7 @@ import ( ) var ( - version = "5.16.1" + version = "5.17.1" build = "Custom" codename = "V2Fly, a community-driven edition of V2Ray." intro = "A unified platform for anti-censorship." diff --git a/v2ray-core/transport/internet/request/assembler/packetconn/req2packet.go b/v2ray-core/transport/internet/request/assembler/packetconn/req2packet.go index baf12c366d..c8e7e881ad 100644 --- a/v2ray-core/transport/internet/request/assembler/packetconn/req2packet.go +++ b/v2ray-core/transport/internet/request/assembler/packetconn/req2packet.go @@ -5,6 +5,7 @@ import ( "context" "crypto/rand" "io" + "sync" "time" "github.com/golang-collections/go-datastructures/queue" @@ -102,7 +103,7 @@ copyFromChan: waitTimer.Stop() go func() { reader, writer := io.Pipe() - defer writer.Close() + defer writer.Close() streamingRespOpt := &pipedStreamingRespOption{writer} go func() { for { @@ -176,7 +177,7 @@ func (r *requestToPacketConnClientSession) Close() error { func newRequestToPacketConnServer(ctx context.Context, config *ServerConfig) *requestToPacketConnServer { return &requestToPacketConnServer{ - sessionMap: make(map[string]*requestToPacketConnServerSession), + sessionMap: sync.Map{}, ctx: ctx, config: config, } @@ -185,7 +186,7 @@ func newRequestToPacketConnServer(ctx context.Context, config *ServerConfig) *re type requestToPacketConnServer struct { packetSessionReceiver request.SessionReceiver - sessionMap map[string]*requestToPacketConnServerSession + sessionMap sync.Map ctx context.Context config *ServerConfig @@ -203,7 +204,15 @@ func (r *requestToPacketConnServer) OnRoundTrip(ctx context.Context, req request return request.Response{}, newError("nil session id") } sessionID := string(SessionID) - session, found := r.sessionMap[sessionID] + var session *requestToPacketConnServerSession + sessionAny, found := r.sessionMap.Load(sessionID) + if found { + var ok bool + session, ok = sessionAny.(*requestToPacketConnServerSession) + if !ok { + return request.Response{}, newError("failed to cast session") + } + } if !found { ctxWithFinish, finish := context.WithCancel(ctx) session = &requestToPacketConnServerSession{ @@ -218,8 +227,10 @@ func (r *requestToPacketConnServer) OnRoundTrip(ctx context.Context, req request maxWriteDuration: int(r.config.MaxWriteDurationMs), maxSimultaneousWriteConnection: int(r.config.MaxSimultaneousWriteConnection), } - r.sessionMap[sessionID] = session - err = r.packetSessionReceiver.OnNewSession(ctx, session) + _, loaded := r.sessionMap.LoadOrStore(sessionID, session) + if !loaded { + err = r.packetSessionReceiver.OnNewSession(ctx, session) + } } if err != nil { return request.Response{}, err @@ -228,7 +239,7 @@ func (r *requestToPacketConnServer) OnRoundTrip(ctx context.Context, req request } func (r *requestToPacketConnServer) removeSessionID(sessionID []byte) { - delete(r.sessionMap, string(sessionID)) + r.sessionMap.Delete(string(sessionID)) } type requestToPacketConnServerSession struct {