Make WireGuard AllowedIPs authoritative over RFC1918 route exclusions (#593)#645
Merged
Conversation
…#593) VpnRoutes previously hardcoded RFC1918 ranges (10/8, 172.16/12, 192.168/16) as always excluded from the tun, so LAN traffic bypasses the tunnel and reaches the local network directly. With WireGuard remote egress and a split-DNS setup (the VPN resolver returns private addresses for self-hosted services behind the WG endpoint), those hosts became unreachable: DNS resolved but packets to private IPs left the tunnel and died. When WG remote egress is active, the profile's AllowedIPs now decide: any part of an RFC1918 range covered by a peer's AllowedIPs (0.0.0.0/0, or an explicit subnet like 192.168.1.0/24) is routed into the tunnel instead of excluded. WG off keeps today's behaviour exactly. No new user-facing toggle — users who don't want LAN-through-tunnel narrow their AllowedIPs. Loopback, link-local, multicast, CGNAT, current-network, and carrier Wi-Fi-calling ranges stay ALWAYS excluded regardless of AllowedIPs. IPv6 AllowedIPs are ignored for now (follow-up). Adds VpnRoutesTest covering the default exclusions, 0.0.0.0/0, explicit subnets, unions, and the reserved-range guard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member
Author
|
Review summary: I inspected the full diff and surrounding VPN-builder/WireGuard configuration flow, including RFC1918 interval subtraction, overlapping/unsorted AllowedIPs, the route-cache key, malformed/IPv6 entry handling, reserved-range precedence, and the added Robolectric coverage. I did not find an actionable correctness or regression issue. is clean, and the refreshed GitHub job passes. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #593 (draft — see note at bottom).
Problem
VpnRoutes.EXCLUDED_RANGEShardcoded the RFC 1918 private ranges (10/8, 172.16/12, 192.168/16) as always excluded from the tun. That is correct for the common case (LAN traffic should reach the local network directly, not the tunnel), but it breaks a legitimate WireGuard remote-egress setup:Design: AllowedIPs-authoritative, no new toggle
Philosophy here is simplicity over configurability, so this adds no user-facing setting. Instead, when WireGuard remote egress is active, the profile's
AllowedIPsbecome authoritative over the RFC 1918 exclusions:AllowedIPscovers (e.g.0.0.0.0/0, or an explicit192.168.1.0/24) is routed into the tunnel instead of excluded.AllowedIPs(the standard WireGuard knob).This gives the reporter their fix with zero UI, and keeps the WG profile as the single source of truth for what egresses remotely.
Always excluded, regardless of AllowedIPs
Loopback (127/8), link-local (169.254/16), multicast/reserved (224/3), CGNAT (100.64/10), current-network (0/8), and the carrier Wi-Fi-calling ranges are split out into an
ALWAYS_EXCLUDEDset and are never routed into the tun, even ifAllowedIPs = 0.0.0.0/0. WG's own socket is already handled byVpnService.protect(), but we still must never route loopback/link-local/multicast into the tunnel.Implementation
VpnRoutesnow splits its ranges intoALWAYS_EXCLUDEDandRFC1918_RANGES.VpnRoutes.getRoutes(List<String> wgAllowedIps): parses the AllowedIPs (IPv4 only), and for each RFC 1918 range subtracts the AllowedIPs-covered portion before computing the route complement (interval math on 32-bit longs; overlapping/unsorted AllowedIPs handled). Result is cached by a normalized AllowedIPs signature so the per-rebuild cost stays low.getRoutes()(no-arg) is unchanged behaviourally and still cached — used whenever WG egress is off or has no usable IPv4 AllowedIPs.ServiceSinkhole.getBuilder()collects the union of every peer'sAllowedIPsfrom the already-parsed WG config and passes it through whenwg_enabledand the config parses.Trade-off
When
AllowedIPscovers RFC 1918 space, that LAN traffic enters the tunnel rather than reaching the local network directly. That is exactly whatAllowedIPsmeans in WireGuard, and it is what the reporter wants, but it is a behaviour change for anyone who set0.0.0.0/0while also relying on direct LAN access. The mitigation is standard: narrowAllowedIPsto only the remote subnets you actually want tunneled.IPv6
IPv6
AllowedIPsare ignored for now (the existingIPUtil.CIDRmath is IPv4-only). RFC 1918 is IPv4-only anyway, and ULA handling would need parallel v6 interval math — noted as a follow-up rather than bundled here.Tests
VpnRoutesTest(Robolectric) covers: default exclusions (WG off),0.0.0.0/0pulling all RFC 1918 in while reserved ranges stay out, an explicit LAN subnet routing only that subnet, unions of multiple AllowedIPs, empty/IPv6-only falling back to default, and a guard that reserved ranges are never re-exposed even if listed in AllowedIPs../gradlew :app:compileGithubDebugJavaWithJavacpasses.Needs on-device verification
AllowedIPs = 0.0.0.0/0: confirm a self-hosted RFC 1918 host behind the endpoint is reachable and general traffic still works.AllowedIPs: confirm only that subnet tunnels and other LAN hosts remain directly reachable.Note: a community contributor volunteered on the issue on 2026-07-12. This draft is offered as a starting point — the maintainer may prefer to hand it over to them.
🤖 Generated with Claude Code