Skip to content

Conversation

@danialramzan
Copy link

@danialramzan danialramzan commented Dec 8, 2025

Implemented Experimental INCLUDE split tunnelling support alongside a search bar for quick app selection.

Updates tailscale/tailscale#13816

This adds a prototype "include-mode" routing model for Android VPN configuration, addressing long-standing user requests for selectively tunneling only chosen applications, alongside a search bar implementation.

When enabled, the VPN builder whitelists specific package names rather than excluding all others. This avoids the need to maintain long exclude lists and supports targeted routing (e.g., only browsers, music players, etc).

Details:
Implemented a UI toggle button which turns on split tunneling, and which then presents the option to either include or exclude app packages in the VPNBuilder, without having to use MDM, with both the include and exclude package lists capable of containing separate apps. When Split tunnelling is disabled, the app excludes all packages in builtInDisallowedPackageNames by default, mirroring existing default functionality when no packages are manually added to the exclude list.
If Included or Excluded packages are included by MDM, the split tunneling toggle is vacuously turned on -- and user include/exclude lists are ignored.
A search bar has also been implemented in order to cut down on app selection times significantly. The search bar matches on both app names and package names (e.g Chrome or com.android.chrome)

Limitations and notes:

  • DNS resolver traffic might fail under include-mode when Tailscale DNS is active. Disabling Tailscale DNS appears to mitigate the issue, but the underlying resolver interaction remains open for analysis. Feedback, testing results, and alternative approaches from developers or knowledgeable users are welcome and appreciated. (When using Mullvad VPN as my exit node, this problem seems to disappear, which leads me to suspect the problem is indeed with my exit node and not the implementation.)

  • When split tunneling mode is set to INCLUDE an empty allowed packages list is interpreted as “route everything,” so all traffic passes through the tunnel. Once an entry is added, filtering works as intended.

This commit is intended as a discussion basis / RFC for upstream consideration and iteration :)

Note: I became aware of PR #621 only after finishing this implementation 😄
My goal is not to replace that effort, this PR explores a different UI/UX design (search bar, explicit include/exclude list behaviour, toggle state logic) which may complement the earlier branch.

Happy to collaborate, merge concepts, or align with the earlier PR, whichever direction maintainers prefer :)

Signed-off-by: danialramzan [email protected]

Implemented Experimental <INCLUDE> split tunnelling support.

This adds a prototype "include-mode" routing model for Android VPN configuration, addressing long-standing user requests for selectively tunneling only chosen applications.

When enabled, the VPN builder whitelists specific package names rather than excluding all others. This avoids the need to maintain long exclude lists and supports targeted routing (e.g., only browsers, music players, etc).

Details: Implemented a UI toggle button which turns on split tunneling, and which then presents the option to either include or exclude app packages in the VPNBuilder, without having to use MDM. *When Split tunnelling is disabled, the app excludes all packages in builtInDisallowedPackageNames by default, mirroring existing default functionality when no packages are manually added to the exclude list*
If Included or Excluded packages are included by MDM, the split tunneling toggle is vacuously turned on -- and user include/exclude lists are ignored.

Limitations: DNS resolver traffic can fail under include-mode when Tailscale DNS is active (different results observed across 3 devices). Disabling Tailscale DNS appears to mitigate the issue, but the underlying resolver interaction remains open for analysis. Feedback, testing results, and alternative approaches from developers or knowledgeable users are welcome and appreciated.

This commit is intended as a discussion basis / RFC for upstream consideration and iteration :)

---------

Signed-off-by: Danial Ramzan <[email protected]>
Signed-off-by: danialramzan <[email protected]>
Signed-off-by: Danial Ramzan <[email protected]>

Signed-off-by: danialramzan <[email protected]>
* Implemented Experimental <INCLUDE> split tunnelling support. (#5)

Implemented Experimental <INCLUDE> split tunnelling support.

This adds a prototype "include-mode" routing model for Android VPN configuration, addressing long-standing user requests for selectively tunneling only chosen applications.

When enabled, the VPN builder whitelists specific package names rather than excluding all others. This avoids the need to maintain long exclude lists and supports targeted routing (e.g., only browsers, music players, etc).

Details: Implemented a UI toggle button which turns on split tunneling, and which then presents the option to either include or exclude app packages in the VPNBuilder, without having to use MDM. *When Split tunnelling is disabled, the app excludes all packages in builtInDisallowedPackageNames by default, mirroring existing default functionality when no packages are manually added to the exclude list*
If Included or Excluded packages are included by MDM, the split tunneling toggle is vacuously turned on -- and user include/exclude lists are ignored.

Limitations: DNS resolver traffic can fail under include-mode when Tailscale DNS is active (different results observed across 3 devices). Disabling Tailscale DNS appears to mitigate the issue, but the underlying resolver interaction remains open for analysis. Feedback, testing results, and alternative approaches from developers or knowledgeable users are welcome and appreciated.

This commit is intended as a discussion basis / RFC for upstream consideration and iteration :)

---------

Signed-off-by: Danial Ramzan <[email protected]>

* Implemented search bar in split-tunneling page.
Signed-off-by: Danial Ramzan <[email protected]>

---------

Signed-off-by: Danial Ramzan <[email protected]>
@danialramzan
Copy link
Author

Updates #tailscale/tailscale#13816
Updates #13816

Signed-off-by: danialramzan <[email protected]>
@RustyHearth
Copy link

Great solution, i started implementing something but saw you already beat me to it, the other solution seems to miss the search bar for filtering which ease the selection.

I just wanted to recommend maybe a solution for the part when no allowed app selected the split tunnel wont work, you could test if userAllowed empty and do something like this:
InstalledAppsManager(packageManager = this.packageManager) .fetchInstalledApps() .map { it.packageName } .toSet() to get all apps and use this as disallow list to implement an empty userAllowed

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.

2 participants