Files
hq/02-DECISIONS/0191-the-meshs-resolver-holds-only-the-meshs-own-names.md
T

121 lines
7.5 KiB
Markdown

---
topic: the tiers
status: accepted
date: 2026-10-03
deciders: jochen
reconstructed: false
supersedes-in-part:
- 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, 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](0066-public-routing-is-name-agnostic.md) 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](0151-a-routes-internal-name-is-composed-under-the-node-that-serves-it.md) 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](0148-the-meshs-names-are-resolved-not-copied-into-containers.md)).
**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](0066-public-routing-is-name-agnostic.md), whose
propagation clause this replaces.
- [ADR 0151 — a route's internal name is composed under the node that serves it](0151-a-routes-internal-name-is-composed-under-the-node-that-serves-it.md),
which made the private answer unnecessary.
- [Connectivity design §2 and §5](../03-DESIGN/01-to-be/08-connectivity.md), amended alongside this
record.