From 96933d6230090df9d73bf98fe736f6359f97a4d9 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Tue, 25 Aug 2026 17:00:45 +0800 Subject: [PATCH] webrtc: choose ICE servers by network, and expose the STUN half Two of the three entries sat on one host, so they failed together - in the same millisecond, on a peer whose route to that host was down. Spend the slots on separate networks instead: two anycast, two unicast, and a :443 for the networks that pass no other UDP port. The note about reading NAT type off two ports of one address goes with them - webrtc-ice queries each URL from its own socket, so that comparison never held, and nothing consumes the result. `stun_servers()` hands the STUN half out, so the IPv6 probe can stop keeping a second hand-written copy and an operator's OPTION_ICE_SERVERS override reaches both paths. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_019UzcMTdYTEv2QbMHcTSUy3 --- src/webrtc.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/webrtc.rs b/src/webrtc.rs index a7bda1c65..41adfef5d 100644 --- a/src/webrtc.rs +++ b/src/webrtc.rs @@ -145,13 +145,14 @@ const FRAG_END: u8 = 0; /// unauthenticated peer can make a receiver hold. Kept at parity with TCP on purpose: one session /// moves between both paths, so a transport-specific ceiling would kill it on the other one. const MAX_RECV_MESSAGE: usize = crate::bytes_codec::MAX_FRAME_LENGTH; -// use 3 public STUN servers to find out the NAT type, 2 must be the same address but different ports -// https://stackoverflow.com/questions/72805316/determine-nat-mapping-behaviour-using-two-stun-servers -// luckily nextcloud supports two ports for STUN -// unluckily webrtc-rs does not use the same port to do the STUN request -static DEFAULT_ICE_SERVERS: [&str; 3] = [ +// Four networks, not four names: webrtc-ice queries each URL from its own socket, so entries +// sharing a host buy no redundancy - the two this list used to carry failed together, in the same +// millisecond, on a peer whose route to that one host was down. Two anycast, two unicast; the 443 +// entry is for networks that pass no other UDP port. +static DEFAULT_ICE_SERVERS: [&str; 4] = [ "stun:stun.cloudflare.com:3478", - "stun:stun.nextcloud.com:3478", + "stun:stun.l.google.com:19302", + "stun:stun.antisip.com:3478", "stun:stun.nextcloud.com:443", ]; @@ -463,6 +464,14 @@ impl WebRTCStream { )) } + /// The default UDP STUN servers as bare `host:port`, for application-level address probes. + pub fn default_stun_servers() -> Vec { + DEFAULT_ICE_SERVERS + .iter() + .filter_map(|url| url.strip_prefix("stun:").map(str::to_owned)) + .collect() + } + /// Split out from `get_ice_servers` so parsing can be exercised without touching the /// process-global, on-disk-persisted option — the tests run in parallel threads of one /// process, so a test that rewrote it raced every peer connection another test was building.