Skip to content

Feat/split tunneling - #244

Open
eYey343 wants to merge 2 commits into
netbirdio:ux/ios-style-redesignfrom
eYey343:feat/split-tunneling
Open

Feat/split tunneling#244
eYey343 wants to merge 2 commits into
netbirdio:ux/ios-style-redesignfrom
eYey343:feat/split-tunneling

Conversation

@eYey343

@eYey343 eYey343 commented Aug 20, 2026

Copy link
Copy Markdown

Let the user choose which apps the tunnel carries

What

Adds a split tunnelling screen under Settings, letting the user decide which
applications the tunnel carries. Three modes:

  • Off — every app uses the VPN, the current behaviour.
  • Exclude — the picked apps bypass the tunnel, everything else stays in it.
  • Include — only the picked apps use the tunnel.

Until now IFace.createTun kept four applications out of the tunnel with no way
for the user to add their own. Those four remain the floor of Exclude, so
turning split tunnelling on never silently pulls them back in.

How

Android's VpnService.Builder takes an allow list or a deny list, never both on
the same builder, so the two selections are stored apart and a mode says which
one is live. SplitTunnelConfig holds that decision — plain Java, no Android
types, so the rules are covered by JVM unit tests.

A change to the selection leaves routes and search domains untouched, which the
existing recreateTUN guard reads as "nothing to do". The renewal request now
carries a force flag so the rebuild that applies the new filter actually runs,
and the change takes hold without asking the user to reconnect.

Two rules are worth calling out:

  • An empty Include selection would allow no app at all, leaving a tunnel that
    carries nothing and reads as broken rather than configured. It falls back to
    carrying everything, and the screen says so.
  • Include always carries this app. The Go engine's own sockets bypass the tunnel
    through protectSocket, but the built-in SSH client has to reach peers
    through it.

The app list resolves the launcher intent rather than asking for
QUERY_ALL_PACKAGES, which Play treats as a sensitive permission. The trade-off
is that applications without a launcher entry are not listed.

Tests

  • SplitTunnelConfigUnitTest — 11 JVM tests covering mode resolution, the empty
    allowlist fallback, self-inclusion, and defensive copying of the stored sets.
  • PreferencesInstrumentedTest — 4 new cases for persistence, including keeping
    the inactive selection across a mode change.

Verified by hand on an API 30 emulator with the tunnel up, watching the filter
follow the mode (disallow 4disallow 5allow 2) and the tunnel rebuild
on every change without a reconnection.

Screenshots

Settings entry Mode picker
Exclude mode Empty allowlist

Note for reviewers

The branch also carries Implement the ConnectionListener state callback, kept
as a separate commit. The netbird bump in 1b7f067 added OnStateChanged to the
interface without the Java side following, which leaves the branch unable to
compile. Drop that commit if it lands upstream first.

The netbird bump added onStateChanged, which every implementation must
carry. EngineRunner forwards it, EngineRestarter filters it during a
restart like the other disconnect events, MainActivity ignores it.
Adds a split tunnelling screen with three modes: off, exclude the picked
apps, or include only them. The two selections are stored apart, since
Android's builder takes an allow list or a deny list but never both.
A change forces a TUN rebuild, so it applies without reconnecting.
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 7feac785-8cd1-435e-8334-c3a571d8a952

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

@eYey343
eYey343 marked this pull request as ready for review August 20, 2026 18:41
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.

1 participant