009. Probe candidates before setting a WireGuard endpoint

Status: accepted

Context

A peer announces several candidate endpoints: LAN addresses, a reflexive address, maybe a configured one. Only some will work. The obvious approach — "spray WireGuard handshakes at all of them and let the best win" — is what Nebula does.

Decision

Probe with small encrypted packets first (internal/disco), then set the one that answered as WireGuard's endpoint.

Why

WireGuard holds exactly one endpoint per peer. You cannot spray at five candidates concurrently; you would be overwriting the endpoint under yourself and could not tell which attempt succeeded. Nebula can spray because it owns its own protocol end to end; we are driving WireGuard.

Probing separately also buys two things:

The rule that silently breaks punching if wrong: a ping is answered to the address it arrived from, never to an announced one. Under endpoint-dependent mapping a peer creates a different external port per destination, so the observed address is the only one that can reach it.

Packets are encrypted rather than merely authenticated — see the commit history; MAC-only left the sender's 32-byte device key in cleartext on every probe, a stable identifier that follows the device between networks.

Consequences