fix(net): harden port mapper from adversarial review

- Shutdown no longer freezes: Drop signalled stop but then blocked on a
  thread join, and nothing observed stop during the blocking UPnP/NAT-PMP
  discovery (up to ~9s). Drop now waits on a done-channel with a 1s cap
  and detaches otherwise, so quitting is always prompt; the finite lease
  cleans up if we detach mid-discovery. Regression-tested against an
  unresponsive gateway.
- Linux default_gateway() no longer returns 0.0.0.0 for a gateway-less
  (directly-connected) default route — it keeps scanning, matching the
  macOS branch, instead of firing pointless NAT-PMP at the unspecified
  address.
- UPnP now retries AddPortMapping with a permanent (lease 0) mapping when
  the router rejects a timed lease (IGDs that only support permanent
  leases), and renews/removes with the accepted lease.
This commit is contained in:
michel
2026-07-19 21:26:51 +02:00
parent 9f74300c7a
commit 84c571767a
2 changed files with 76 additions and 25 deletions
+6 -1
View File
@@ -196,7 +196,12 @@ pub fn default_gateway() -> Option<Ipv4Addr> {
let gateway = fields.next()?;
if destination == "00000000" {
let raw = u32::from_str_radix(gateway, 16).ok()?;
return Some(Ipv4Addr::from(raw.to_le_bytes()));
// A 0.0.0.0 gateway is a directly-connected default route (no
// next hop): not a usable NAT-PMP gateway. Keep scanning for a
// real one rather than returning the unspecified address.
if raw != 0 {
return Some(Ipv4Addr::from(raw.to_le_bytes()));
}
}
}
None