diff --git a/README.md b/README.md index 813c23d..9fc485a 100644 --- a/README.md +++ b/README.md @@ -141,5 +141,6 @@ adapter until shutdown. 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 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. +then restores the previous route policy on exit. Until automatic TAP MAC/MTU +configuration is wired, startup fails before bridging if the driver-reported +MAC or MTU does not match the tunnel settings. diff --git a/crates/lanparty-client-win/src/main.rs b/crates/lanparty-client-win/src/main.rs index 29bb227..97214fa 100644 --- a/crates/lanparty-client-win/src/main.rs +++ b/crates/lanparty-client-win/src/main.rs @@ -5,7 +5,7 @@ use std::{ thread, }; -use anyhow::{Context, Result}; +use anyhow::{Context, Result, bail}; use clap::Parser; #[cfg(windows)] use lanparty_client_core::ClientRelayIo; @@ -204,13 +204,19 @@ struct TapRouteProtectionGuard { #[cfg(windows)] fn open_tap_adapter(session: &ClientSession) -> Result { let tap = lanparty_client_tap::open_first_adapter()?; - tap.set_media_connected(true)?; let tap_interface = lanparty_client_route::interface_identity_from_guid(tap.info().instance_id()) .context("failed to resolve TAP interface identity")?; let route_guard = protect_tap_routes(tap_interface)?; let driver_mac = tap.driver_mac()?; let driver_mtu = tap.driver_mtu()?; + validate_tap_driver_settings( + session.config().virtual_mac(), + session.welcome().effective_tap_mtu(), + driver_mac, + driver_mtu, + )?; + tap.set_media_connected(true)?; println!( "lanparty-client-win opened TAP adapter {}", @@ -227,20 +233,6 @@ fn open_tap_adapter(session: &ClientSession) -> Result { tap_interface.index(), tap_interface.luid() ); - if driver_mac != session.config().virtual_mac() { - eprintln!( - "TAP driver MAC {} does not match tunnel identity {}; MAC configuration is not wired yet", - driver_mac, - session.config().virtual_mac() - ); - } - if driver_mtu != u32::from(session.welcome().effective_tap_mtu()) { - eprintln!( - "TAP driver MTU {} does not match relay-selected MTU {}; MTU configuration is not wired yet", - driver_mtu, - session.welcome().effective_tap_mtu() - ); - } Ok(OpenedTapAdapter { tap, @@ -248,6 +240,29 @@ fn open_tap_adapter(session: &ClientSession) -> Result { }) } +#[cfg_attr(not(windows), allow(dead_code))] +fn validate_tap_driver_settings( + expected_mac: MacAddr, + expected_mtu: u16, + driver_mac: MacAddr, + driver_mtu: u32, +) -> Result<()> { + if driver_mac != expected_mac { + bail!( + "TAP driver MAC {driver_mac} does not match tunnel identity {expected_mac}; automatic MAC configuration is not wired yet" + ); + } + + let expected_mtu = u32::from(expected_mtu); + if driver_mtu != expected_mtu { + bail!( + "TAP driver MTU {driver_mtu} does not match relay-selected MTU {expected_mtu}; automatic MTU configuration is not wired yet" + ); + } + + Ok(()) +} + #[cfg(windows)] fn protect_tap_routes(identity: NetworkInterfaceIdentity) -> Result { let ipv4_metric = lanparty_client_route::set_scoped_interface_metric( @@ -403,3 +418,35 @@ fn read_and_relay_tap_frame( fn open_tap_adapter(_session: &ClientSession) { println!("Windows TAP adapter opening is compiled only on Windows"); } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn accepts_matching_tap_driver_settings() { + assert!(validate_tap_driver_settings(mac(1), 1200, mac(1), 1200).is_ok()); + } + + #[test] + fn rejects_tap_driver_mac_mismatch() { + let error = validate_tap_driver_settings(mac(1), 1200, mac(2), 1200).unwrap_err(); + + assert!(error.to_string().contains("does not match tunnel identity")); + } + + #[test] + fn rejects_tap_driver_mtu_mismatch() { + let error = validate_tap_driver_settings(mac(1), 1200, mac(1), 1500).unwrap_err(); + + assert!( + error + .to_string() + .contains("does not match relay-selected MTU") + ); + } + + const fn mac(last_octet: u8) -> MacAddr { + MacAddr::new([0x02, 0, 0, 0, 0, last_octet]) + } +}