protocol: enrollment links carry the public name, not the endpoint

Sharing port 443 between the admin UI and the control plane forces two
hostnames — one port and one name is one certificate, and the two need
different ones. That difference had been leaking into every enrollment
link, so an operator handed out fmr-1.echo-lot.app when the thing they
and their users know is fmr.echo-lot.app.

The link now carries the public name and the app asks GET /v1/discover
where to actually connect. The endpoint is plumbing: it exists to select
a certificate, and nobody needs to see it.

Discovery hands out an address and never a pin. The pin stays in the
link. Fetching it over an ordinary TLS connection would make pinning
worth exactly what the certificate authorities are worth, and pinning is
there to survive one the operator does not control — a root injected by
corporate device management, say, which is unremarkable on the networks
this tool gets pointed at. With the pin pre-shared, an intercepted
discovery can only send a device somewhere the pin will not match: an
outage, not a compromise.

Optional on both sides. A server that does not answer, or a link that
already names the control endpoint, works unchanged — enrollment must not
start failing because a lookup did.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrambossek
2026-08-02 00:13:27 +02:00
co-authored by Claude Opus 5
parent a720e84411
commit 082a2314ef
6 changed files with 120 additions and 2 deletions
+25
View File
@@ -111,6 +111,31 @@ DELETE /v1/sessions/{id}
Per-credential and per-source-IP token buckets on: session creation, actions, UDP packets, bytes. `429` on control plane; silent drop on data plane (probes must tolerate loss anyway). All reflected/generated traffic goes **only** to the session's observed source address (or, for connect-back, the source address of the session-creating request). Data-plane responses to unauthenticated packets are never larger than the request (§3.4).
### 2.2 `GET /v1/discover` — where the control plane lives
Unauthenticated, and says almost nothing: the control-plane URL and the server's display name.
```json
{ "control_url": "https://probe.example.net", "name": "example" }
```
It exists so an enrollment link can carry the name a person recognises while the app still connects
to the name that selects the pinned certificate. When a server shares port 443 between its admin UI
and its control plane, those must be different hostnames — one port and one name is one certificate,
and the two need different ones (a browser-trusted certificate, and a long-lived self-signed one the
client pins). Without discovery, the difference leaks into every enrollment link an operator hands
out.
**It hands out an address, never a pin.** The pin travels in the link itself. Serving it here would
reduce pinning to whatever the certificate authorities are worth, and pinning exists precisely to
survive one the operator does not control — a root injected by corporate device management, for
instance, which is unremarkable on the networks this tool is pointed at. Because the pin is
pre-shared, an intercepted discovery response can only send a device to the wrong host, where the
pin will not match: an outage, not a compromise.
Clients treat it as optional. A server that does not answer, or a link that already names the
control endpoint, works unchanged — enrollment must not begin failing because a lookup did.
## 3. UDP probe protocol
### 3.1 Packet header (fixed 32 bytes, network byte order)