diff --git a/README.md b/README.md index e403b5c..55222aa 100644 --- a/README.md +++ b/README.md @@ -218,11 +218,12 @@ The startup status reports whether the relay already has a LAN gateway for the room. `--virtual-mac` can still override the stored identity for manual testing. On Windows it sets the TAP IP interface MTU to the relay-selected MTU, 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 and disables TAP default routes while it runs, periodically -rechecks that the relay route remains pinned, then restores the previous route -policy on exit. Startup prints a warning when TAP default routes were enabled +TAP media connected for the scoped client run, and reports the driver MAC/MTU +before forwarding frames, along with the TAP interface index/LUID. The client +applies a scoped TAP interface metric and disables TAP default routes while it +runs, periodically rechecks that the relay route remains pinned, then restores +the previous route policy and TAP media status on exit. Startup prints a warning +when TAP default routes were enabled before the scoped protection was applied. Startup still fails before bridging if the driver-reported MAC does not match the tunnel identity, because an already-initialized Windows TAP adapter may need to be disabled/enabled or diff --git a/TESTING.md b/TESTING.md index 1c06ae5..d2982f2 100644 --- a/TESTING.md +++ b/TESTING.md @@ -232,7 +232,7 @@ Uncommon LAN subnets such as `10.73.42.0/24` are safer than `192.168.0.0/24`. ## Cleanup Stop client, gateway, and relay with Ctrl-C. The Windows client restores the TAP -route policy when it exits normally. +route policy and marks TAP media disconnected when it exits normally. Keep `lanparty-client-identity.json` if you want the same virtual MAC on the next run. Delete it only when you intentionally want a new client identity. diff --git a/crates/lanparty-client-win/src/main.rs b/crates/lanparty-client-win/src/main.rs index c9bcdcb..0fcf4c7 100644 --- a/crates/lanparty-client-win/src/main.rs +++ b/crates/lanparty-client-win/src/main.rs @@ -208,6 +208,7 @@ async fn run_client( tap, tap_diagnostics, tap_interface, + _media_guard, _route_guard, } = open_tap_adapter(session, tap_instance_id)?; let relay_route = @@ -396,9 +397,10 @@ fn route_next_hop_label(next_hop: Option) -> String { #[cfg(windows)] struct OpenedTapAdapter { - tap: TapAdapter, + tap: Arc, tap_diagnostics: TapDiagnostics, tap_interface: NetworkInterfaceIdentity, + _media_guard: TapMediaStatusGuard, _route_guard: TapRouteProtectionGuard, } @@ -412,12 +414,38 @@ struct TapRouteProtectionGuard { _ipv6_mtu: Option, } +#[cfg(windows)] +struct TapMediaStatusGuard { + tap: Arc, +} + +#[cfg(windows)] +impl TapMediaStatusGuard { + fn connected(tap: Arc) -> Result { + tap.set_media_connected(true)?; + + Ok(Self { tap }) + } +} + +#[cfg(windows)] +impl Drop for TapMediaStatusGuard { + fn drop(&mut self) { + if let Err(error) = self.tap.set_media_connected(false) { + eprintln!("failed to mark TAP media disconnected during cleanup: {error:#}"); + } + } +} + #[cfg(windows)] fn open_tap_adapter( session: &ClientSession, tap_instance_id: Option<&str>, ) -> Result { - let tap = open_configured_tap_adapter(session.config().virtual_mac(), tap_instance_id)?; + let tap = Arc::new(open_configured_tap_adapter( + session.config().virtual_mac(), + tap_instance_id, + )?); let tap_interface = lanparty_client_route::interface_identity_from_guid(tap.info().instance_id()) .context("failed to resolve TAP interface identity")?; @@ -425,7 +453,7 @@ fn open_tap_adapter( let driver_mac = tap.driver_mac()?; let driver_mtu = tap.driver_mtu()?; validate_tap_driver_mac(session.config().virtual_mac(), driver_mac)?; - tap.set_media_connected(true)?; + let media_guard = TapMediaStatusGuard::connected(Arc::clone(&tap))?; println!( "lanparty-client-win opened TAP adapter {}", @@ -453,6 +481,7 @@ fn open_tap_adapter( tap, tap_diagnostics, tap_interface, + _media_guard: media_guard, _route_guard: route_guard, }) } @@ -908,8 +937,7 @@ fn tap_default_routes_override_message(family: &str, previous_disabled: bool) -> } #[cfg(windows)] -async fn run_tap_frame_pump(relay_io: ClientRelayIo, tap: TapAdapter) -> Result<()> { - let tap = Arc::new(tap); +async fn run_tap_frame_pump(relay_io: ClientRelayIo, tap: Arc) -> Result<()> { let (tap_error_tx, tap_error_rx) = mpsc::channel(); spawn_tap_reader(Arc::clone(&tap), relay_io.clone(), tap_error_tx)?;