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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019UzcMTdYTEv2QbMHcTSUy3
This commit is contained in:
rustdesk
2026-08-25 17:00:45 +08:00
parent 2f7536527d
commit 96933d6230
+15 -6
View File
@@ -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<String> {
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.