Skip to content

Wire the dormant allowBypass pref into the VPN builder; add phone-UI toggle (fixes wireless Android Auto) - #3057

Open
kazimurtaza wants to merge 5 commits into
celzero:mainfrom
kazimurtaza:allow-bypass-2685
Open

kazimurtaza wants to merge 5 commits into
celzero:mainfrom
kazimurtaza:allow-bypass-2685

Conversation

@kazimurtaza

@kazimurtaza kazimurtaza commented Aug 26, 2026

Copy link
Copy Markdown

What

Wires the dormant allowBypass persistent preference into the VPN builder and adds the corresponding phone-UI toggle (the TV build already ships a toggle for this pref; the strings settings_allow_bypass_heading/_desc have been in values/strings.xml all along — only the wire-up was missing).

Fixes #2685.

Root cause

PersistentState.allowBypass exists (allow_bypass, default false) and SettingsScreen.kt (TV) writes it, but BraveVPNService never reads it — VpnService.Builder.allowBypass() is never called, so the established VPN is always non-bypassable:

$ dumpsys connectivity | grep -A2 'VPN CONNECTED'
  ni{VPN CONNECTED extra: VPN:com.celzero.bravedns} ...
  TransportInfo: <VpnTransportInfo{type=1, sessionId=Rethink, bypassable=false ...}>

Wireless Android Auto negotiates its transport over Wi-Fi-Direct and checks the default network object: when it is a non-bypassable VPN, the session is refused regardless of per-app configuration:

NearbyMediums: [WifiNetworkV2] defaultNetworkCallback onCapabilitiesChanged network:NNN [ CELLULAR VPN ] isNonBypassable:true
GH.WirelessStartup: ProjectionErrorCode = 3, ProjectionErrorDetail = 52, io error
GH.WIRELESS.SETUP: State changed to START_WIFI_REQUEST_FAILED_WIFI_NOT_YET_STARTED

App-level workarounds (Exclude / Bypass DNS & Firewall for com.google.android.projection.gearhead) do not help because the check inspects the network, not tunnel membership. With builder.allowBypass() called at establish, the platform surfaces bypassable=true and apps that explicitly opt out (bindProcessToNetwork, as AA's transport does) can use the underlying network — the documented purpose of VpnService.Builder.allowBypass().

Changes

  • BraveVPNService.newBuilder(): call builder.allowBypass() when the pref is enabled, skipped under VPN lockdown (the platform disallows bypass in lockdown mode — mirrors the existing excluded-apps guard).
  • BraveVPNService.onSharedPreferenceChanged(): restart the tunnel when the pref changes (same one-liner as the PRIVATE_IPS branch — allowBypass() is additive, so disabling requires a rebuild of the builder).
  • TunnelSettingsActivity + activity_tunnel_settings.xml: new "Enable network visibility" toggle row cloned from the lan-traffic row, using the existing strings.

No behavior change by default (allowBypass defaults to false; opt-in via the new toggle).

Note: with this change the TV build's toggle becomes functional too (it currently writes a pref nothing reads). A follow-up could switch its hardcoded labels to settings_allow_bypass_heading.

Testing

Built assembleFdroidFullReleaseDebug, installed on a Pixel 8 Pro (Android 17), Rethink active:

  • Toggle appears in Configure → Network; enabling it restarts the tunnel (via the ALLOW_BYPASS pref branch).
  • dumpsys connectivity shows the VPN bypassable=true after the restart.
  • DNS blocking unaffected (doubleclick.net127.0.0.1).
  • Wireless Android Auto session negotiates with the VPN active (the reported failure mode in Android Auto and local VPN #2685).

Summary by CodeRabbit

  • New Features

    • Added a tunnel setting that lets apps bypass the VPN tunnel.
    • Added a switch and descriptive text for enabling or disabling app bypass.
    • Changes take effect automatically when the setting is updated.
    • The selected preference is retained and clearly reflected in tunnel settings.
  • Bug Fixes

    • Ensured the VPN configuration reflects the selected bypass preference when lockdown mode is inactive.

…toggle

The allowBypass persistent preference and its settings strings exist, and the
TV build exposes a toggle, but BraveVPNService never calls
VpnService.Builder.allowBypass() — the pref is dead on phones. Wireless
Android Auto refuses to negotiate its Wi-Fi-Direct transport when the default
network is a non-bypassable VPN, so Rethink users cannot use wireless AA at
all (workarounds like app-level Exclude don't help; the check inspects the
network object, not tunnel membership).
- BraveVPNService.newBuilder(): call builder.allowBypass() when the pref is
  set and VPN is not in lockdown mode (platform forbids bypass in lockdown)
- BraveVPNService.onSharedPreferenceChanged: restart the tunnel on change,
  like the privateIps toggle
- TunnelSettingsActivity + layout: 'Enable network visibility' toggle using
  the already-shipped settings_allow_bypass_heading/_desc strings
Fixes celzero#2685
@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5d1ad843-fcc3-4043-ab55-acedc5534233

📥 Commits

Reviewing files that changed from the base of the PR and between 941255b and 228f4ae.

📒 Files selected for processing (1)
  • app/src/main/java/com/celzero/bravedns/ui/activity/TunnelSettingsActivity.kt

Included review availability: Your plan provides up to 8 included reviews per hour; 4 remain after this review.

📜 Recent review details
🔇 Additional comments (1)
app/src/main/java/com/celzero/bravedns/ui/activity/TunnelSettingsActivity.kt (1)

109-109: LGTM!

Also applies to: 127-139, 150-151, 218-225, 239-253, 276-276, 285-285, 391-405


📝 Walkthrough

Walkthrough

Adds a tunnel settings row and switch for app bypass. The preference is persisted in PersistentState. BraveVPNService applies bypass when lockdown is inactive and restarts after preference changes.

Changes

Tunnel bypass setting

Layer / File(s) Summary
Persist tunnel-bypass setting
app/src/main/java/com/celzero/bravedns/service/PersistentState.kt, app/src/full/res/layout/activity_tunnel_settings.xml, app/src/main/java/com/celzero/bravedns/ui/activity/TunnelSettingsActivity.kt
Adds the ALLOW_BYPASS preference key, the settings row and switch, switch initialization, row and switch listeners, persistence, and event logging.
Apply bypass during VPN restart
app/src/main/java/com/celzero/bravedns/service/BraveVPNService.kt
Enables allowBypass() when lockdown is inactive and persistentState.allowBypass is enabled. Changes to ALLOW_BYPASS trigger a debounced VPN restart.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 228f4

This change enables an opt-in VPN bypass setting while preserving the existing default behavior, with no actionable merge-blocking risk remaining.

Sequence Diagram(s)

sequenceDiagram
  participant TunnelSettingsActivity
  participant PersistentState
  participant BraveVPNService
  TunnelSettingsActivity->>PersistentState: Save allowBypass
  PersistentState->>BraveVPNService: Report ALLOW_BYPASS change
  BraveVPNService->>BraveVPNService: Request debounced VPN restart
  BraveVPNService->>PersistentState: Read allowBypass
  BraveVPNService->>BraveVPNService: Call allowBypass when lockdown is inactive
Loading

Suggested reviewers: hussainmohd-a

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The changes directly address issue #2685 by enabling VPN bypass for Android Auto-related connectivity, excluding lockdown mode, persisting the setting, and restarting the VPN when the setting changes.…
Out of Scope Changes check ✅ Passed The changes remain within scope. The layout, preference key, VPN builder behavior, preference-change restart, and phone UI toggle all support the Android Auto VPN-bypass objective. Documentation comme…
Docstring Coverage ✅ Passed Docstring coverage is 81.25% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 16 functions across 3 files.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: connecting the allowBypass preference to the VPN builder and adding a phone UI toggle. It also identifies the Android Auto issue addressed.
Full details: Linked Issues check

Explanation

The changes directly address issue #2685 by enabling VPN bypass for Android Auto-related connectivity, excluding lockdown mode, persisting the setting, and restarting the VPN when the setting changes. The phone UI exposes the setting, and the provided testing confirms the intended behavior.

Full details: Out of Scope Changes check

Explanation

The changes remain within scope. The layout, preference key, VPN builder behavior, preference-change restart, and phone UI toggle all support the Android Auto VPN-bypass objective. Documentation comments and restored declarations are supporting maintenance changes.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Addresses the docstring-coverage pre-merge check on PR celzero#3057.
Refs celzero#2685
Brings docstring coverage over the pre-merge threshold on PR celzero#3057.
Refs celzero#2685
Completes docstring coverage for the diff context on PR celzero#3057.
Refs celzero#2685
Previous commit's scripted insertion mangled the declarations; restored
them and re-verified the build compiles.
Refs celzero#2685
@kazimurtaza

Copy link
Copy Markdown
Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Aug 26, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

@whispy

whispy commented Aug 27, 2026

Copy link
Copy Markdown

Wouldn't this allow any app to initiate a VPN bypass? Is there a way to only allow it from certain callers that the user selects in RethinkDNS? So they can allow Android Auto to bypass VPN, but not e.g. Facebook.

@kazimurtaza

Copy link
Copy Markdown
Author

Good question. Three parts to the answer.

What allowBypass actually changes: bypass stays on-demand and per socket. An app only side-steps the tunnel if it explicitly binds to a non-VPN network, for example via ConnectivityManager.bindProcessToNetwork() or by binding a socket to a specific Network. Apps that do nothing keep flowing through the VPN exactly as before. So Facebook does not gain anything just because the flag is set; it would have to deliberately implement network binding, and only the sockets bound that way escape.

The honest trade-off: yes, any app that does implement those calls can then use the underlying network directly. That is inherent to the platform API: VpnService.Builder has no "allow bypass only for package X" form. The per-app tools it offers are addAllowedApplication / addDisallowedApplication, and those are full exclusions, not on-demand bypass. This is why the PR keeps the setting opt-in with the default unchanged (off): enabling it is the user accepting that trade-off.

On selecting specific apps: the stronger per-app form already exists as Configure, Apps, Exclude, which removes an app from the tunnel entirely (addDisallowedApplication). For Android Auto wireless specifically, Exclude is not sufficient: its transport checks the bypassable flag on the default network object before it will negotiate the session (see the logcat in the PR description), so the tunnel itself must be established as bypassable for the handshake to proceed, even in a setup where Android Auto is also excluded.

One further limitation worth naming: once the flag is on, Rethink cannot see or log which apps bypass, because bypassed traffic never enters the tunnel. So a per-app prompt or audit log is not something this change could layer on top; that would need platform support that does not exist today.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Android Auto and local VPN

2 participants