feat(client): add scoped default-route suppression

The Windows route helper now supports a scoped DisableDefaultRoutes override
for an IP interface family. The guard snapshots the existing interface row,
sets the requested default-route disabled state, and restores the previous
state when dropped.

This is the route-crate half of neutralizing TAP default-route takeover from
PLAN.md. It intentionally does not wire the client yet, so the public API can
be reviewed independently from the client startup behavior.

The implementation keeps metric restoration and default-route restoration
separate even though both read the same IP interface row. That avoids one guard
accidentally reverting the other guard's setting when the Windows client holds
both at the same time.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-route
- cargo clippy -p lanparty-client-route --all-targets -- -D warnings
- cargo check -p lanparty-client-route --target x86_64-pc-windows-msvc
- cargo clippy -p lanparty-client-route --target x86_64-pc-windows-msvc --all-targets -- -D warnings
- git diff --check

Refs: PLAN.md
This commit is contained in:
2026-05-21 19:26:07 +02:00
parent c6a4a9da89
commit 9c0a974281
3 changed files with 79 additions and 2 deletions
+23 -2
View File
@@ -2,7 +2,7 @@
//!
//! The client binary uses this crate to keep Win32 route/metric calls out of
//! the relay session code. The crate can snapshot the current relay route and
//! install a scoped host route that pins the relay IP to the pre-TAP interface.
//! install scoped route/interface overrides that are restored when dropped.
use std::net::IpAddr;
@@ -175,7 +175,10 @@ mod windows;
#[cfg(windows)]
pub use windows::{PinnedRelayRoute, best_route_to, interface_identity_from_guid, pin_relay_route};
#[cfg(windows)]
pub use windows::{ScopedInterfaceMetric, interface_metric, set_scoped_interface_metric};
pub use windows::{
ScopedDefaultRoutes, ScopedInterfaceMetric, interface_metric,
set_scoped_default_routes_disabled, set_scoped_interface_metric,
};
#[cfg(not(windows))]
pub fn best_route_to(_destination: IpAddr) -> Result<RouteSnapshot> {
@@ -221,6 +224,21 @@ pub fn set_scoped_interface_metric(
bail!("Windows interface metric updates are only available on Windows");
}
#[cfg(not(windows))]
#[derive(Debug)]
pub struct ScopedDefaultRoutes {
_private: (),
}
#[cfg(not(windows))]
pub fn set_scoped_default_routes_disabled(
_identity: NetworkInterfaceIdentity,
_family: IpInterfaceFamily,
_disabled: bool,
) -> Result<ScopedDefaultRoutes> {
bail!("Windows interface default-route updates are only available on Windows");
}
#[cfg(test)]
mod tests {
use super::*;
@@ -305,6 +323,9 @@ mod tests {
assert!(interface_metric(identity, IpInterfaceFamily::Ipv4).is_err());
assert!(set_scoped_interface_metric(identity, IpInterfaceFamily::Ipv4, 500).is_err());
assert!(
set_scoped_default_routes_disabled(identity, IpInterfaceFamily::Ipv4, true).is_err()
);
}
fn ip(value: &str) -> IpAddr {