diff --git a/README.md b/README.md index 3b8ae9e..813c23d 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/crates/lanparty-client-win/src/main.rs b/crates/lanparty-client-win/src/main.rs index 75913d3..29bb227 100644 --- a/crates/lanparty-client-win/src/main.rs +++ b/crates/lanparty-client-win/src/main.rs @@ -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, +struct TapRouteProtectionGuard { + _ipv4_metric: ScopedInterfaceMetric, + _ipv4_default_routes: ScopedDefaultRoutes, + _ipv6_metric: Option, + _ipv6_default_routes: Option, } #[cfg(windows)] @@ -206,7 +208,7 @@ fn open_tap_adapter(session: &ClientSession) -> Result { 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 { Ok(OpenedTapAdapter { tap, - _metric_guard: metric_guard, + _route_guard: route_guard, }) } #[cfg(windows)] -fn protect_tap_metrics(identity: NetworkInterfaceIdentity) -> Result { - let ipv4 = lanparty_client_route::set_scoped_interface_metric( +fn protect_tap_routes(identity: NetworkInterfaceIdentity) -> Result { + 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 { + 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);