Files
AuraVPN/crates
xah30 d2d3bc3e3c feat(cli): v3.5 — coexist routing with foreign VPNs (#2)
Closes the long-standing "Aura killed the internet while Clash Verge is
running" symptom. The cause is unsurprising once you stare at the routing
table: even after the user turns Tun mode off in Clash's GUI, the
clash-verge-service daemon does NOT remove the split-tunnel routes it
installed. They linger as `1/8`, `2/7`, `4/6`, `8/5`, `16/4`, `32/3`,
`64/2`, `128.0/1` → `198.18.0.1` (Clash's dead TUN). Aura's half-Internet
routes (`0.0.0.0/1` + `128.0.0.0/1`) lose by longest-prefix-match to those
foreign /8 / /7 / ... entries — so DNS goes to a non-functional foreign
interface and the user-visible internet looks dead.

## New module: aura-cli/src/coexist.rs

`scan_foreign_routes_macos(our_iface, pool_cidr) -> Vec<ForeignRoute>` —
shells out to `netstat -rn -f inet`, parses the output (incl. macOS's
classful shorthand: `1` = `1.0.0.0/8`, `169.254` = `169.254.0.0/16`, etc),
filters out: ourselves, loopback (`lo*`), link-local, LAN interfaces
(`en*` / `eth*` / `wlan*`), reserved ranges (127/8, 169.254/16, 224/4),
and the VPN's own pool. What's left is foreign-VPN territory.

`generate_override_cidrs(foreign, max_prefix=24) -> Vec<IpNetwork>` —
for each foreign /n, emits two strictly-more-specific /(n+1) routes that
together cover exactly the same range but point at Aura's TUN. By
longest-prefix-match the kernel routes that traffic through Aura;
foreign routes stay in the table untouched (which makes rollback trivial:
OsRouteGuard's Drop only undoes what Aura installed).

Routes /24 or narrower are skipped — those typically are LAN segments
operators don't want hijacked.

## Wired through SplitRoutes

`SplitRoutes` gains a `force_vpn_cidrs: Vec<IpNetwork>` field for the
override list. `macos_apply_plan`'s `DefaultAction::Vpn` arm now installs
them between the direct-host bypasses (most specific — server IP) and the
half-Internet catch-alls (least specific). Plan ordering becomes:

  [0..N]      direct CIDR / direct host bypasses (server IP, user-direct CIDRs)
  [N..N+2K]   override routes (2 per foreign /n the scan found)
  [N+2K..]    0.0.0.0/1 + 128.0.0.0/1 catch-alls

## Wired through client.rs

After the existing bypass-injection block, when `default == VPN` and we're
on macOS, scan foreign routes and append the generated overrides to
`split.force_vpn_cidrs`. Logged at INFO level so the operator can see in
the journal exactly which foreign VPN was detected and how many overrides
were emitted.

## Tests

9 new unit tests in `coexist::tests`: macOS shorthand parsing (`1` /
`2/7` / `192.168.1`), bare IP host routes, garbage rejection, full-table
netstat-output parsing against a real captured sample (the user's
machine's actual routing table with Clash Verge running), half-splitting,
classful Clash pattern coverage, the /24 skip rule, and the doubling
property of generate_override_cidrs.

All workspace tests still pass; `cargo clippy --workspace --all-targets
-- -D warnings` is clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-29 22:35:46 +03:00
..