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 itssiblings; - 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_peerdid.
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_secsclamps a smallerother_ttl_secsup 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
peeralready 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
peerin the table without ever duplicating a peer mDNS already knows:find_agentqueries 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.Nonefor 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.