feat(client): disable TAP default routes while running
The Windows client now holds scoped default-route suppression guards for the TAP interface while the frame pump is active. IPv4 protection is required, matching the relay-route safety path. IPv6 protection is still best-effort so IPv4-only Windows TAP setups do not fail startup just because there is no IPv6 interface row to update. This completes the current client-side route-policy wiring from PLAN.md: the relay host route is pinned before TAP activation, TAP interface metrics are raised while running, and TAP default routes are disabled until the client exits or startup unwinds. Automatic TAP MAC and MTU configuration remain follow-up work. The full Windows client target check still cannot complete on this Linux host: `ring` fails while compiling for `x86_64-pc-windows-msvc` because the Windows C header `assert.h` is unavailable, before `lanparty-client-win` is typechecked. The independent Windows-target route crate checks do pass. Test Plan: - cargo fmt --check - cargo test --workspace - cargo clippy --workspace --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:
@@ -140,6 +140,6 @@ adapter until shutdown.
|
||||
`--virtual-mac` can still override the stored identity for manual testing. On
|
||||
Windows it marks the TAP media connected and reports the driver MAC/MTU before
|
||||
forwarding frames, along with the TAP interface index/LUID. The client applies
|
||||
a scoped TAP interface metric while it runs and restores the previous metric on
|
||||
exit. Default-route takeover detection and automatic TAP MAC/MTU configuration
|
||||
are not wired yet.
|
||||
a scoped TAP interface metric and disables TAP default routes while it runs,
|
||||
then restores the previous route policy on exit. Automatic TAP MAC/MTU
|
||||
configuration is not wired yet.
|
||||
|
||||
@@ -15,7 +15,7 @@ use lanparty_client_core::{
|
||||
#[cfg(windows)]
|
||||
use lanparty_client_route::{
|
||||
IpInterfaceFamily, NetworkInterfaceIdentity, PinnedRelayRoute, RouteSnapshot,
|
||||
ScopedInterfaceMetric,
|
||||
ScopedDefaultRoutes, ScopedInterfaceMetric,
|
||||
};
|
||||
#[cfg(windows)]
|
||||
use lanparty_client_tap::TapAdapter;
|
||||
@@ -124,9 +124,9 @@ async fn main() -> Result<()> {
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn run_client(session: &ClientSession) -> Result<()> {
|
||||
let OpenedTapAdapter { tap, _metric_guard } = open_tap_adapter(session)?;
|
||||
let OpenedTapAdapter { tap, _route_guard } = open_tap_adapter(session)?;
|
||||
println!(
|
||||
"bridging TAP frames; relay route is pinned and TAP metrics are scoped; default-route takeover detection is not wired yet; press Ctrl-C to stop"
|
||||
"bridging TAP frames; relay route is pinned and TAP route policy is scoped; press Ctrl-C to stop"
|
||||
);
|
||||
|
||||
tokio::select! {
|
||||
@@ -190,13 +190,15 @@ fn print_pinned_relay_route(route: &PinnedRelayRoute) {
|
||||
#[cfg(windows)]
|
||||
struct OpenedTapAdapter {
|
||||
tap: TapAdapter,
|
||||
_metric_guard: TapMetricGuard,
|
||||
_route_guard: TapRouteProtectionGuard,
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
struct TapMetricGuard {
|
||||
_ipv4: ScopedInterfaceMetric,
|
||||
_ipv6: Option<ScopedInterfaceMetric>,
|
||||
struct TapRouteProtectionGuard {
|
||||
_ipv4_metric: ScopedInterfaceMetric,
|
||||
_ipv4_default_routes: ScopedDefaultRoutes,
|
||||
_ipv6_metric: Option<ScopedInterfaceMetric>,
|
||||
_ipv6_default_routes: Option<ScopedDefaultRoutes>,
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
@@ -206,7 +208,7 @@ fn open_tap_adapter(session: &ClientSession) -> Result<OpenedTapAdapter> {
|
||||
let tap_interface =
|
||||
lanparty_client_route::interface_identity_from_guid(tap.info().instance_id())
|
||||
.context("failed to resolve TAP interface identity")?;
|
||||
let metric_guard = protect_tap_metrics(tap_interface)?;
|
||||
let route_guard = protect_tap_routes(tap_interface)?;
|
||||
let driver_mac = tap.driver_mac()?;
|
||||
let driver_mtu = tap.driver_mtu()?;
|
||||
|
||||
@@ -242,21 +244,29 @@ fn open_tap_adapter(session: &ClientSession) -> Result<OpenedTapAdapter> {
|
||||
|
||||
Ok(OpenedTapAdapter {
|
||||
tap,
|
||||
_metric_guard: metric_guard,
|
||||
_route_guard: route_guard,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn protect_tap_metrics(identity: NetworkInterfaceIdentity) -> Result<TapMetricGuard> {
|
||||
let ipv4 = lanparty_client_route::set_scoped_interface_metric(
|
||||
fn protect_tap_routes(identity: NetworkInterfaceIdentity) -> Result<TapRouteProtectionGuard> {
|
||||
let ipv4_metric = lanparty_client_route::set_scoped_interface_metric(
|
||||
identity,
|
||||
IpInterfaceFamily::Ipv4,
|
||||
TAP_INTERFACE_METRIC,
|
||||
)
|
||||
.context("failed to set TAP IPv4 interface metric")?;
|
||||
print_tap_metric_override(IpInterfaceFamily::Ipv4, &ipv4);
|
||||
print_tap_metric_override(IpInterfaceFamily::Ipv4, &ipv4_metric);
|
||||
|
||||
let ipv6 = match lanparty_client_route::set_scoped_interface_metric(
|
||||
let ipv4_default_routes = lanparty_client_route::set_scoped_default_routes_disabled(
|
||||
identity,
|
||||
IpInterfaceFamily::Ipv4,
|
||||
true,
|
||||
)
|
||||
.context("failed to disable TAP IPv4 default routes")?;
|
||||
print_tap_default_routes_override(IpInterfaceFamily::Ipv4, &ipv4_default_routes);
|
||||
|
||||
let ipv6_metric = match lanparty_client_route::set_scoped_interface_metric(
|
||||
identity,
|
||||
IpInterfaceFamily::Ipv6,
|
||||
TAP_INTERFACE_METRIC,
|
||||
@@ -273,9 +283,28 @@ fn protect_tap_metrics(identity: NetworkInterfaceIdentity) -> Result<TapMetricGu
|
||||
}
|
||||
};
|
||||
|
||||
Ok(TapMetricGuard {
|
||||
_ipv4: ipv4,
|
||||
_ipv6: ipv6,
|
||||
let ipv6_default_routes = match lanparty_client_route::set_scoped_default_routes_disabled(
|
||||
identity,
|
||||
IpInterfaceFamily::Ipv6,
|
||||
true,
|
||||
) {
|
||||
Ok(default_routes) => {
|
||||
print_tap_default_routes_override(IpInterfaceFamily::Ipv6, &default_routes);
|
||||
Some(default_routes)
|
||||
}
|
||||
Err(error) => {
|
||||
eprintln!(
|
||||
"failed to disable TAP IPv6 default routes; IPv6 route protection may be incomplete: {error:#}"
|
||||
);
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
Ok(TapRouteProtectionGuard {
|
||||
_ipv4_metric: ipv4_metric,
|
||||
_ipv4_default_routes: ipv4_default_routes,
|
||||
_ipv6_metric: ipv6_metric,
|
||||
_ipv6_default_routes: ipv6_default_routes,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -290,6 +319,15 @@ fn print_tap_metric_override(family: IpInterfaceFamily, metric: &ScopedInterface
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn print_tap_default_routes_override(family: IpInterfaceFamily, routes: &ScopedDefaultRoutes) {
|
||||
let previous = routes.previous();
|
||||
println!(
|
||||
"TAP {family:?} default routes disabled; previous default-routes-disabled {}",
|
||||
previous.disable_default_routes()
|
||||
);
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
async fn run_tap_frame_pump(relay_io: ClientRelayIo, tap: TapAdapter) -> Result<()> {
|
||||
let tap = Arc::new(tap);
|
||||
|
||||
Reference in New Issue
Block a user