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:
@@ -57,6 +57,7 @@ Windows route-table boundary:
|
||||
- selected source address, next hop, interface index/LUID, prefix, and metric
|
||||
- interface index/LUID lookup from Windows network adapter GUIDs
|
||||
- scoped IP interface metric overrides with restore-on-drop behavior
|
||||
- scoped default-route suppression with restore-on-drop behavior
|
||||
- scoped host-route pinning for the relay IP on the pre-TAP interface
|
||||
- non-Windows builds return a clear unsupported-platform error
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -78,6 +78,24 @@ pub fn set_scoped_interface_metric(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn set_scoped_default_routes_disabled(
|
||||
identity: NetworkInterfaceIdentity,
|
||||
family: IpInterfaceFamily,
|
||||
disabled: bool,
|
||||
) -> Result<ScopedDefaultRoutes> {
|
||||
let previous = interface_metric(identity, family)?;
|
||||
let mut row = get_interface_row(identity, family)?;
|
||||
row.DisableDefaultRoutes = disabled;
|
||||
set_interface_row(&mut row).with_context(|| {
|
||||
format!("failed to set {family:?} default-route disabled state to {disabled}")
|
||||
})?;
|
||||
|
||||
Ok(ScopedDefaultRoutes {
|
||||
previous,
|
||||
active: true,
|
||||
})
|
||||
}
|
||||
|
||||
pub struct ScopedInterfaceMetric {
|
||||
previous: InterfaceMetricSnapshot,
|
||||
active: bool,
|
||||
@@ -109,6 +127,37 @@ impl Drop for ScopedInterfaceMetric {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ScopedDefaultRoutes {
|
||||
previous: InterfaceMetricSnapshot,
|
||||
active: bool,
|
||||
}
|
||||
|
||||
impl ScopedDefaultRoutes {
|
||||
#[must_use]
|
||||
pub const fn previous(&self) -> InterfaceMetricSnapshot {
|
||||
self.previous
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for ScopedDefaultRoutes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ScopedDefaultRoutes")
|
||||
.field("previous", &self.previous)
|
||||
.field("active", &self.active)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ScopedDefaultRoutes {
|
||||
fn drop(&mut self) {
|
||||
if !self.active {
|
||||
return;
|
||||
}
|
||||
|
||||
let _ = restore_default_routes(self.previous);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn best_route_to(destination: IpAddr) -> Result<RouteSnapshot> {
|
||||
let destination_sockaddr = sockaddr_from_ip(destination);
|
||||
let mut route = MIB_IPFORWARD_ROW2::default();
|
||||
@@ -183,6 +232,12 @@ fn restore_interface_metric(snapshot: InterfaceMetricSnapshot) -> Result<()> {
|
||||
set_interface_row(&mut row)
|
||||
}
|
||||
|
||||
fn restore_default_routes(snapshot: InterfaceMetricSnapshot) -> Result<()> {
|
||||
let mut row = get_interface_row(snapshot.identity(), snapshot.family())?;
|
||||
row.DisableDefaultRoutes = snapshot.disable_default_routes();
|
||||
set_interface_row(&mut row)
|
||||
}
|
||||
|
||||
fn interface_row_key(
|
||||
identity: NetworkInterfaceIdentity,
|
||||
family: IpInterfaceFamily,
|
||||
|
||||
Reference in New Issue
Block a user