- PROGRESS.md: hard NAT Phase A, relay cross-wiring, 588 tests - ARCHITECTURE.md: hard NAT port prediction diagram + pattern table - PRD-p2p-direct.md: Phase 8.6 split into a/b/c/d with status - PRD-hard-nat.md: Phase A done, B signal ready, effort table updated - PRD-netcheck.md: port_allocation field + probe documented Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3.4 KiB
PRD: Network Diagnostic (Netcheck)
Phase: Implemented Status: Done (2026-04-14) Crate: wzp-client
Problem
When P2P connections fail or call quality is poor, there is no diagnostic tool to understand why. Users and developers must manually probe STUN, check NAT type, test relay connectivity, and verify port mapping support — all separately. Tailscale's netcheck consolidates all of this into a single diagnostic report.
Solution
A comprehensive run_netcheck() function that probes all network capabilities in parallel and produces a structured NetcheckReport. Exposed as a CLI subcommand (wzp-client --netcheck) and available for in-app diagnostics.
Implementation
New Module: crates/wzp-client/src/netcheck.rs
NetcheckReport:
pub struct NetcheckReport {
pub nat_type: NatType,
pub reflexive_addr: Option<String>,
pub ipv4_reachable: bool,
pub ipv6_reachable: bool,
pub hairpin_works: Option<bool>,
pub port_mapping: Option<PortMapProtocol>,
pub relay_latencies: Vec<RelayLatency>,
pub preferred_relay: Option<String>,
pub stun_latency_ms: Option<u32>,
pub upnp_available: bool,
pub pcp_available: bool,
pub nat_pmp_available: bool,
pub gateway: Option<String>,
pub duration_ms: u32,
pub stun_probes: Vec<NatProbeResult>,
pub port_allocation: Option<PortAllocation>,
}
Probes (all parallel via tokio::join!):
- STUN probes —
probe_stun_servers()to all configured STUN servers - Relay latencies —
probe_reflect_addr()to each configured relay - Port mapping —
acquire_port_mapping()to detect NAT-PMP/PCP/UPnP - Gateway —
default_gateway()for the router address - IPv6 — attempt to bind
[::]:0and send to an IPv6 STUN server - Port allocation —
detect_port_allocation()probes STUN servers from single socket to classify NAT pattern as PortPreserving/Sequential/Random (feeds into hard NAT prediction)
Derived fields:
nat_type/reflexive_addr— fromclassify_nat()on STUN probesipv4_reachable— true if any STUN probe succeededpreferred_relay— relay with lowest RTTport_mapping/nat_pmp_available/pcp_available/upnp_available— from portmap result
Human-readable output: format_report() produces a formatted text report with sections for NAT info, port mapping, STUN probes, relay latencies.
CLI Integration
wzp-client --netcheck <relay-addr> — runs the diagnostic using the specified relay plus default STUN servers, prints the report, and exits.
Deferred
- Hairpin test — send packet from shared endpoint to own reflexive addr to test NAT hairpinning. Architecture is in place (
hairpin_works: Option<bool>) but the actual probe is not yet implemented. - Android/Desktop in-app UI — expose via JNI (Android) and Tauri command (desktop) for user-facing diagnostics.
Files
| File | Change |
|---|---|
crates/wzp-client/src/netcheck.rs |
New — NetcheckReport + run_netcheck + format_report |
crates/wzp-client/src/lib.rs |
Add pub mod netcheck |
crates/wzp-client/src/cli.rs |
--netcheck flag + handler |
Testing
- 5 unit tests: default config, report JSON serialization + roundtrip, RelayLatency serialization, format_report with empty relays, format_report with full data (STUN probes, relay latencies, preferred relay, port mapping)
- 1 integration test (
#[ignore]): full netcheck run