121 lines
7.5 KiB
Markdown
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.
|