fix(client): fail fast outside Windows

The MVP client only has a real TAP and route-protection runtime on Windows. A
non-Windows build was able to connect to the relay as a no-TAP client and then
wait for control events, which could consume a room slot while giving the false
impression that the Windows client path had been exercised.

Reject normal runtime startup on non-Windows platforms before reading tunnel
inputs or joining the relay. Keep non-Windows builds useful for type checking,
and document that they are not runnable tunnel clients.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-win
- cargo check -p lanparty-client-win
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- cargo run -p lanparty-client-win -- --relay 127.0.0.1:1 \
  --relay-ca-cert /tmp/does-not-matter.der --room ROOM1
- git diff --check
- git diff --cached --check

Refs: MVP Windows TAP client boundary
This commit is contained in:
2026-05-22 08:45:02 +02:00
parent 37293b9999
commit e5f6e44d12
2 changed files with 33 additions and 2 deletions
+6 -2
View File
@@ -235,8 +235,12 @@ cargo run -p lanparty-client-win -- \
--room ROOM1 --room ROOM1
``` ```
The Windows client binary currently connects to the relay as `role = client` The Windows client binary is runtime-gated to Windows because the real client
with a generated locally administered virtual MAC persisted in path depends on TAP-Windows6 and Windows route protection. Non-Windows builds
are useful for type checking, but they fail before tunnel setup instead of
joining a room without a TAP adapter. On Windows, the binary connects to the
relay as `role = client` with a generated locally administered virtual MAC
persisted in
`lanparty-client-identity.json`. Before resolving or connecting to the relay, `lanparty-client-identity.json`. Before resolving or connecting to the relay,
it writes the generated tunnel MAC to the selected TAP driver's it writes the generated tunnel MAC to the selected TAP driver's
`NetworkAddress` registry setting and marks TAP media disconnected. That clears `NetworkAddress` registry setting and marks TAP media disconnected. That clears
+27
View File
@@ -172,6 +172,7 @@ async fn main() -> Result<()> {
return Ok(()); return Ok(());
} }
ensure_supported_platform()?;
let startup_config = args.into_startup_config()?; let startup_config = args.into_startup_config()?;
#[cfg(windows)] #[cfg(windows)]
prepare_tap_before_relay_connect( prepare_tap_before_relay_connect(
@@ -218,6 +219,18 @@ async fn main() -> Result<()> {
run_result run_result
} }
#[cfg(windows)]
fn ensure_supported_platform() -> Result<()> {
Ok(())
}
#[cfg(not(windows))]
fn ensure_supported_platform() -> Result<()> {
bail!(
"lanparty-client-win can only run on Windows; TAP-Windows6 and relay route protection are Windows-only"
)
}
fn print_available_tap_adapters() -> Result<()> { fn print_available_tap_adapters() -> Result<()> {
let adapters = lanparty_client_tap::available_adapters()?; let adapters = lanparty_client_tap::available_adapters()?;
for line in format_tap_adapter_list(&adapters) { for line in format_tap_adapter_list(&adapters) {
@@ -1235,6 +1248,20 @@ mod tests {
use lanparty_net::DEFAULT_RELAY_PORT; use lanparty_net::DEFAULT_RELAY_PORT;
use lanparty_obs::{QuicDiagnostics, TunnelStats}; use lanparty_obs::{QuicDiagnostics, TunnelStats};
#[cfg(not(windows))]
#[test]
fn rejects_runtime_on_non_windows() {
let error = ensure_supported_platform().unwrap_err();
assert!(error.to_string().contains("can only run on Windows"));
}
#[cfg(windows)]
#[test]
fn accepts_runtime_on_windows() {
assert!(ensure_supported_platform().is_ok());
}
#[test] #[test]
fn accepts_matching_tap_driver_mac() { fn accepts_matching_tap_driver_mac() {
assert!(validate_tap_driver_mac(mac(1), mac(1)).is_ok()); assert!(validate_tap_driver_mac(mac(1), mac(1)).is_ok());