From 578a95289f1a2be48d1847ce7b660b3fccc1f3e0 Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 7 Aug 2026 11:56:56 +0800 Subject: [PATCH] ws: read the all-ICE declaration from the offer envelope, drop the proto field MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Companion to hbb_common 68d2729: the full-ICE declaration now lives as an `ice_policy: "all"` key inside the webrtc:// envelope, so the request assembly no longer sets webrtc_all_ice and the controlled side asks the envelope (endpoint_declares_all_ice) instead of a PunchHole field. The rendezvous server carries the offer opaquely — no forwarding to keep in sync. Skew behavior is unchanged: an unmarked or unparseable envelope reads as the old Relay-only semantics. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01ExUfAkYbq8UC9pQCiLy8TQ --- src/client.rs | 9 +++++---- src/rendezvous_mediator.rs | 12 +++++++----- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/client.rs b/src/client.rs index 209c7bd6d..9a1808b38 100644 --- a/src/client.rs +++ b/src/client.rs @@ -612,7 +612,8 @@ impl Client { /// is configured, so skip building a guaranteed-dead pc + STUN/TURN gathering + answerer /// signaling in that case. WebSocket-forced relay is deliberately NOT policy: ws only /// tunnels the signaling/relay legs, so the offer keeps full ICE and may land a direct - /// connection - the flagship path for ws deployments (`webrtc_all_ice` tells the peer). + /// connection - the flagship path for ws deployments (the offer envelope's `ice_policy` + /// key tells the peer). /// When policy relay *and* TURN are configured, WebRTC via TURN is a valid "relayed" path: /// `connect` keeps a WebRTC win instead of replacing it with the RustDesk relay, and the /// RelayResponse path races it without a P2P preference delay. Any request carrying an offer @@ -888,10 +889,10 @@ impl Client { force_relay: interface.is_force_relay(), socket_addr_v6: ipv6.1.unwrap_or_default(), switch_code, + // The offer's envelope itself declares its ICE policy (`ice_policy: "all"` under + // pure ws), telling the controlled side its answer may gather every candidate + // type despite force_relay instead of requiring TURN. webrtc_sdp_offer: webrtc_sdp_offer.clone(), - // Full-ICE offer despite force_relay (ws transport): tells the controlled side - // its answer may gather every candidate type instead of requiring TURN. - webrtc_all_ice: !webrtc_sdp_offer.is_empty() && !interface.is_policy_relay(), ..Default::default() }); let webrtc_session_key = webrtc_offerer diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index 3db47f7d3..4adafc2f1 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -849,11 +849,13 @@ impl RendezvousMediator { // and STUN bypass the proxy and leak the real IP. WebSocket mode does NOT disable it — // ws only tunnels the signaling/relay legs to the server, classic punching stays forced // to relay (`relay` above), and the answer rides the RelayResponse, leaving ICE as the - // only P2P path there. force_relay depends on why it was set: with webrtc_all_ice the - // controller's relay is transport-forced (ws) and its offer carries every candidate - // type, so answer with full ICE and let a direct pair form; without it the offer is - // Relay-only ICE by policy, viable (and answerable) only through TURN. - let webrtc_relay_only = ph.force_relay && !ph.webrtc_all_ice; + // only P2P path there. force_relay depends on why it was set, and the offer's envelope + // says which: an `ice_policy: "all"` declaration means the controller's relay is + // transport-forced (ws) and its offer carries every candidate type, so answer with + // full ICE and let a direct pair form; without it the offer is Relay-only ICE by + // policy, viable (and answerable) only through TURN. + let webrtc_relay_only = ph.force_relay + && !WebRTCStream::endpoint_declares_all_ice(&ph.webrtc_sdp_offer); let webrtc_viable = !ph.webrtc_sdp_offer.is_empty() && !Config::is_proxy() && (!webrtc_relay_only || WebRTCStream::has_turn_server());