Skip to main content

Module udp_peers

Module udp_peers 

Source
Expand description

Desktop-to-desktop discovery that does not depend on mDNS (docs/specs/SPEC_LAN_FIREWALL_SETUP_2026_10_01.md §4.7 item 5, docs/specs/SPEC_LAN_UDP_PEER_DISCOVERY_2026_10_02.md).

mDNS can fail for reasons nothing on our side can fix: another program holds UDP 5353 (Area54, 2026-10-01: Chrome, then the DNS Client service), a guest network filters multicast, an interface never gets a socket. The UDP probe responder on 47891 only ever served mobile clients, so two desktops had one route to each other and no second.

Each instance binds one UDP port (DESKTOP_DISCOVERY_PORT) while LAN is on and, from that same socket:

  • sends the existing probe to the limited broadcast address and to each interface’s directed broadcast every PROBE_INTERVAL;
  • answers a probe from a private-range source with the identity payload the 47891 responder sends (probe_response_json), without its siblings;
  • reads identity payloads that come back and records the sender as a peer.

Probing and answering share one socket on purpose: a peer’s reply goes to the probe’s source port, so it lands on a port the firewall rule names rather than on an ephemeral one.

Trust is the same as mDNS. A reply is network-claimed and unauthenticated, exactly like a TXT record; what it gains an attacker is a place in the peer table, not an identity. Jekt signing and LAN key pinning are untouched. The limits below (private-range source, field sizes, port floor, a peer cap) are the same defence in depth the mDNS path has.

Like the 47891 responder this socket does not set SO_REUSEADDR, so only the first instance on a host holds it. A second instance (a task dev build next to an installed one) quietly does without; hosts with one install are the case this exists for.

Structs§

UdpPeer 🔒
The identity a peer’s reply claims, after validation.

Enums§

Merge 🔒
What merge_udp_peer did.

Constants§

DESKTOP_DISCOVERY_PORT 🔒
UDP port for desktop-to-desktop discovery. Inside the fixed block (lan_ports::LAN_PORT_RANGE, below every OS’s ephemeral range) so one firewall rule can name it. UDP and TCP port numbers are separate, so sharing a number with a TCP listener in the block is harmless.
MAX_AUTH_KEY_LEN 🔒
MAX_CHANNEL_LEN 🔒
MAX_HOSTNAME_LEN 🔒
MAX_ID_LEN 🔒
MAX_UDP_PEERS 🔒
Peers learned over UDP at once. An unauthenticated broadcast must not be able to grow the table without bound; a real LAN has a handful of machines.
MAX_VERSION_LEN 🔒
MIN_PEER_PORT 🔒
Below this a port is privileged or a well-known service, never one of ours.
PROBE_INTERVAL 🔒
How often each instance probes.
UDP_KEY_PREFIX 🔒
Key prefix of a peer learned over UDP in LanDiscovery::instances (mDNS peers are keyed by their service name).
UDP_PEER_TTL_SECS 🔒
How long a UDP-learned peer stays listed after its last reply. This is the staleness floor every peer gets (peer_staleness_window_secs clamps a smaller other_ttl_secs up to it), so it is the real lifetime, not a hint: ten missed probes. A departed peer therefore lingers five minutes, which is still far shorter than an mDNS peer’s TTL.

Functions§

drop_udp_duplicates 🔒
Remove UDP-learned entries that an mDNS entry now covers (the same address and port). Called after an mDNS resolution so the order the two routes find a peer in does not decide whether it is listed twice. Instance ids are not compared: they are per release, not per machine (see udp_key).
find_existing 🔒
The same peer as peer already in the table, by the one identity that is unique on a LAN: the address it answers on and the port it serves.
local_broadcasts 🔒
The directed broadcast address of every usable local IPv4 interface.
merge_udp_peer 🔒
Record peer in the table without ever duplicating a peer mDNS already knows: find_agent queries every entry, so a double would double every lookup. An mDNS entry is authoritative and only has its liveness refreshed.
parse_peer_reply 🔒
Validate a datagram as a peer’s identity reply from src. None for noise, a probe, another protocol version, a source outside the private ranges, or any field that is missing, empty or implausibly large.
probe_datagram 🔒
The probe datagram. The same one a mobile client sends, so every responder in the field already understands it.
probe_targets 🔒
Where to send a probe: the limited broadcast address, plus each non-loopback IPv4 interface’s directed broadcast. The limited broadcast alone leaves by one interface only on Windows, which is the wrong one on a host with a VPN or a virtual adapter (narko has four).
udp_key 🔒
A UDP peer’s key: the address its reply came from and the port it serves.