controller: the NAT test takes the resolver's address for the server

`new_direct_udp_for` learned which address to send the UDP NAT test to by
opening a TCP connection to the rendezvous server and dropping it - a
handshake, one round trip, on every connection the controller starts,
right before `_start_inner` opens the connection it keeps to the same
host. The NAT test now takes the resolver's preferred address,
`new_direct_udp_for_unverified`, which spends no round trip proving it and
gives its lookup a second: an address the server does not answer on costs
this connection its UDP punch, which the TCP punch and the relay cover, as
they do whenever the test finds no port. The controlled side's punch reply
keeps `new_direct_udp_for` and its proof - a reply sent to such an address
is a device online and unreachable.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns
This commit is contained in:
rustdesk
2026-09-19 00:18:48 +08:00
parent 30c2f07061
commit e001878f06

View File

@@ -57,7 +57,7 @@ use hbb_common::{
rand,
rendezvous_proto::*,
sha2::{Digest, Sha256},
socket_client::{connect_tcp, connect_tcp_local, ipv4_to_ipv6, new_direct_udp_for},
socket_client::{connect_tcp, connect_tcp_local, ipv4_to_ipv6, new_direct_udp_for_unverified},
sodiumoxide::{base64, crypto::sign},
timeout,
tokio::{
@@ -490,7 +490,7 @@ impl Client {
// no need to care about multiple rendezvous servers case, since it is acutally not used any more.
// Shared state for UDP NAT test result
if crate::get_udp_punch_enabled() && !interface.is_force_relay() {
if let Ok((socket, addr)) = new_direct_udp_for(&rendezvous_server).await {
if let Ok((socket, addr)) = new_direct_udp_for_unverified(&rendezvous_server).await {
let udp_port = Arc::new(Mutex::new(0));
let up_cloned = udp_port.clone();
let socket_cloned = socket.clone();