fix(client): fail fast on TAP identity mismatch
The Windows client now validates the driver-reported TAP MAC and MTU before it marks the adapter media connected or starts bridging frames. If the TAP driver settings do not match the tunnel identity and relay-selected MTU, startup fails with a direct error instead of continuing into a session that would drop frames or advertise the wrong L2 identity. This is intentionally a correctness guard, not automatic configuration yet. Until TAP MAC and MTU configuration are wired, the safe behavior is to fail before traffic can flow. Route protection is still applied before validation and restored if validation fails during startup. 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. Test Plan: - cargo fmt --check - cargo test -p lanparty-client-win - cargo clippy -p lanparty-client-win --all-targets -- -D warnings - cargo test --workspace - cargo clippy --workspace --all-targets -- -D warnings - git diff --check Refs: PLAN.md
This commit is contained in:
@@ -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<OpenedTapAdapter> {
|
||||
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<OpenedTapAdapter> {
|
||||
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<OpenedTapAdapter> {
|
||||
})
|
||||
}
|
||||
|
||||
#[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<TapRouteProtectionGuard> {
|
||||
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])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user