From 75f012ee24e2cf153cd876f233242d5c738a9064 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 Aug 2025 15:53:34 +0000 Subject: [PATCH 1/5] Initial plan From 0f67e4f2eb0a5197d4758d06b12696015597a06c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:00:29 +0000 Subject: [PATCH 2/5] Fix bypass universal not respected in background blocking Co-authored-by: ignoramous <852289+ignoramous@users.noreply.github.com> --- .../java/com/celzero/bravedns/service/BraveVPNService.kt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt b/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt index e43a46c62..62aba2016 100644 --- a/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt +++ b/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt @@ -1123,6 +1123,13 @@ class BraveVPNService : VpnService(), ConnectionMonitor.NetworkListener, Bridge, private suspend fun blockBackgroundData(uid: Int): Boolean { if (!persistentState.getBlockAppWhenBackground()) return false + // Apps with bypass universal setting should not be blocked by background rules + val appStatus = FirewallManager.appStatus(uid) + if (appStatus.bypassUniversal()) { + logd("blockBackgroundData: app has bypass universal, allowing background, $uid") + return false + } + if (!accessibilityServiceFunctional()) { Logger.w(LOG_TAG_VPN, "accessibility service not functional, disable bg-block") handleAccessibilityFailure() From 278b82f9238ef5d9e7d9ee9c8c41e7a0f9f6268e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:01:40 +0000 Subject: [PATCH 3/5] Also exempt bypass universal apps from device lock blocking Co-authored-by: ignoramous <852289+ignoramous@users.noreply.github.com> --- .../com/celzero/bravedns/service/BraveVPNService.kt | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt b/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt index 62aba2016..8d013d12d 100644 --- a/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt +++ b/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt @@ -758,9 +758,15 @@ class BraveVPNService : VpnService(), ConnectionMonitor.NetworkListener, Bridge, } if (deviceLocked()) { - closeTrackedConnsOnDeviceLock() - logd("firewall: device locked, $uid") - return FirewallRuleset.RULE3 + // Apps with bypass universal setting should not be blocked by device lock + val appStatus = FirewallManager.appStatus(uid) + if (appStatus.bypassUniversal()) { + logd("firewall: device locked but app has bypass universal, allowing, $uid") + } else { + closeTrackedConnsOnDeviceLock() + logd("firewall: device locked, $uid") + return FirewallRuleset.RULE3 + } } if (udpBlocked(uid, connInfo.protocol, connInfo.destPort)) { From 09f844e328a6e78a8e2fad47ff04aff7ea96a8e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 22 Aug 2025 16:02:51 +0000 Subject: [PATCH 4/5] Add unit test for bypass universal functionality Co-authored-by: ignoramous <852289+ignoramous@users.noreply.github.com> --- .../bravedns/service/BypassUniversalTest.kt | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 app/src/test/java/com/celzero/bravedns/service/BypassUniversalTest.kt diff --git a/app/src/test/java/com/celzero/bravedns/service/BypassUniversalTest.kt b/app/src/test/java/com/celzero/bravedns/service/BypassUniversalTest.kt new file mode 100644 index 000000000..8ab081ff9 --- /dev/null +++ b/app/src/test/java/com/celzero/bravedns/service/BypassUniversalTest.kt @@ -0,0 +1,65 @@ +package com.celzero.bravedns.service + +import org.junit.Test +import org.junit.Assert.assertEquals + +/** + * Test for Bypass Universal functionality to ensure bypassed apps are not blocked + * by universal firewall rules. This test verifies the fix for issue #2148 where + * bypass universal setting was not respected in background blocking and device lock rules. + */ +class BypassUniversalTest { + + @Test + fun testFirewallStatusBypassUniversal() { + // Test that BYPASS_UNIVERSAL status returns true for bypassUniversal() + val bypassStatus = FirewallManager.FirewallStatus.BYPASS_UNIVERSAL + assertEquals(true, bypassStatus.bypassUniversal()) + + // Test that other statuses return false + assertEquals(false, FirewallManager.FirewallStatus.NONE.bypassUniversal()) + assertEquals(false, FirewallManager.FirewallStatus.EXCLUDE.bypassUniversal()) + assertEquals(false, FirewallManager.FirewallStatus.ISOLATE.bypassUniversal()) + } + + @Test + fun testFirewallStatusIds() { + // Verify firewall status IDs are correctly defined + assertEquals(2, FirewallManager.FirewallStatus.BYPASS_UNIVERSAL.id) + assertEquals(3, FirewallManager.FirewallStatus.EXCLUDE.id) + assertEquals(4, FirewallManager.FirewallStatus.ISOLATE.id) + assertEquals(5, FirewallManager.FirewallStatus.NONE.id) + assertEquals(6, FirewallManager.FirewallStatus.UNTRACKED.id) + assertEquals(7, FirewallManager.FirewallStatus.BYPASS_DNS_FIREWALL.id) + } + + @Test + fun testFirewallRulesetBypassRules() { + // Test that RULE8 is the correct bypass rule + assertEquals("Whitelist", FirewallRuleset.RULE8.id) + assertEquals(true, FirewallRuleset.isBypassRule(FirewallRuleset.RULE8)) + + // Test that blocking rules are not bypass rules + assertEquals(false, FirewallRuleset.isBypassRule(FirewallRuleset.RULE3)) // Device lock + assertEquals(false, FirewallRuleset.isBypassRule(FirewallRuleset.RULE4)) // Background + } + + /** + * This test documents the expected behavior for the fix to issue #2148. + * The bug was that apps with BYPASS_UNIVERSAL status were still being blocked + * by universal rules like background blocking and device lock. + */ + @Test + fun testBypassUniversalBehaviorDocumentation() { + // This test documents that when an app has BYPASS_UNIVERSAL status: + // 1. It should not be blocked by background data rules (RULE4) + // 2. It should not be blocked by device lock rules (RULE3) + // 3. It should return RULE8 (Whitelist) from the main bypass check + + // The fix ensures that blockBackgroundData() and device lock check + // both respect the bypass universal setting before applying blocking rules. + + val bypassStatus = FirewallManager.FirewallStatus.BYPASS_UNIVERSAL + assertEquals(true, bypassStatus.bypassUniversal()) + } +} \ No newline at end of file From 1454828c0bde6f8ace77cb81750385cbbaad5d18 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 28 Aug 2025 13:04:11 +0000 Subject: [PATCH 5/5] Remove redundant bypass universal checks from device lock and background blocking Co-authored-by: hussainmohd-a <56958445+hussainmohd-a@users.noreply.github.com> --- .../bravedns/service/BraveVPNService.kt | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt b/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt index 8d013d12d..e43a46c62 100644 --- a/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt +++ b/app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt @@ -758,15 +758,9 @@ class BraveVPNService : VpnService(), ConnectionMonitor.NetworkListener, Bridge, } if (deviceLocked()) { - // Apps with bypass universal setting should not be blocked by device lock - val appStatus = FirewallManager.appStatus(uid) - if (appStatus.bypassUniversal()) { - logd("firewall: device locked but app has bypass universal, allowing, $uid") - } else { - closeTrackedConnsOnDeviceLock() - logd("firewall: device locked, $uid") - return FirewallRuleset.RULE3 - } + closeTrackedConnsOnDeviceLock() + logd("firewall: device locked, $uid") + return FirewallRuleset.RULE3 } if (udpBlocked(uid, connInfo.protocol, connInfo.destPort)) { @@ -1129,13 +1123,6 @@ class BraveVPNService : VpnService(), ConnectionMonitor.NetworkListener, Bridge, private suspend fun blockBackgroundData(uid: Int): Boolean { if (!persistentState.getBlockAppWhenBackground()) return false - // Apps with bypass universal setting should not be blocked by background rules - val appStatus = FirewallManager.appStatus(uid) - if (appStatus.bypassUniversal()) { - logd("blockBackgroundData: app has bypass universal, allowing background, $uid") - return false - } - if (!accessibilityServiceFunctional()) { Logger.w(LOG_TAG_VPN, "accessibility service not functional, disable bg-block") handleAccessibilityFailure()