From 0aacd3e91a55d403971dae109eca45ef08f33a3f Mon Sep 17 00:00:00 2001 From: rustdesk Date: Fri, 18 Sep 2026 16:09:44 +0800 Subject: [PATCH] punch reply: send it to the address the registration runs on `punch_udp_hole` resolved the rendezvous host afresh for every reply, and since hbb_common f688d41 that is the resolver's first answer, not one a handshake proved: with an AAAA published for a daemon that answers only on v4, the PunchHoleSent - the WebRTC answer, the v6 address, the relay server - went to the address the server does not listen on, and UDP loses it without a word. The registration itself kept working over v4, so the device looked online and could not be reached. The mediator holds the address its registration runs on, chosen by `start_udp` through the handshake and replaced on every rebind. The reply goes there: no lookup, no probe, no address family the registration is not already using. The host is resolved only where the registration's address is not an IP, which is not the UDP mediator's case. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns --- src/rendezvous_mediator.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index b039995a8..375c9cb30 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -1216,7 +1216,19 @@ impl RendezvousMediator { ) -> ResultType<()> { let mut msg_out = Message::new(); msg_out.set_punch_hole_sent(msg_punch); - let (socket, addr) = new_direct_udp_for(&self.host).await?; + // To the address the registration runs on, which `start_udp` proved reachable and keeps + // current across rebinds. Resolving the host again could name an address the server does + // not answer on - an AAAA beside a daemon bound to v4 - and a reply sent there is lost. + let (socket, addr) = match &self.addr { + TargetAddr::Ip(addr) => ( + Arc::new( + tokio::net::UdpSocket::bind(Config::get_any_listen_addr(addr.is_ipv4())) + .await?, + ), + *addr, + ), + _ => new_direct_udp_for(&self.host).await?, + }; let data = msg_out.write_to_bytes()?; socket.send_to(&data, addr).await?; // The reply is out, and with it the answer and the v6 address: declined is the listen