feat: WebRTC transport racing, DTLS identity binding, and pc-leak fixes

- prefer-P2P racing (race_transports_prefer_webrtc) across punch and RelayResponse; ICE bridge with 400ms candidate resend
- controlled-side answerer and ICE routing; sign local DTLS fingerprint into SignedId, controller verifies the binding fail-closed
- fix pc leaks: close_webrtc() on insecure-decline paths (io_loop, port_forward); compute direct before disarming the offerer guard
- point hbb_common to the WebRTC data-plane commit 9f5a296

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
rustdesk
2026-07-22 11:18:35 +08:00
parent 7981b65121
commit 07fbbe17b6
8 changed files with 887 additions and 200 deletions

View File

@@ -155,6 +155,9 @@ async fn connect_and_login(
if !stream.is_secured() && !crate::common::is_direct_ip_access(id) {
if !confirm_insecure_connection(&interface, ui_receiver).await {
*close_port_forward = true;
// Close the WebRTC pc on this decline path too (no-op for TCP/WS), matching every
// other exit in this function; a bare drop leaks it in the global session cache.
stream.close_webrtc().await;
return Ok(None);
}
}
@@ -167,6 +170,7 @@ async fn connect_and_login(
tokio::select! {
res = timeout(READ_TIMEOUT, stream.next()) => match res {
Err(_) => {
stream.close_webrtc().await;
bail!("Timeout");
}
Ok(Some(Ok(bytes))) => {
@@ -174,7 +178,13 @@ async fn connect_and_login(
received = true;
interface.update_received(true);
}
let msg_in = Message::parse_from_bytes(&bytes)?;
let msg_in = match Message::parse_from_bytes(&bytes) {
Ok(msg) => msg,
Err(err) => {
stream.close_webrtc().await;
return Err(err.into());
}
};
match msg_in.union {
Some(message::Union::Hash(hash)) => {
if !interface.handle_hash(password, hash, &mut stream).await {
@@ -184,6 +194,7 @@ async fn connect_and_login(
Some(message::Union::LoginResponse(lr)) => match lr.union {
Some(login_response::Union::Error(err)) => {
if !interface.handle_login_error(&err) {
stream.close_webrtc().await;
return Ok(None);
}
}
@@ -200,9 +211,11 @@ async fn connect_and_login(
}
}
Ok(Some(Err(err))) => {
stream.close_webrtc().await;
bail!("Connection closed: {}", err);
}
_ => {
stream.close_webrtc().await;
bail!("Reset by the peer");
}
},
@@ -221,6 +234,7 @@ async fn connect_and_login(
if let Some(Ok(bytes)) = res {
buffer.extend(bytes);
} else {
stream.close_webrtc().await;
return Ok(None);
}
},
@@ -255,5 +269,6 @@ async fn run_forward(forward: Framed<TcpStream, BytesCodec>, stream: Stream) ->
},
}
}
stream.close_webrtc().await;
Ok(())
}