mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-09-20 11:23:14 +03:00
* bump webrtc fork: one IPv6 host candidate per interface and prefix ICE gathered every IPv6 address on every interface. Beside the temporary address that privacy extensions rotate, a prefix usually carries a stable one, often derived from the MAC, that the OS never picks as a source: a host candidate for it hands the peer an identifier that outlives every rotation and that nothing else this machine sends out ever shows. RFC 8445 §5.1.1.1 has the trackable addresses of an interface and prefix left out once a privacy one is gathered. There is no portable way to tell the two apart, so the fork's `local_interfaces` stands in for that rule with a best-effort approximation: of an interface's addresses in one prefix, it asks the OS which one it sends from - a UDP `connect` inside the group's own prefix, nothing sent, nothing outside this machine's own prefixes involved - and if the answer is one of them, keeps that one alone. If the answer is none of them, the whole group is kept, as it was: the probe is bound to no interface, so where Ethernet and Wi-Fi share a LAN the route picks one of them and the answer for the other is an address it does not hold, and the enumeration order would be no better a guess - on macOS its first address is the stable one. Every other interface and prefix keeps its address, a VPN's unique-local one among them. Two static addresses in one prefix keep one, the recorded price of the stand-in; the interface a shared prefix's route bypasses keeps both of its addresses, a gap the stand-in leaves open rather than a regression. The Windows enumeration, which named every adapter "" with no mask, now carries the adapter's name and on-link prefix, without which Ethernet and Wi-Fi on one LAN would have been a single group. That reaches IPv4 too: its addresses carry the adapter's name and mask where they were "" at /32, so the candidates gathered are the same but `interface_filter` sees the real names. hbb_common is untouched: its fe80::/10 filter still applies to what the fork keeps. Two more fork commits ride along, found by the same review. SCTP never reported a DATA chunk received again: `handle_data` asks `can_push` before `push`, and `push` was where a duplicate was noted, so the no-cwnd sender's reordering window, which widens on reported duplicates, never heard of one from another of these endpoints; and the SACK, its gap blocks and now its duplicates unbounded, could outgrow the MTU the DATA chunks keep to under a thousand chunks in flight with holes among them. Duplicates are now listed and SACKed at once (RFC 9260 §6.2), and the SACK reports the lowest gap blocks that fit (§6.7). And the Windows adapter struct, split into nested parts, read `Ipv6IfIndex` eight bytes late on x64 - only into a scope id that `Interface::convert` drops, so nothing gathered wrongly, but the field an interface-bound probe would need; it is flat now, with a compile-time check written for Rust 1.75, the version this crate builds with - `offset_of!` would have wanted 1.77. rustdesk-org/webrtc 80d5a20..49c89bd8, six commits: the heuristic, the fail-open it grew in review, its comments brought in line with that, the SCTP duplicates and SACK bound, the flat Windows adapter struct, and its check made to build on 1.75. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns * pin hbb_common to main 7a5ad52 0eb1759..7a5ad52, six commits: the message cap's tests on WebSocket and WebRTC with the fragmented WebSocket message bounded too (e999dce, f0f1548); hyper_util's debug logs out of the default filters (#608); and `new_direct_udp_for_unverified`, the controller's UDP socket on the resolver's preferred address for the rendezvous server, with a second for the lookup and without the TCP connection `test_target` opens and drops to prove it - while `new_direct_udp_for`, `new_udp_for` and `rebind_udp_for`, which the controlled side's punch reply and its registration live on, keep that proof (f688d41, 0bc8336, 7a5ad52). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns * ipv6 punch: ask the kernel for the route without resolving a name first `test_ipv6` is awaited on the connection path by both sides of a punch, and before it looked for a public IPv6 address in the background it resolved the STUN hosts' names inline - racing the four, so that one resolver that hangs would not decide. It could still: `select_ok` returns the first success or the last failure, so with no resolver answering the probe waits for the slowest lookup to give up, as long as the system resolver takes, once a minute, on the first connection of that minute. The name was never needed. `connect` on a UDP socket sends nothing; it has the kernel pick a route and a source address for the destination, and any global address serves, so the probe now names one - the one libwebrtc's QueryDefaultLocalAddress asks for - and touches no network at all: a bind, a connect, a local_addr. A machine without an IPv6 route learns so from the connect's error, at once, as before. Two smaller things beside it. The minute's gate read the timestamp under one lock and set it under another, so two connections arriving together both found it over and both probed; it is one critical section now. And the background STUN probe, bounded so far by the STUN client's own ten seconds and the resolver's, has a deadline of its own, five seconds: a probe that outlived the minute could write an earlier network's address over a later probe's. Test: the route probe completes within a second, an address found or not. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019aokqJuhjvB3kijXtAg5Ns * 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 --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
11 KiB
11 KiB