fix(client): configure TAP MAC before relay connect

The Windows startup path opened the TAP adapter to clear stale media state
before loading the persisted tunnel identity and writing the NetworkAddress
registry value. That made the first TAP touch happen with whatever MAC Windows
already had loaded from a previous run.

Build the client runtime config first so the virtual MAC and resolved relay
address are known before TAP activation. The pre-connect TAP preparation now
writes the selected adapter's NetworkAddress value before opening the adapter to
mark media disconnected. The relay route is still pinned only after the relay
handshake, while TAP remains media-disconnected.

This reduces the chance of a first-run or post-crash TAP MAC mismatch during
the manual Windows MVP test. The client still validates the driver-reported MAC
before bridging and still fails closed if Windows has not reloaded the registry
value.

Test Plan:
- cargo test -p lanparty-client-win
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- cargo fmt --check
- git diff --check
- cargo check -p lanparty-client-win --target x86_64-pc-windows-gnu
  - blocked by missing x86_64-w64-mingw32-gcc for ring on this host

Refs: PLAN.md Windows routing / metric handling; TESTING.md MVP guide
This commit is contained in:
2026-05-22 05:43:16 +02:00
parent bd6479e4b5
commit 563a073d24
3 changed files with 29 additions and 17 deletions
+18 -5
View File
@@ -145,10 +145,12 @@ async fn main() -> Result<()> {
return Ok(());
}
#[cfg(windows)]
prepare_tap_before_relay_connect(args.tap_instance_id.as_deref())?;
let config = args.into_config()?;
#[cfg(windows)]
prepare_tap_before_relay_connect(
config.tap_instance_id.as_deref(),
config.session.virtual_mac(),
)?;
println!(
"lanparty-client-win connecting virtual MAC {} to relay {} room {}",
config.session.virtual_mac(),
@@ -201,16 +203,27 @@ fn print_available_tap_adapters() -> Result<()> {
}
#[cfg(windows)]
fn prepare_tap_before_relay_connect(tap_instance_id: Option<&str>) -> Result<()> {
fn prepare_tap_before_relay_connect(
tap_instance_id: Option<&str>,
virtual_mac: MacAddr,
) -> Result<()> {
let adapters = lanparty_client_tap::available_adapters()
.context("failed to list TAP-Windows6 adapters before relay connect")?;
let info = select_tap_adapter(adapters, tap_instance_id)?;
lanparty_client_tap::configure_adapter_mac(&info, virtual_mac).with_context(|| {
format!(
"failed to persist TAP MAC {virtual_mac} for adapter {}",
info.instance_id()
)
})?;
let device_path = info.device_path();
let tap = TapAdapter::open(info)?;
tap.set_media_connected(false)
.with_context(|| format!("failed to mark TAP media disconnected for {device_path}"))?;
println!("prepared TAP adapter {device_path}: media disconnected before relay connect");
println!(
"prepared TAP adapter {device_path}: MAC {virtual_mac} configured and media disconnected before relay connect"
);
Ok(())
}