Files
hq/02-DECISIONS/0191-the-meshs-resolver-holds-only-the-meshs-own-names.md
T
jschoubben ca8a865e73 ADR 0191: the mesh's names are known by where they were composed, not by their suffix
A progressive insight: the rule and its check were stated as a suffix test; the mesh composes both
names of a route and publishes its internal one. The decision is unchanged.
2026-10-03 15:39:07 +02:00

7.4 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
0066-public-routing-is-name-agnostic.md
0151-a-routes-internal-name-is-composed-under-the-node-that-serves-it.md

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: it composes both names of every route itself, name from the node's public domain and internal-name from its own domain under the serving node (ADR 0151), and publishes the second. Which names are its own is known from where each was composed. 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 publishes into internal resolution only the names it composes for itself — a machine's name, and each route's internal-name, never a route's public name. 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 catalogue tests assert that the names served are routes' internal names and that no route's public name is among them — one published 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