7.5 KiB
topic, status, date, deciders, reconstructed, supersedes-in-part
| topic | status | date | deciders | reconstructed | supersedes-in-part | ||
|---|---|---|---|---|---|---|---|
| the tiers | accepted | 2026-10-03 | jochen | false |
|
191. The mesh's resolver holds only the mesh's own names; a public name resolves publicly
Progressive insight — 2026-10-03. The first implementation told the mesh's names from public ones by their spelling — a name ending in the mesh suffix — and this record said so: the Decision read "only names under its own suffix", and the roster check "every name the roster carries ends in the mesh suffix". The mesh needs no such test, nor any per-route name: domains are a node's. A node has one internal domain,
<node>.internal, and every route on it is a name under that domain (ADR 0151), answered by one wildcard per node; a node has one or more public domains, which public DNS answers. So the mesh's resolver holds the nodes' internal domains and nothing else, and the roster carries the machines and no routed name. Both sentences now say that; what was decided — a public name is never given a private answer — is unchanged.
Context
ADR 0066 published every routed name into internal resolution, mesh-wide, at the address of the node that serves it. The reason was an internal certificate authority in the lab: it validates by connecting to the name it certifies, and a routed public name that nothing inside the mesh resolved could not be certified. ADR 0151 kept it: the roster publishes it as itself, once, at the serving node's address.
So every machine's resolver answered public names with private-network addresses. On a
production mesh on 2026-10-03, each machine's hosts region carried 47 lines of the form
<private address> <label>.<public domain> — every public name of the control-node at its tunnel
address, every public name of the home server at its own. For the machines themselves this is merely
a detour: their traffic to a public name goes through the tunnel instead of the internet.
For anything that is not a member it is an outage. The home server's resolver also answers its LAN — a listen address added as a setting on 2026-10-02. A phone on that LAN asked for the mail server's public name, was given the control-node's tunnel address, and could not connect: couldn't connect to host, port: 10.10.0.1:143. Every public name of the mesh failed the same way for every non-member on that LAN — a phone, a television, a guest — while every check the mesh runs reported success, because every check runs from a member.
And the reason for publishing them is gone. ADR 0151 gave every route an internal name,
<label>.<serving node>.internal, under the node's own name. It resolves inside the mesh without any
entry of its own, the proxy serves it, and the internal authority certifies it — the proxy has two
authorities since 2026-09-25: a public one for public names, the internal one for internal names.
Measured the same day: drive.<control-node>.internal resolves to the control-node's tunnel address
and answers 200 with a certificate that verifies against the internal root. Nothing the mesh runs
needs a public name to resolve to a private address. The one consumer that did — an internal
authority validating a public name — is the case the second authority removed.
The predecessor's resolver held exactly this and no more: an address per machine under .internal,
and everything else forwarded to public resolvers.
Considered Options
1. Keep publishing public names; stop the resolver answering the LAN. Fixes the phone and nothing else. The mesh would still hold a second, private answer for names the public DNS already answers — two answers for one name, which disagree by design and are correct in different places. And it forbids a reasonable setup: a home server's resolver serving its own LAN.
2. Answer per source: private addresses to members, public ones to everyone else. Split-horizon by client. It is what a resolver serving two audiences would need if the private answer were worth giving. It is not — option 3 shows nothing needs it — and it makes a name's address depend on who asks, which is the hardest kind of fault to see from a member.
3. The mesh's resolver holds only the mesh's own domain. Names under the mesh suffix — machines, and routes' internal names under them — resolve to private addresses. Every other name, including every public name the mesh serves, is forwarded and resolves publicly. Chosen.
Decision
The mesh's resolver holds each node's internal domain and nothing else — <node>.internal and
everything under it, at that node's private address. A machine's name,
and through it every <label>.<node>.internal, resolve to that machine's private address. A public
name is never given a private answer by the mesh: it resolves through public DNS to the public
address, from members and non-members alike.
This replaces ADR 0066's clause "when the proxy is granted a name, the mesh publishes that name → the node that serves it into internal resolution, mesh-wide", and ADR 0151's "the roster publishes it as itself, once, at the serving node's address." Everything else in both stands: the label, the node's public domain, the composition, and the internal name under the serving node.
Inside the mesh, a route is reached by its internal name. A container or a validator that must
reach a routed service inside the mesh uses <label>.<node>.internal; the internal authority
certifies that name, and a public authority certifies the public one. A mesh with no public
reachability — the lab — certifies its internal names and has no public names to resolve.
Consequences
- A resolver serving a LAN is safe. What it adds to public resolution is the mesh's own domain, which no public resolver answers.
- A member reaches a public name over the internet, as anyone does. A route the proxy restricts to the private network is reached by its internal name, never by its public one — a public name is, by this decision, public.
- The internal authority certifies internal names only. It was the only consumer of a public name's private answer; the proxy's second authority already took that role away from it.
- Public names leave every machine's hosts region on the first push after the change. Containers do not move with it: the roster is not part of a container's identity (ADR 0148).
How each is checked:
- The roster: the controller's tests assert that the roster names the machines and nothing else — a routed name in it, public or internal, fails the build.
- On a machine: asking the machine's resolver for a public name the mesh serves returns the public address, and asking it for that route's internal name returns the private one. Asked from a non-member on a LAN the resolver answers, the first must hold as well.
References
- ADR 0066 — public routing is name-agnostic, whose propagation clause this replaces.
- ADR 0151 — a route's internal name is composed under the node that serves it, which made the private answer unnecessary.
- Connectivity design §2 and §5, amended alongside this record.