diff --git a/.github/update.log b/.github/update.log index 7c438888a3..3340f222ef 100644 --- a/.github/update.log +++ b/.github/update.log @@ -760,3 +760,4 @@ Update On Sat Sep 7 20:31:47 CEST 2024 Update On Sun Sep 8 20:32:53 CEST 2024 Update On Mon Sep 9 20:33:04 CEST 2024 Update On Tue Sep 10 20:33:27 CEST 2024 +Update On Wed Sep 11 20:35:20 CEST 2024 diff --git a/clash-meta-android/.github/workflows/update-dependencies.yaml b/clash-meta-android/.github/workflows/update-dependencies.yaml index dc7ce21f94..476489f649 100644 --- a/clash-meta-android/.github/workflows/update-dependencies.yaml +++ b/clash-meta-android/.github/workflows/update-dependencies.yaml @@ -34,10 +34,6 @@ jobs: key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} restore-keys: | ${{ runner.os }}-go- - - - name: Download GeoIP Database - run: | - ./gradlew :core:downloadGeoipDatabase - name: Install update-go-mod-replace run: | diff --git a/clash-meta-android/app/build.gradle.kts b/clash-meta-android/app/build.gradle.kts index 20f61121bc..3bd47e00a8 100644 --- a/clash-meta-android/app/build.gradle.kts +++ b/clash-meta-android/app/build.gradle.kts @@ -38,6 +38,7 @@ task("downloadGeoFiles") { "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geoip.metadb" to "geoip.metadb", "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/geosite.dat" to "geosite.dat", // "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/country.mmdb" to "country.mmdb", + "https://github.com/MetaCubeX/meta-rules-dat/releases/download/latest/GeoLite2-ASN.mmdb" to "ASN.mmdb", ) doLast { diff --git a/clash-meta-android/app/src/main/java/com/github/kr328/clash/MainApplication.kt b/clash-meta-android/app/src/main/java/com/github/kr328/clash/MainApplication.kt index 3cdfb5b508..7f4ddf74d9 100644 --- a/clash-meta-android/app/src/main/java/com/github/kr328/clash/MainApplication.kt +++ b/clash-meta-android/app/src/main/java/com/github/kr328/clash/MainApplication.kt @@ -54,6 +54,13 @@ class MainApplication : Application() { assets.open("geosite.dat").copyTo(it); } } + + val ASNFile = File(clashDir, "ASN.mmdb") + if(!ASNFile.exists()) { + FileOutputStream(ASNFile).use { + assets.open("ASN.mmdb").copyTo(it); + } + } } fun finalize() { diff --git a/clash-meta-android/app/src/main/java/com/github/kr328/clash/MetaFeatureSettingsActivity.kt b/clash-meta-android/app/src/main/java/com/github/kr328/clash/MetaFeatureSettingsActivity.kt index 29ebbcb3cc..913bc07e14 100644 --- a/clash-meta-android/app/src/main/java/com/github/kr328/clash/MetaFeatureSettingsActivity.kt +++ b/clash-meta-android/app/src/main/java/com/github/kr328/clash/MetaFeatureSettingsActivity.kt @@ -70,6 +70,12 @@ class MetaFeatureSettingsActivity : BaseActivity() { "*/*") importGeoFile(uri, MetaFeatureSettingsDesign.Request.ImportCountry) } + MetaFeatureSettingsDesign.Request.ImportASN -> { + val uri = startActivityForResult( + ActivityResultContracts.GetContent(), + "*/*") + importGeoFile(uri, MetaFeatureSettingsDesign.Request.ImportASN) + } } } } @@ -107,6 +113,8 @@ class MetaFeatureSettingsActivity : BaseActivity() { "geosite$ext" MetaFeatureSettingsDesign.Request.ImportCountry -> "country$ext" + MetaFeatureSettingsDesign.Request.ImportASN -> + "ASN$ext" else -> "" } diff --git a/clash-meta-android/app/src/main/java/com/github/kr328/clash/OverrideSettingsActivity.kt b/clash-meta-android/app/src/main/java/com/github/kr328/clash/OverrideSettingsActivity.kt index c1636c8664..b4641ed0de 100644 --- a/clash-meta-android/app/src/main/java/com/github/kr328/clash/OverrideSettingsActivity.kt +++ b/clash-meta-android/app/src/main/java/com/github/kr328/clash/OverrideSettingsActivity.kt @@ -45,45 +45,14 @@ class OverrideSettingsActivity : BaseActivity() { withClash { clearOverride(Clash.OverrideSlot.Persist) } - - service.sideloadGeoip = "" } finish() } } - OverrideSettingsDesign.Request.EditSideloadGeoip -> { - withContext(Dispatchers.IO) { - val list = querySideloadProviders() - val initial = service.sideloadGeoip - val exist = list.any { info -> info.packageName == initial } - - service.sideloadGeoip = - design.requestSelectSideload(if (exist) initial else "", list) - } - } } } } } } - - private fun querySideloadProviders(): List { - val apps = packageManager.getInstalledPackages(PackageManager.GET_META_DATA) - .filter { - it.applicationInfo.metaData?.containsKey(Metadata.GEOIP_FILE_NAME) - ?: false - } - .map { it.toAppInfo(packageManager) } - - return listOf( - AppInfo( - packageName = "", - label = getString(R.string.use_built_in), - icon = getDrawableCompat(R.drawable.ic_baseline_work)!!, - installTime = 0, - updateDate = 0, - ) - ) + apps - } } \ No newline at end of file diff --git a/clash-meta-android/core/build.gradle.kts b/clash-meta-android/core/build.gradle.kts index ed6dd2ad69..e50230aa10 100644 --- a/clash-meta-android/core/build.gradle.kts +++ b/clash-meta-android/core/build.gradle.kts @@ -11,10 +11,6 @@ plugins { id("golang-android") } -val geoipDatabaseUrl = - "https://raw.githubusercontent.com/Loyalsoldier/geoip/release/Country.mmdb" -val geoipInvalidate = Duration.ofDays(7)!! -val geoipOutput = buildDir.resolve("intermediates/golang_blob") val golangSource = file("src/main/golang/native") golang { @@ -66,52 +62,4 @@ afterEvaluate { tasks.withType(GolangBuildTask::class.java).forEach { it.inputs.dir(golangSource) } -} - -task("downloadGeoipDatabase") { - val databaseFile = geoipOutput.resolve("Country.mmdb") - val moduleFile = geoipOutput.resolve("go.mod") - val sourceFile = geoipOutput.resolve("blob.go") - - val moduleContent = """ - module "cfa/blob" - """.trimIndent() - - val sourceContent = """ - package blob - - import _ "embed" - - //go:embed Country.mmdb - var GeoipDatabase []byte - """.trimIndent() - - outputs.dir(geoipOutput) - - onlyIf { - System.currentTimeMillis() - databaseFile.lastModified() > geoipInvalidate.toMillis() - } - - doLast { - geoipOutput.mkdirs() - - moduleFile.writeText(moduleContent) - sourceFile.writeText(sourceContent) - - URL(geoipDatabaseUrl).openConnection().getInputStream().use { input -> - FileOutputStream(databaseFile).use { output -> - input.copyTo(output) - } - } - } -} - -afterEvaluate { - val downloadTask = tasks["downloadGeoipDatabase"] - - tasks.forEach { - if (it.name.startsWith("externalGolangBuild")) { - it.dependsOn(downloadTask) - } - } -} +} \ No newline at end of file diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go index edb6b9110a..0c606a9521 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/parser.go @@ -9,7 +9,6 @@ import ( "github.com/metacubex/mihomo/common/utils" "github.com/metacubex/mihomo/component/resource" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/constant/features" types "github.com/metacubex/mihomo/constant/provider" ) @@ -94,7 +93,7 @@ func ParseProxyProvider(name string, mapping map[string]any) (types.ProxyProvide path := C.Path.GetPathByHash("proxies", schema.URL) if schema.Path != "" { path = C.Path.Resolve(schema.Path) - if !features.CMFA && !C.Path.IsSafePath(path) { + if !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go index 107b621b41..5f86777cc4 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/provider.go @@ -18,7 +18,6 @@ import ( "github.com/metacubex/mihomo/component/resource" C "github.com/metacubex/mihomo/constant" types "github.com/metacubex/mihomo/constant/provider" - "github.com/metacubex/mihomo/log" "github.com/metacubex/mihomo/tunnel/statistic" "github.com/dlclark/regexp2" @@ -149,10 +148,7 @@ func (pp *proxySetProvider) getSubscriptionInfo() { return } } - pp.subscriptionInfo, err = NewSubscriptionInfo(userInfoStr) - if err != nil { - log.Warnln("[Provider] get subscription-userinfo: %e", err) - } + pp.subscriptionInfo = NewSubscriptionInfo(userInfoStr) }() } diff --git a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/subscription_info.go b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/subscription_info.go index 3a9e2d72c7..b72c7b6161 100644 --- a/clash-meta-android/core/src/foss/golang/clash/adapter/provider/subscription_info.go +++ b/clash-meta-android/core/src/foss/golang/clash/adapter/provider/subscription_info.go @@ -1,8 +1,11 @@ package provider import ( + "fmt" "strconv" "strings" + + "github.com/metacubex/mihomo/log" ) type SubscriptionInfo struct { @@ -12,28 +15,46 @@ type SubscriptionInfo struct { Expire int64 } -func NewSubscriptionInfo(userinfo string) (si *SubscriptionInfo, err error) { +func NewSubscriptionInfo(userinfo string) (si *SubscriptionInfo) { userinfo = strings.ToLower(userinfo) userinfo = strings.ReplaceAll(userinfo, " ", "") si = new(SubscriptionInfo) + for _, field := range strings.Split(userinfo, ";") { - switch name, value, _ := strings.Cut(field, "="); name { - case "upload": - si.Upload, err = strconv.ParseInt(value, 10, 64) - case "download": - si.Download, err = strconv.ParseInt(value, 10, 64) - case "total": - si.Total, err = strconv.ParseInt(value, 10, 64) - case "expire": - if value == "" { - si.Expire = 0 - } else { - si.Expire, err = strconv.ParseInt(value, 10, 64) - } + name, value, ok := strings.Cut(field, "=") + if !ok { + continue } + + intValue, err := parseValue(value) if err != nil { - return + log.Warnln("[Provider] get subscription-userinfo: %e", err) + continue + } + + switch name { + case "upload": + si.Upload = intValue + case "download": + si.Download = intValue + case "total": + si.Total = intValue + case "expire": + si.Expire = intValue } } - return + + return si +} + +func parseValue(value string) (int64, error) { + if intValue, err := strconv.ParseInt(value, 10, 64); err == nil { + return intValue, nil + } + + if floatValue, err := strconv.ParseFloat(value, 64); err == nil { + return int64(floatValue), nil + } + + return 0, fmt.Errorf("failed to parse value '%s'", value) } diff --git a/clash-meta-android/core/src/foss/golang/clash/common/arc/arc.go b/clash-meta-android/core/src/foss/golang/clash/common/arc/arc.go index da78b1c1a0..8d44a180a7 100644 --- a/clash-meta-android/core/src/foss/golang/clash/common/arc/arc.go +++ b/clash-meta-android/core/src/foss/golang/clash/common/arc/arc.go @@ -33,15 +33,8 @@ type ARC[K comparable, V any] struct { // New returns a new Adaptive Replacement Cache (ARC). func New[K comparable, V any](options ...Option[K, V]) *ARC[K, V] { - arc := &ARC[K, V]{ - p: 0, - t1: list.New[*entry[K, V]](), - b1: list.New[*entry[K, V]](), - t2: list.New[*entry[K, V]](), - b2: list.New[*entry[K, V]](), - len: 0, - cache: make(map[K]*entry[K, V]), - } + arc := &ARC[K, V]{} + arc.Clear() for _, option := range options { option(arc) @@ -49,6 +42,19 @@ func New[K comparable, V any](options ...Option[K, V]) *ARC[K, V] { return arc } +func (a *ARC[K, V]) Clear() { + a.mutex.Lock() + defer a.mutex.Unlock() + + a.p = 0 + a.t1 = list.New[*entry[K, V]]() + a.b1 = list.New[*entry[K, V]]() + a.t2 = list.New[*entry[K, V]]() + a.b2 = list.New[*entry[K, V]]() + a.len = 0 + a.cache = make(map[K]*entry[K, V]) +} + // Set inserts a new key-value pair into the cache. // This optimizes future access to this entry (side effect). func (a *ARC[K, V]) Set(key K, value V) { diff --git a/clash-meta-android/core/src/foss/golang/clash/common/lru/lrucache.go b/clash-meta-android/core/src/foss/golang/clash/common/lru/lrucache.go index 35f605b10c..4afe8e0c35 100644 --- a/clash-meta-android/core/src/foss/golang/clash/common/lru/lrucache.go +++ b/clash-meta-android/core/src/foss/golang/clash/common/lru/lrucache.go @@ -68,10 +68,8 @@ type LruCache[K comparable, V any] struct { // New creates an LruCache func New[K comparable, V any](options ...Option[K, V]) *LruCache[K, V] { - lc := &LruCache[K, V]{ - lru: list.New[*entry[K, V]](), - cache: make(map[K]*list.Element[*entry[K, V]]), - } + lc := &LruCache[K, V]{} + lc.Clear() for _, option := range options { option(lc) @@ -80,6 +78,14 @@ func New[K comparable, V any](options ...Option[K, V]) *LruCache[K, V] { return lc } +func (c *LruCache[K, V]) Clear() { + c.mu.Lock() + defer c.mu.Unlock() + + c.lru = list.New[*entry[K, V]]() + c.cache = make(map[K]*list.Element[*entry[K, V]]) +} + // Get returns any representation of a cached response and a bool // set to true if the key was found. func (c *LruCache[K, V]) Get(key K) (V, bool) { @@ -250,15 +256,6 @@ func (c *LruCache[K, V]) deleteElement(le *list.Element[*entry[K, V]]) { } } -func (c *LruCache[K, V]) Clear() error { - c.mu.Lock() - defer c.mu.Unlock() - - c.cache = make(map[K]*list.Element[*entry[K, V]]) - - return nil -} - // Compute either sets the computed new value for the key or deletes // the value for the key. When the delete result of the valueFn function // is set to true, the value will be deleted, if it exists. When delete diff --git a/clash-meta-android/core/src/foss/golang/clash/component/fakeip/memory.go b/clash-meta-android/core/src/foss/golang/clash/component/fakeip/memory.go index 00eff81015..0a8492f8aa 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/fakeip/memory.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/fakeip/memory.go @@ -67,8 +67,9 @@ func (m *memoryStore) CloneTo(store store) { // FlushFakeIP implements store.FlushFakeIP func (m *memoryStore) FlushFakeIP() error { - _ = m.cacheIP.Clear() - return m.cacheHost.Clear() + m.cacheIP.Clear() + m.cacheHost.Clear() + return nil } func newMemoryStore(size int) *memoryStore { diff --git a/clash-meta-android/core/src/foss/golang/clash/component/mmdb/patch_android.go b/clash-meta-android/core/src/foss/golang/clash/component/mmdb/patch_android.go deleted file mode 100644 index dfa96cacbd..0000000000 --- a/clash-meta-android/core/src/foss/golang/clash/component/mmdb/patch_android.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build android && cmfa - -package mmdb - -import "github.com/oschwald/maxminddb-golang" - -func InstallOverride(override *maxminddb.Reader) { - newReader := IPReader{Reader: override} - switch override.Metadata.DatabaseType { - case "sing-geoip": - ipReader.databaseType = typeSing - case "Meta-geoip0": - ipReader.databaseType = typeMetaV0 - default: - ipReader.databaseType = typeMaxmind - } - ipReader = newReader -} diff --git a/clash-meta-android/core/src/foss/golang/clash/component/resolver/resolver.go b/clash-meta-android/core/src/foss/golang/clash/component/resolver/resolver.go index 07c68824c3..feb3f98fb5 100644 --- a/clash-meta-android/core/src/foss/golang/clash/component/resolver/resolver.go +++ b/clash-meta-android/core/src/foss/golang/clash/component/resolver/resolver.go @@ -46,6 +46,7 @@ type Resolver interface { LookupIPv6(ctx context.Context, host string) (ips []netip.Addr, err error) ExchangeContext(ctx context.Context, m *dns.Msg) (msg *dns.Msg, err error) Invalid() bool + ClearCache() } // LookupIPv4WithResolver same as LookupIPv4, but with a resolver diff --git a/clash-meta-android/core/src/foss/golang/clash/config/config.go b/clash-meta-android/core/src/foss/golang/clash/config/config.go index 26518758ef..0af30b3989 100644 --- a/clash-meta-android/core/src/foss/golang/clash/config/config.go +++ b/clash-meta-android/core/src/foss/golang/clash/config/config.go @@ -30,7 +30,6 @@ import ( "github.com/metacubex/mihomo/component/trie" "github.com/metacubex/mihomo/component/updater" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/constant/features" providerTypes "github.com/metacubex/mihomo/constant/provider" snifferTypes "github.com/metacubex/mihomo/constant/sniffer" "github.com/metacubex/mihomo/dns" @@ -649,7 +648,7 @@ func ParseRawConfig(rawCfg *RawConfig) (*Config, error) { config.DNS = dnsCfg err = parseTun(rawCfg.Tun, config.General) - if !features.CMFA && err != nil { + if err != nil { return nil, err } diff --git a/clash-meta-android/core/src/foss/golang/clash/constant/path.go b/clash-meta-android/core/src/foss/golang/clash/constant/path.go index 77f7d0ef0a..0227937181 100644 --- a/clash-meta-android/core/src/foss/golang/clash/constant/path.go +++ b/clash-meta-android/core/src/foss/golang/clash/constant/path.go @@ -8,6 +8,8 @@ import ( "path/filepath" "strconv" "strings" + + "github.com/metacubex/mihomo/constant/features" ) const Name = "mihomo" @@ -73,7 +75,7 @@ func (p *path) Resolve(path string) string { // IsSafePath return true if path is a subpath of homedir func (p *path) IsSafePath(path string) bool { - if p.allowUnsafePath { + if p.allowUnsafePath || features.CMFA { return true } homedir := p.HomeDir() diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/dhcp.go b/clash-meta-android/core/src/foss/golang/clash/dns/dhcp.go index d4944a9600..dc1344f500 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/dhcp.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/dhcp.go @@ -1,5 +1,3 @@ -//go:build !(android && cmfa) - package dns import ( diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/doh.go b/clash-meta-android/core/src/foss/golang/clash/dns/doh.go index 97e01ea720..ffb65fcef0 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/doh.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/doh.go @@ -9,6 +9,7 @@ import ( "io" "net" "net/http" + "net/netip" "net/url" "runtime" "strconv" @@ -67,6 +68,8 @@ type dnsOverHTTPS struct { dialer *dnsDialer addr string skipCertVerify bool + ecsPrefix netip.Prefix + ecsOverride bool } // type check @@ -99,6 +102,28 @@ func newDoHClient(urlString string, r *Resolver, preferH3 bool, params map[strin doh.skipCertVerify = true } + if ecs := params["ecs"]; ecs != "" { + prefix, err := netip.ParsePrefix(ecs) + if err != nil { + addr, err := netip.ParseAddr(ecs) + if err != nil { + log.Warnln("DOH [%s] config with invalid ecs: %s", doh.addr, ecs) + } else { + doh.ecsPrefix = netip.PrefixFrom(addr, addr.BitLen()) + } + } else { + doh.ecsPrefix = prefix + } + } + + if doh.ecsPrefix.IsValid() { + log.Debugln("DOH [%s] config with ecs: %s", doh.addr, doh.ecsPrefix) + } + + if params["ecs-override"] == "true" { + doh.ecsOverride = true + } + runtime.SetFinalizer(doh, (*dnsOverHTTPS).Close) return doh @@ -126,6 +151,10 @@ func (doh *dnsOverHTTPS) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D. } }() + if doh.ecsPrefix.IsValid() { + setEdns0Subnet(m, doh.ecsPrefix, doh.ecsOverride) + } + // Check if there was already an active client before sending the request. // We'll only attempt to re-connect if there was one. client, isCached, err := doh.getClient(ctx) diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/edns0_subnet.go b/clash-meta-android/core/src/foss/golang/clash/dns/edns0_subnet.go new file mode 100644 index 0000000000..2ed4f140b5 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/dns/edns0_subnet.go @@ -0,0 +1,51 @@ +package dns + +import ( + "net/netip" + + "github.com/miekg/dns" +) + +func setEdns0Subnet(message *dns.Msg, clientSubnet netip.Prefix, override bool) bool { + var ( + optRecord *dns.OPT + subnetOption *dns.EDNS0_SUBNET + ) +findExists: + for _, record := range message.Extra { + var isOPTRecord bool + if optRecord, isOPTRecord = record.(*dns.OPT); isOPTRecord { + for _, option := range optRecord.Option { + var isEDNS0Subnet bool + if subnetOption, isEDNS0Subnet = option.(*dns.EDNS0_SUBNET); isEDNS0Subnet { + if !override { + return false + } + break findExists + } + } + } + } + if optRecord == nil { + optRecord = &dns.OPT{ + Hdr: dns.RR_Header{ + Name: ".", + Rrtype: dns.TypeOPT, + }, + } + message.Extra = append(message.Extra, optRecord) + } + if subnetOption == nil { + subnetOption = new(dns.EDNS0_SUBNET) + optRecord.Option = append(optRecord.Option, subnetOption) + } + subnetOption.Code = dns.EDNS0SUBNET + if clientSubnet.Addr().Is4() { + subnetOption.Family = 1 + } else { + subnetOption.Family = 2 + } + subnetOption.SourceNetmask = uint8(clientSubnet.Bits()) + subnetOption.Address = clientSubnet.Addr().AsSlice() + return true +} diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/patch_android.go b/clash-meta-android/core/src/foss/golang/clash/dns/patch_android.go index e62aabcdfc..386680e773 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/patch_android.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/patch_android.go @@ -3,53 +3,16 @@ package dns import ( - "context" - - D "github.com/miekg/dns" - - "github.com/metacubex/mihomo/common/lru" - "github.com/metacubex/mihomo/component/dhcp" "github.com/metacubex/mihomo/component/resolver" ) const SystemDNSPlaceholder = "system" -var systemResolver *Resolver -var isolateHandler handler - -var _ dnsClient = (*dhcpClient)(nil) - -type dhcpClient struct { - enable bool -} - -func (d *dhcpClient) Address() string { - return SystemDNSPlaceholder -} - -func (d *dhcpClient) Exchange(m *D.Msg) (msg *D.Msg, err error) { - return d.ExchangeContext(context.Background(), m) -} - -func (d *dhcpClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { - if s := systemResolver; s != nil { - return s.ExchangeContext(ctx, m) - } - - return nil, dhcp.ErrNotFound -} - -func ServeDNSWithDefaultServer(msg *D.Msg) (*D.Msg, error) { - if h := isolateHandler; h != nil { - return handlerWithContext(context.Background(), h, msg) - } - - return nil, D.ErrTime -} +var systemResolver []dnsClient func FlushCacheWithDefaultResolver() { if r := resolver.DefaultResolver; r != nil { - r.(*Resolver).cache = lru.New(lru.WithSize[string, *D.Msg](4096), lru.WithStale[string, *D.Msg](true)) + r.ClearCache() } } @@ -63,19 +26,9 @@ func UpdateSystemDNS(addr []string) { ns = append(ns, NameServer{Addr: d}) } - systemResolver = NewResolver(Config{Main: ns}) + systemResolver = transform(ns, nil) } -func UpdateIsolateHandler(resolver *Resolver, mapper *ResolverEnhancer) { - if resolver == nil { - isolateHandler = nil - - return - } - - isolateHandler = NewHandler(resolver, mapper) -} - -func newDHCPClient(ifaceName string) *dhcpClient { - return &dhcpClient{enable: ifaceName == SystemDNSPlaceholder} +func (c *systemClient) getDnsClients() ([]dnsClient, error) { + return systemResolver, nil } diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/patch_common.go b/clash-meta-android/core/src/foss/golang/clash/dns/patch_common.go deleted file mode 100644 index fae1e1265f..0000000000 --- a/clash-meta-android/core/src/foss/golang/clash/dns/patch_common.go +++ /dev/null @@ -1,6 +0,0 @@ -//go:build !(android && cmfa) - -package dns - -func UpdateIsolateHandler(resolver *Resolver, mapper *ResolverEnhancer) { -} diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go b/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go index 232f3b3367..e03feef46f 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/resolver.go @@ -29,6 +29,7 @@ type dnsClient interface { type dnsCache interface { GetWithExpire(key string) (*D.Msg, time.Time, bool) SetWithExpire(key string, value *D.Msg, expire time.Time) + Clear() } type result struct { @@ -369,6 +370,12 @@ func (r *Resolver) Invalid() bool { return len(r.main) > 0 } +func (r *Resolver) ClearCache() { + if r != nil && r.cache != nil { + r.cache.Clear() + } +} + type NameServer struct { Net string Addr string diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/server.go b/clash-meta-android/core/src/foss/golang/clash/dns/server.go index d45fb5ebad..1cf58d4d8a 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/server.go @@ -6,7 +6,6 @@ import ( "net" "github.com/metacubex/mihomo/common/sockopt" - "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/context" "github.com/metacubex/mihomo/log" @@ -50,10 +49,6 @@ func (s *Server) SetHandler(handler handler) { } func ReCreateServer(addr string, resolver *Resolver, mapper *ResolverEnhancer) { - if features.CMFA { - UpdateIsolateHandler(resolver, mapper) - } - if addr == address && resolver != nil { handler := NewHandler(resolver, mapper) server.SetHandler(handler) diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/system.go b/clash-meta-android/core/src/foss/golang/clash/dns/system.go index dc1006fa56..944f2824c2 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/system.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/system.go @@ -3,16 +3,11 @@ package dns import ( "context" "fmt" - "net" "strings" "sync" "time" - "github.com/metacubex/mihomo/component/resolver" - "github.com/metacubex/mihomo/log" - D "github.com/miekg/dns" - "golang.org/x/exp/slices" ) const ( @@ -31,64 +26,6 @@ type systemClient struct { lastFlush time.Time } -func (c *systemClient) getDnsClients() ([]dnsClient, error) { - c.mu.Lock() - defer c.mu.Unlock() - var err error - if time.Since(c.lastFlush) > SystemDnsFlushTime { - var nameservers []string - if nameservers, err = dnsReadConfig(); err == nil { - log.Debugln("[DNS] system dns update to %s", nameservers) - for _, addr := range nameservers { - if resolver.IsSystemDnsBlacklisted(addr) { - continue - } - if _, ok := c.dnsClients[addr]; !ok { - clients := transform( - []NameServer{{ - Addr: net.JoinHostPort(addr, "53"), - Net: "udp", - }}, - nil, - ) - if len(clients) > 0 { - c.dnsClients[addr] = &systemDnsClient{ - disableTimes: 0, - dnsClient: clients[0], - } - } - } - } - available := 0 - for nameserver, sdc := range c.dnsClients { - if slices.Contains(nameservers, nameserver) { - sdc.disableTimes = 0 // enable - available++ - } else { - if sdc.disableTimes > SystemDnsDeleteTimes { - delete(c.dnsClients, nameserver) // drop too old dnsClient - } else { - sdc.disableTimes++ - } - } - } - if available > 0 { - c.lastFlush = time.Now() - } - } - } - dnsClients := make([]dnsClient, 0, len(c.dnsClients)) - for _, sdc := range c.dnsClients { - if sdc.disableTimes == 0 { - dnsClients = append(dnsClients, sdc.dnsClient) - } - } - if len(dnsClients) > 0 { - return dnsClients, nil - } - return nil, err -} - func (c *systemClient) ExchangeContext(ctx context.Context, m *D.Msg) (msg *D.Msg, err error) { dnsClients, err := c.getDnsClients() if err != nil { diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/system_common.go b/clash-meta-android/core/src/foss/golang/clash/dns/system_common.go new file mode 100644 index 0000000000..06dc0b3020 --- /dev/null +++ b/clash-meta-android/core/src/foss/golang/clash/dns/system_common.go @@ -0,0 +1,71 @@ +//go:build !(android && cmfa) + +package dns + +import ( + "net" + "time" + + "github.com/metacubex/mihomo/component/resolver" + "github.com/metacubex/mihomo/log" + + "golang.org/x/exp/slices" +) + +func (c *systemClient) getDnsClients() ([]dnsClient, error) { + c.mu.Lock() + defer c.mu.Unlock() + var err error + if time.Since(c.lastFlush) > SystemDnsFlushTime { + var nameservers []string + if nameservers, err = dnsReadConfig(); err == nil { + log.Debugln("[DNS] system dns update to %s", nameservers) + for _, addr := range nameservers { + if resolver.IsSystemDnsBlacklisted(addr) { + continue + } + if _, ok := c.dnsClients[addr]; !ok { + clients := transform( + []NameServer{{ + Addr: net.JoinHostPort(addr, "53"), + Net: "udp", + }}, + nil, + ) + if len(clients) > 0 { + c.dnsClients[addr] = &systemDnsClient{ + disableTimes: 0, + dnsClient: clients[0], + } + } + } + } + available := 0 + for nameserver, sdc := range c.dnsClients { + if slices.Contains(nameservers, nameserver) { + sdc.disableTimes = 0 // enable + available++ + } else { + if sdc.disableTimes > SystemDnsDeleteTimes { + delete(c.dnsClients, nameserver) // drop too old dnsClient + } else { + sdc.disableTimes++ + } + } + } + if available > 0 { + c.lastFlush = time.Now() + } + } + } + dnsClients := make([]dnsClient, 0, len(c.dnsClients)) + for _, sdc := range c.dnsClients { + if sdc.disableTimes == 0 { + dnsClients = append(dnsClients, sdc.dnsClient) + } + } + if len(dnsClients) > 0 { + return dnsClients, nil + } + return nil, err +} diff --git a/clash-meta-android/core/src/foss/golang/clash/dns/util.go b/clash-meta-android/core/src/foss/golang/clash/dns/util.go index 50459cc120..92a86dbc2b 100644 --- a/clash-meta-android/core/src/foss/golang/clash/dns/util.go +++ b/clash-meta-android/core/src/foss/golang/clash/dns/util.go @@ -99,6 +99,10 @@ func transform(servers []NameServer, resolver *Resolver) []dnsClient { ret = append(ret, newDoHClient(s.Addr, resolver, s.PreferH3, s.Params, s.ProxyAdapter, s.ProxyName)) continue case "dhcp": + if s.Addr == "system" { // Compatible with old writing + ret = append(ret, newSystemClient()) + continue + } ret = append(ret, newDHCPClient(s.Addr)) continue case "system": diff --git a/clash-meta-android/core/src/foss/golang/clash/hub/hub.go b/clash-meta-android/core/src/foss/golang/clash/hub/hub.go index 04662a7b68..e22f721970 100644 --- a/clash-meta-android/core/src/foss/golang/clash/hub/hub.go +++ b/clash-meta-android/core/src/foss/golang/clash/hub/hub.go @@ -1,10 +1,7 @@ package hub import ( - "strings" - "github.com/metacubex/mihomo/config" - "github.com/metacubex/mihomo/constant/features" "github.com/metacubex/mihomo/hub/executor" "github.com/metacubex/mihomo/hub/route" "github.com/metacubex/mihomo/log" @@ -43,11 +40,6 @@ func ApplyConfig(cfg *config.Config) { } func applyRoute(cfg *config.Config) { - if features.CMFA && strings.HasSuffix(cfg.Controller.ExternalUI, ":0") { - // CMFA have set its default override value to end with ":0" for security. - // so we direct return at here - return - } if cfg.Controller.ExternalUI != "" { route.SetUIPath(cfg.Controller.ExternalUI) } diff --git a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go index e843eae824..a135a30192 100644 --- a/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go +++ b/clash-meta-android/core/src/foss/golang/clash/listener/sing_tun/server.go @@ -132,13 +132,12 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis if options.GSOMaxSize == 0 { options.GSOMaxSize = 65536 } - if !supportRedirect || !options.AutoRoute { + if !supportRedirect { options.AutoRedirect = false } tunName := options.Device - if tunName == "" || !checkTunName(tunName) { + if options.FileDescriptor == 0 && (tunName == "" || !checkTunName(tunName)) { tunName = CalculateInterfaceName(InterfaceName) - options.Device = tunName } routeAddress := options.RouteAddress if len(options.Inet4RouteAddress) > 0 { @@ -266,7 +265,7 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis var networkUpdateMonitor tun.NetworkUpdateMonitor var defaultInterfaceMonitor tun.DefaultInterfaceMonitor - if options.AutoRoute { // don't start NetworkUpdateMonitor because netlink banned by google on Android14+ + if options.AutoRoute || options.AutoDetectInterface { // don't start NetworkUpdateMonitor because netlink banned by google on Android14+ networkUpdateMonitor, err = tun.NewNetworkUpdateMonitor(log.SingLogger) if err != nil { err = E.Cause(err, "create NetworkUpdateMonitor") @@ -440,6 +439,9 @@ func New(options LC.Tun, tunnel C.Tunnel, additions ...inbound.Addition) (l *Lis //l.openAndroidHotspot(tunOptions) + if options.FileDescriptor != 0 { + tunName = fmt.Sprintf("%s(fd=%d)", tunName, options.FileDescriptor) + } l.addrStr = fmt.Sprintf("%s(%s,%s), mtu: %d, auto route: %v, auto redir: %v, ip stack: %s", tunName, tunOptions.Inet4Address, tunOptions.Inet6Address, tunMTU, options.AutoRoute, options.AutoRedirect, options.Stack) return diff --git a/clash-meta-android/core/src/foss/golang/clash/rules/provider/parse.go b/clash-meta-android/core/src/foss/golang/clash/rules/provider/parse.go index 227debb3a0..b3c6af3cbf 100644 --- a/clash-meta-android/core/src/foss/golang/clash/rules/provider/parse.go +++ b/clash-meta-android/core/src/foss/golang/clash/rules/provider/parse.go @@ -8,7 +8,6 @@ import ( "github.com/metacubex/mihomo/common/structure" "github.com/metacubex/mihomo/component/resource" C "github.com/metacubex/mihomo/constant" - "github.com/metacubex/mihomo/constant/features" P "github.com/metacubex/mihomo/constant/provider" ) @@ -50,7 +49,7 @@ func ParseRuleProvider(name string, mapping map[string]interface{}, parse func(t path := C.Path.GetPathByHash("rules", schema.URL) if schema.Path != "" { path = C.Path.Resolve(schema.Path) - if !features.CMFA && !C.Path.IsSafePath(path) { + if !C.Path.IsSafePath(path) { return nil, fmt.Errorf("%w: %s", errSubPath, path) } } diff --git a/clash-meta-android/core/src/foss/golang/go.mod b/clash-meta-android/core/src/foss/golang/go.mod index a4af5078f8..6a00af12a1 100644 --- a/clash-meta-android/core/src/foss/golang/go.mod +++ b/clash-meta-android/core/src/foss/golang/go.mod @@ -4,8 +4,6 @@ go 1.20 require cfa v0.0.0 -require cfa/blob v0.0.0-00010101000000-000000000000 // indirect - require ( github.com/3andne/restls-client-go v0.1.6 // indirect github.com/RyuaNerin/go-krypto v1.2.4 // indirect @@ -115,5 +113,3 @@ replace github.com/sagernet/sing => github.com/metacubex/sing v0.0.0-20240724044 replace cfa => ../../main/golang replace github.com/metacubex/mihomo => ./clash - -replace cfa/blob => ../../../build/intermediates/golang_blob diff --git a/clash-meta-android/core/src/main/cpp/main.c b/clash-meta-android/core/src/main/cpp/main.c index a836a0e155..2ad3f71788 100644 --- a/clash-meta-android/core/src/main/cpp/main.c +++ b/clash-meta-android/core/src/main/cpp/main.c @@ -111,18 +111,20 @@ Java_com_github_kr328_clash_core_bridge_Bridge_nativeNotifyInstalledAppChanged(J JNIEXPORT void JNICALL Java_com_github_kr328_clash_core_bridge_Bridge_nativeStartTun(JNIEnv *env, jobject thiz, jint fd, + jstring stack, jstring gateway, jstring portal, jstring dns, jobject cb) { TRACE_METHOD(); + scoped_string _stack = get_string(stack); scoped_string _gateway = get_string(gateway); scoped_string _portal = get_string(portal); scoped_string _dns = get_string(dns); jobject _interface = new_global(cb); - startTun(fd, _gateway, _portal, _dns, _interface); + startTun(fd, _stack, _gateway, _portal, _dns, _interface); } JNIEXPORT void JNICALL @@ -287,33 +289,6 @@ Java_com_github_kr328_clash_core_bridge_Bridge_nativeClearOverride(JNIEnv *env, clearOverride(slot); } -JNIEXPORT void JNICALL -Java_com_github_kr328_clash_core_bridge_Bridge_nativeInstallSideloadGeoip(JNIEnv *env, jobject thiz, - jbyteArray data) { - TRACE_METHOD(); - - if (data == NULL) { - installSideloadGeoip(NULL, 0); - - return; - } - - jbyte *bytes = (*env)->GetByteArrayElements(env, data, NULL); - int size = (*env)->GetArrayLength(env, data); - - scoped_string err = installSideloadGeoip(bytes, size); - - (*env)->ReleaseByteArrayElements(env, data, bytes, JNI_ABORT); - - if (err != NULL) { - (*env)->ThrowNew( - env, - find_class("com/github/kr328/clash/core/bridge/ClashException"), - err - ); - } -} - JNIEXPORT jstring JNICALL Java_com_github_kr328_clash_core_bridge_Bridge_nativeQueryConfiguration(JNIEnv *env, jobject thiz) { TRACE_METHOD(); diff --git a/clash-meta-android/core/src/main/golang/.idea/codeStyles/Project.xml b/clash-meta-android/core/src/main/golang/.idea/codeStyles/Project.xml index bbba885ff1..235439ed29 100644 --- a/clash-meta-android/core/src/main/golang/.idea/codeStyles/Project.xml +++ b/clash-meta-android/core/src/main/golang/.idea/codeStyles/Project.xml @@ -5,7 +5,6 @@