Skip to content

Route the full tunnel in tethering compatibility mode (#699) - #700

Merged
kasnder merged 1 commit into
masterfrom
claude/trackercontrol-android-699-hp387l
Aug 1, 2026
Merged

Route the full tunnel in tethering compatibility mode (#699)#700
kasnder merged 1 commit into
masterfrom
claude/trackercontrol-android-699-hp387l

Conversation

@kasnder

@kasnder kasnder commented Aug 1, 2026

Copy link
Copy Markdown
Member

Addresses #699 — tethering worked on 2026.04.03 and stopped on 2026.07.27; downgrading restores it. The reporter's device has a broken tethering path of its own, and TrackerControl was what made tethering work.

Why it regressed

68fcd531 (#546, 2026-04-06, first released in 2026.04.27 — three days after the reporter's last working build) replaced the tun's catch-all route with the static split-tunnel route set:

  • Before, subnet defaulted to false, so getBuilder() fell through to builder.addRoute("0.0.0.0", 0) and the tun captured everything.
  • After, VpnRoutes.getRoutes() covers public IPv4 only. Permanently excluded are 10/8, 172.16/12, 192.168/16 (which contains the tethering downstreams 192.168.42/43/44/49), 100.64/10, 169.254/16 and 224.0.0.0/3 — the last of which contains the 255.255.255.255 DHCP broadcast that check_dhcp() answers for tethered clients.

The same commit also deleted the subnet, tethering and lan preferences, so there is no longer any toggle that restores the old behaviour — which is why downgrading is the reporter's only recourse.

The likely mechanism is that some devices only forward tethered traffic into the tun while the VPN carries a real default route. Without one, tethering falls back to the device's own path, which on such devices is broken.

What this changes

The opt-in, default-off "Tethering compatibility mode" (added for #478, previously MSS clamp only) now also installs a single 0.0.0.0/0 route, restoring the pre-2026.04.27 behaviour for users who need it. The split-tunnel route set stays the default for everyone else.

  • VpnRoutes.getTetheringRoutes() — the full-tunnel route list, with the rationale documented.
  • ServiceSinkhole.getBuilder() — picks it when the mode is on. WireGuard keeps precedence: a full tunnel would hand LAN and reserved ranges to the peer, which drops them, so an active profile's AllowedIPs still decide the routes (Allow traffic towards private internal endpoints via WireGuard #593), and the override is logged when it applies.
  • On Android 13+, the carrier ePDG excludeRoute() calls still apply on top of the default route, so Wi-Fi calling is unaffected.
  • Setting summary updated: the mode now costs direct LAN access as well as performance.
  • VpnRoutesTest covers the new route list and that it does not disturb the cached default one.

No new preference — this reuses the switch that already exists, and it is a breakage-recovery control rather than a general firewall knob.

Testing

Not built or run: this environment has no Android SDK, so :app:testGithubDebugUnitTest could not be executed here. CI should cover compilation and the unit tests.

Still needs on-device confirmation from the reporter that enabling the mode restores tethering on 2026.07.27 — the route mechanism above is inferred from the change history, not yet observed on an affected device.


Generated by Claude Code

Before the static VPN route set landed, the tun carried a plain
0.0.0.0/0 route, so tethered traffic — including the downstream subnets
and the DHCP broadcast — went through TrackerControl. On devices whose
own tethering path is broken, that is what made tethering work at all.
The split-tunnel route set removed the default route and, with it, the
subnet/tethering/lan preferences, leaving affected users with no way
back other than downgrading.

Reuse the existing (opt-in, default off) tethering compatibility mode:
alongside the TCP MSS clamp it now installs a single 0.0.0.0/0 route,
restoring the previous behaviour for the users who need it while the
split-tunnel route set stays the default for everyone else.

WireGuard keeps precedence — a full tunnel would hand LAN and reserved
ranges to the peer, which drops them — so an active profile's AllowedIPs
still decide the routes. On Android 13+ the carrier ePDG excludeRoute()
calls still apply on top of the default route, so Wi-Fi calling is
unaffected.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01FhD7ETjNc5qb5hSw9taYtS
@kasnder
kasnder marked this pull request as ready for review August 1, 2026 22:27
@kasnder
kasnder merged commit 28a8eda into master Aug 1, 2026
2 checks passed
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