feat(client): report TAP IP in diagnostics

Add InterfaceUnicastAddress snapshots to client-route, backed by the Windows
unicast IP address table. The Windows client samples the TAP interface after it
resolves the adapter identity, preferring IPv4 for diagnostics and falling back
to the first address or unknown on lookup failure.

This keeps Win32 IP table handling in the route crate and fills the existing
TapDiagnostics IP field without making bridging depend on DHCP being present.
If DHCP has not assigned an address yet, diagnostics still make that visible as
unknown.

Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-route
- cargo test -p lanparty-client-win
- cargo check -p lanparty-client-route --target x86_64-pc-windows-gnu
- cargo check -p lanparty-client-route --target x86_64-pc-windows-gnu --tests
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check

Attempted:
- cargo check -p lanparty-client-route -p lanparty-client-win
  --target x86_64-pc-windows-gnu

Blocked because ring needs missing x86_64-w64-mingw32-gcc here.

Refs: PLAN.md
This commit is contained in:
2026-05-21 20:20:55 +02:00
parent 2afdae44c6
commit c6dbb78cfc
4 changed files with 235 additions and 11 deletions
+28 -1
View File
@@ -1,3 +1,5 @@
#[cfg(windows)]
use std::net::IpAddr;
use std::{fs, net::SocketAddr, path::PathBuf};
#[cfg(windows)]
use std::{
@@ -342,11 +344,12 @@ fn open_tap_adapter(session: &ClientSession) -> Result<OpenedTapAdapter> {
tap_interface.index(),
tap_interface.luid()
);
let tap_ip = tap_unicast_ip(tap_interface);
let tap_diagnostics = TapDiagnostics::new(
true,
Some(driver_mac),
Some(session.welcome().effective_tap_mtu()),
None,
tap_ip,
);
Ok(OpenedTapAdapter {
@@ -402,6 +405,30 @@ fn optional_label<T: std::fmt::Display>(value: Option<T>) -> String {
value.map_or_else(|| "unknown".to_string(), |value| value.to_string())
}
#[cfg(windows)]
fn tap_unicast_ip(identity: NetworkInterfaceIdentity) -> Option<IpAddr> {
match lanparty_client_route::interface_unicast_addresses(identity) {
Ok(addresses) => preferred_tap_ip(&addresses),
Err(error) => {
eprintln!(
"failed to inspect TAP IP address; diagnostics will report unknown: {error:#}"
);
None
}
}
}
#[cfg(windows)]
fn preferred_tap_ip(
addresses: &[lanparty_client_route::InterfaceUnicastAddress],
) -> Option<IpAddr> {
addresses
.iter()
.find(|address| matches!(address.address(), IpAddr::V4(_)))
.or_else(|| addresses.first())
.map(|address| address.address())
}
#[cfg_attr(not(windows), allow(dead_code))]
fn validate_tap_driver_mac(expected_mac: MacAddr, driver_mac: MacAddr) -> Result<()> {
if driver_mac != expected_mac {