feat(cli): OS-level split-tunnel routes (removes send_direct stub)
DIRECT-destination traffic now bypasses the TUN entirely via OS routing
table edits, instead of going through user-space and hitting the v1
send_direct stub. The user-space router only sees VPN-bound packets,
making the split-tunnel real.
- aura_cli::os_routes::OsRouteGuard: RAII install + rollback of OS routes.
Linux: `ip route show default` parser -> DIRECT CIDRs via original gw,
VPN default via TUN with metric 50. macOS: `route -n get default`
parser -> `route add -net/-host ... <gw>` for DIRECT, `route add -net
... -interface <tun>` for VPN. Windows: stub + warning (v3).
- dry_run works on every platform (logs `would run: ...`); useful for
tests and operator confidence-checks.
- SplitRoutes::from_config folds [[tunnel.split.direct]]/[[...vpn]] +
resolved domains (via AuraDns) into one declarative plan.
- New [tunnel.os_routes] {enabled (default true), dry_run, gateway,
egress_iface}; absent section = old user-space behavior (back-compat).
- client::run installs routes after AuraTun::create, before privdrop;
guard's Drop reverts everything on shutdown.
- aura-tunnel::router unchanged; AuraRouter::send_direct kept as a
defensive fallback (in v2 it should never fire — OS routes prevent
DIRECT packets from reaching the TUN at all).
20 new tests (linux/macos parser unit tests, install dry-run, config
back-compat). Workspace: 174 tests passed (+19), clippy -D warnings
clean, fmt clean.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -213,6 +213,48 @@ pub struct ClientTunnelSection {
|
||||
/// `[tunnel.split]` split-tunnel configuration.
|
||||
#[serde(default)]
|
||||
pub split: SplitSection,
|
||||
/// `[tunnel.os_routes]` sub-section: v2 OS-level split tunnelling. Omitting it (or setting
|
||||
/// `enabled = false`) preserves the v1 user-space behaviour where the [`AuraRouter`] sees
|
||||
/// every packet (the `send_direct` path was a stub). When enabled, the client programs the
|
||||
/// system routing table so DIRECT destinations bypass the TUN entirely and only
|
||||
/// VPN-classified traffic reaches it. See [`crate::os_routes`].
|
||||
#[serde(default)]
|
||||
pub os_routes: Option<OsRoutesSection>,
|
||||
}
|
||||
|
||||
/// `[tunnel.os_routes]` section: v2 OS-level split-tunnel programming. When `enabled` (the
|
||||
/// default), the client adds system routes at startup so DIRECT-classified traffic never enters
|
||||
/// the TUN; when omitted or `enabled = false`, behaviour falls back to the v1 user-space router.
|
||||
///
|
||||
/// See [`crate::os_routes`] for the apply / rollback semantics.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(default)]
|
||||
pub struct OsRoutesSection {
|
||||
/// Master switch. `true` (default) installs system routes via [`crate::os_routes::OsRouteGuard`];
|
||||
/// `false` leaves the host routing table alone and behaves like v1.
|
||||
pub enabled: bool,
|
||||
/// When `true`, every routing command is only logged (`would run: ...`) and not executed.
|
||||
/// Useful for testing and for verifying the plan without root privileges.
|
||||
pub dry_run: bool,
|
||||
/// Optional explicit IPv4 default gateway. When set, the gateway-auto-detection step is
|
||||
/// skipped and this value is used for every DIRECT bypass route. When omitted (the default),
|
||||
/// the gateway is read from the host (Linux: `ip route show default`; macOS:
|
||||
/// `route -n get default`).
|
||||
pub gateway: Option<String>,
|
||||
/// Optional explicit egress interface name (e.g. `"eth0"` on Linux, `"en0"` on macOS). When
|
||||
/// omitted (the default), derived from the same auto-detection step as `gateway`.
|
||||
pub egress_iface: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for OsRoutesSection {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
dry_run: false,
|
||||
gateway: None,
|
||||
egress_iface: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `[tunnel.split]` section: default action plus direct/vpn override rules.
|
||||
|
||||
Reference in New Issue
Block a user