diff --git a/app/src/main/java/com/github/kr328/clash/remote/Broadcasts.kt b/app/src/main/java/com/github/kr328/clash/remote/Broadcasts.kt index 9be7026bf5..ac3924ba13 100644 --- a/app/src/main/java/com/github/kr328/clash/remote/Broadcasts.kt +++ b/app/src/main/java/com/github/kr328/clash/remote/Broadcasts.kt @@ -7,6 +7,7 @@ import android.content.Intent import android.content.IntentFilter import com.github.kr328.clash.common.compat.registerReceiverCompat import com.github.kr328.clash.common.constants.Intents +import com.github.kr328.clash.common.constants.Permissions import com.github.kr328.clash.common.log.Log import java.util.* @@ -59,12 +60,16 @@ class Broadcasts(private val context: Application) { Intents.ACTION_PROFILE_UPDATE_COMPLETED -> receivers.forEach { it.onProfileUpdateCompleted( - UUID.fromString(intent.getStringExtra(Intents.EXTRA_UUID))) + intent.getStringExtra(Intents.EXTRA_UUID)?.let { + runCatching { UUID.fromString(it) }.getOrNull() + }) } Intents.ACTION_PROFILE_UPDATE_FAILED -> receivers.forEach { it.onProfileUpdateFailed( - UUID.fromString(intent.getStringExtra(Intents.EXTRA_UUID)), + intent.getStringExtra(Intents.EXTRA_UUID)?.let { + runCatching { UUID.fromString(it) }.getOrNull() + }, intent.getStringExtra(Intents.EXTRA_FAIL_REASON)) } Intents.ACTION_PROFILE_LOADED -> { @@ -89,15 +94,20 @@ class Broadcasts(private val context: Application) { return try { - context.registerReceiverCompat(broadcastReceiver, IntentFilter().apply { - addAction(Intents.ACTION_SERVICE_RECREATED) - addAction(Intents.ACTION_CLASH_STARTED) - addAction(Intents.ACTION_CLASH_STOPPED) - addAction(Intents.ACTION_PROFILE_CHANGED) - addAction(Intents.ACTION_PROFILE_UPDATE_COMPLETED) - addAction(Intents.ACTION_PROFILE_UPDATE_FAILED) - addAction(Intents.ACTION_PROFILE_LOADED) - }) + context.registerReceiverCompat( + broadcastReceiver, + IntentFilter().apply { + addAction(Intents.ACTION_SERVICE_RECREATED) + addAction(Intents.ACTION_CLASH_STARTED) + addAction(Intents.ACTION_CLASH_STOPPED) + addAction(Intents.ACTION_PROFILE_CHANGED) + addAction(Intents.ACTION_PROFILE_UPDATE_COMPLETED) + addAction(Intents.ACTION_PROFILE_UPDATE_FAILED) + addAction(Intents.ACTION_PROFILE_LOADED) + }, + Permissions.RECEIVE_SELF_BROADCASTS, + null, + ) clashRunning = StatusClient(context).currentProfile() != null } catch (e: Exception) { @@ -117,4 +127,4 @@ class Broadcasts(private val context: Application) { Log.w("Unregister global receiver: $e", e) } } -} \ No newline at end of file +} diff --git a/core/src/main/golang/native/config/process.go b/core/src/main/golang/native/config/process.go index 0b60b1c520..b88ec64898 100644 --- a/core/src/main/golang/native/config/process.go +++ b/core/src/main/golang/native/config/process.go @@ -44,6 +44,11 @@ func patchOverride(cfg *config.RawConfig, _ string) error { func patchExternalController(cfg *config.RawConfig, _ string) error { cfg.ExternalController = "" cfg.ExternalControllerTLS = "" + cfg.ExternalControllerUnix = "" + cfg.ExternalControllerPipe = "" + cfg.ExternalControllerCors = config.RawCors{} + cfg.Secret = "" + cfg.DNS.Listen = "" return nil } diff --git a/core/src/main/golang/native/config/process_test.go b/core/src/main/golang/native/config/process_test.go new file mode 100644 index 0000000000..95b4cdc6d3 --- /dev/null +++ b/core/src/main/golang/native/config/process_test.go @@ -0,0 +1,85 @@ +package config + +import ( + "testing" + + mihomoConfig "github.com/metacubex/mihomo/config" +) + +func TestPatchExternalControllerStripsProfileSecurityState(t *testing.T) { + cfg := &mihomoConfig.RawConfig{ + ExternalController: "0.0.0.0:9090", + ExternalControllerTLS: "0.0.0.0:9443", + ExternalControllerUnix: "/data/local/tmp/clash.sock", + ExternalControllerPipe: "clash-pipe", + ExternalControllerCors: mihomoConfig.RawCors{ + AllowOrigins: []string{"https://attacker.example"}, + AllowPrivateNetwork: true, + }, + Secret: "profile-controlled-secret", + DNS: mihomoConfig.RawDNS{ + Enable: true, + Listen: ":1053", + }, + } + + if err := patchExternalController(cfg, ""); err != nil { + t.Fatalf("patchExternalController failed: %v", err) + } + + if cfg.ExternalController != "" || cfg.ExternalControllerTLS != "" || + cfg.ExternalControllerUnix != "" || cfg.ExternalControllerPipe != "" { + t.Fatal("profile-controlled external controller endpoint was preserved") + } + if len(cfg.ExternalControllerCors.AllowOrigins) != 0 || cfg.ExternalControllerCors.AllowPrivateNetwork { + t.Fatal("profile-controlled external controller CORS was preserved") + } + if cfg.Secret != "" { + t.Fatal("profile-controlled external controller secret was preserved") + } + if cfg.DNS.Listen != "" { + t.Fatal("profile-controlled DNS listener was preserved") + } +} + +func TestPatchOverrideCanRestoreTrustedSecurityState(t *testing.T) { + cfg := &mihomoConfig.RawConfig{ + ExternalController: "0.0.0.0:9090", + Secret: "profile-controlled-secret", + DNS: mihomoConfig.RawDNS{ + Enable: true, + Listen: ":1053", + }, + } + + if err := patchExternalController(cfg, ""); err != nil { + t.Fatalf("patchExternalController failed: %v", err) + } + + WriteOverride(OverrideSlotSession, `{ + "external-controller":"127.0.0.1:9090", + "external-controller-cors":{ + "allow-origins":["https://dashboard.example"], + "allow-private-network":true + }, + "secret":"trusted-secret", + "dns":{"listen":"127.0.0.1:1053"} + }`) + defer ClearOverride(OverrideSlotSession) + + if err := patchOverride(cfg, ""); err != nil { + t.Fatalf("patchOverride failed: %v", err) + } + + if cfg.ExternalController != "127.0.0.1:9090" || cfg.Secret != "trusted-secret" { + t.Fatal("trusted external controller override was not restored") + } + if len(cfg.ExternalControllerCors.AllowOrigins) != 1 || + cfg.ExternalControllerCors.AllowOrigins[0] != "https://dashboard.example" || + !cfg.ExternalControllerCors.AllowPrivateNetwork { + t.Fatal("trusted external controller CORS override was not restored") + } + if cfg.DNS.Listen != "127.0.0.1:1053" { + t.Fatal("trusted DNS listener override was not restored") + } +} diff --git a/service/src/main/java/com/github/kr328/clash/service/TunService.kt b/service/src/main/java/com/github/kr328/clash/service/TunService.kt index 8550f8ab81..2f39fc5782 100644 --- a/service/src/main/java/com/github/kr328/clash/service/TunService.kt +++ b/service/src/main/java/com/github/kr328/clash/service/TunService.kt @@ -221,7 +221,11 @@ class TunService : VpnService(), CoroutineScope by CoroutineScope(Dispatchers.De stack = store.tunStackMode, gateway = "$TUN_GATEWAY/$TUN_SUBNET_PREFIX" + if (store.allowIpv6) ",$TUN_GATEWAY6/$TUN_SUBNET_PREFIX6" else "", portal = TUN_PORTAL + if (store.allowIpv6) ",$TUN_PORTAL6" else "", - dns = if (store.dnsHijacking) NET_ANY else (TUN_DNS + if (store.allowIpv6) ",$TUN_DNS6" else ""), + dns = if (store.dnsHijacking) { + NET_ANY + if (store.allowIpv6) ",$NET_ANY6" else "" + } else { + TUN_DNS + if (store.allowIpv6) ",$TUN_DNS6" else "" + }, ) }