fix(obs): warn on TAP link-local IPv4
IPv4 link-local on the TAP adapter means Windows self-assigned APIPA because LAN DHCP did not complete through the tunnel. The previous user diagnostic only said "TAP IP detected", which made a failed DHCP path look neutral during MVP testing. Return a full UserDiagnostic from TAP IP classification so IPv4 link-local can be a warning while normal IPv4 still reports the received DHCP address. Keep IPv6 link-local neutral because it is expected on many Windows interfaces and is not evidence of LAN DHCP success or failure. TESTING.md now tells the operator to troubleshoot 169.254.x.x like `Waiting for TAP IP`. Test Plan: - cargo test -p lanparty-obs - cargo test -p lanparty-client-win - cargo test --workspace - cargo clippy --workspace --all-targets -- -D warnings - cargo fmt --check - git diff --check Refs: PLAN.md diagnostics; TESTING.md MVP guide
This commit is contained in:
@@ -242,6 +242,10 @@ If the client says `Waiting for TAP IP`, DHCP is not making the full round trip.
|
||||
Check relay/gateway frame logs for broadcast traffic and check that the gateway
|
||||
is on wired Ethernet.
|
||||
|
||||
If the client reports a TAP link-local address such as `169.254.x.x`, treat it
|
||||
the same way: Windows has self-assigned an address, but LAN DHCP did not
|
||||
complete through the tunnel.
|
||||
|
||||
If startup fails with a TAP MAC mismatch, disable/enable the TAP adapter or
|
||||
reinstall TAP-Windows6 so Windows reloads the `NetworkAddress` value. Do not
|
||||
continue with a mismatched MAC.
|
||||
|
||||
@@ -434,8 +434,8 @@ impl ClientDiagnostics {
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(message) = tap_ip_user_message(self.tap.ip()) {
|
||||
diagnostics.push(UserDiagnostic::new(UserDiagnosticLevel::Info, message));
|
||||
if let Some(diagnostic) = tap_ip_user_diagnostic(self.tap.ip()) {
|
||||
diagnostics.push(diagnostic);
|
||||
}
|
||||
|
||||
if let Some(rtt_ms) = self.quic.relay_rtt_ms() {
|
||||
@@ -456,10 +456,20 @@ impl ClientDiagnostics {
|
||||
}
|
||||
}
|
||||
|
||||
fn tap_ip_user_message(ip: Option<IpAddr>) -> Option<String> {
|
||||
fn tap_ip_user_diagnostic(ip: Option<IpAddr>) -> Option<UserDiagnostic> {
|
||||
match ip {
|
||||
Some(IpAddr::V4(ip)) if !ip.is_link_local() => Some(format!("DHCP received: {ip}")),
|
||||
Some(ip) => Some(format!("TAP IP detected: {ip}")),
|
||||
Some(IpAddr::V4(ip)) if ip.is_link_local() => Some(UserDiagnostic::new(
|
||||
UserDiagnosticLevel::Warning,
|
||||
format!("TAP has link-local IP {ip}; waiting for LAN DHCP"),
|
||||
)),
|
||||
Some(IpAddr::V4(ip)) => Some(UserDiagnostic::new(
|
||||
UserDiagnosticLevel::Info,
|
||||
format!("DHCP received: {ip}"),
|
||||
)),
|
||||
Some(ip) => Some(UserDiagnostic::new(
|
||||
UserDiagnosticLevel::Info,
|
||||
format!("TAP IP detected: {ip}"),
|
||||
)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
@@ -712,14 +722,21 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn avoids_calling_link_local_tap_ip_dhcp() {
|
||||
fn reports_link_local_tap_ipv4_as_waiting_for_lan_dhcp() {
|
||||
let diagnostic = tap_ip_user_diagnostic(Some("169.254.10.20".parse().unwrap())).unwrap();
|
||||
|
||||
assert_eq!(diagnostic.level(), UserDiagnosticLevel::Warning);
|
||||
assert_eq!(
|
||||
tap_ip_user_message(Some("169.254.10.20".parse().unwrap())),
|
||||
Some("TAP IP detected: 169.254.10.20".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
tap_ip_user_message(Some("fe80::1".parse().unwrap())),
|
||||
Some("TAP IP detected: fe80::1".to_string())
|
||||
diagnostic.message(),
|
||||
"TAP has link-local IP 169.254.10.20; waiting for LAN DHCP"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn reports_ipv6_link_local_tap_ip_without_calling_it_dhcp() {
|
||||
let diagnostic = tap_ip_user_diagnostic(Some("fe80::1".parse().unwrap())).unwrap();
|
||||
|
||||
assert_eq!(diagnostic.level(), UserDiagnosticLevel::Info);
|
||||
assert_eq!(diagnostic.message(), "TAP IP detected: fe80::1");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user