ADR 0196: a node asks the mesh's resolver first, and a public one only when it is silent
ADR 0194 rejected sending every query to the mesh's resolver because a node with its tunnel down would resolve nothing; a public resolver listed second answers exactly then. That drops the systemd-resolved stub and the runtime's dns: containers copy the machine's resolvers. Narrows 0194; amends connectivity §2.
This commit is contained in:
@@ -10,6 +10,7 @@ code:
|
||||
- mesh-host internal/apply (the service that reflects a rule set)
|
||||
updated: 2026-10-03
|
||||
decisions:
|
||||
- 02-DECISIONS/0196-a-node-asks-the-meshs-resolver-first-and-a-public-one-only-when-it-is-silent.md
|
||||
- 02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md
|
||||
- 02-DECISIONS/0191-the-meshs-resolver-holds-only-the-meshs-own-names.md
|
||||
- 02-DECISIONS/0180-the-found-front-end-is-uninstalled-once-a-machine-is-converged.md
|
||||
@@ -292,8 +293,9 @@ expensively enough to be worth restating:
|
||||
that name for everything else that needs it.
|
||||
|
||||
**What the host receives:** what to ask, not what to answer. The mesh has **one resolver**, holding
|
||||
every node's internal domain; a node routes the mesh's suffix to it and every other name to public
|
||||
resolvers ([ADR 0194](../../02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md)).
|
||||
every node's internal domain; a node asks it first and a public resolver only when it is silent
|
||||
([ADR 0194](../../02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md),
|
||||
[ADR 0196](../../02-DECISIONS/0196-a-node-asks-the-meshs-resolver-first-and-a-public-one-only-when-it-is-silent.md)).
|
||||
|
||||
**What goes away:** the `/etc/hosts` floor. It exists because a node had to reach the mesh
|
||||
database before its own DNS existed; with [ADR 0004](../../02-DECISIONS/0004-a-node-and-how-it-joins.md)
|
||||
@@ -355,21 +357,25 @@ machine — declared or not — is what a nameserver in `resolv.conf` would be f
|
||||
|
||||
*2026-10-03.* **The mesh's names live in one place: the module holding `mesh-resolver`**, a mesh-scoped
|
||||
seat of capacity one, placed on the node every tunnel converges on. It holds one wildcard per node —
|
||||
`<node>.internal` and everything under it — and listens on the private network only. Every node's
|
||||
`node-resolver-config` routes the mesh's suffix to it and leaves every other name with public
|
||||
resolvers; plain `resolv.conf` cannot route by domain, so the asking side is a stub that can — a
|
||||
`systemd-resolved` module claiming `node-resolver-config` in place of `resolv-conf`, routing the
|
||||
suffix to `mesh-resolver`. The container runtime cannot use a loopback stub, so its `dns` names
|
||||
`mesh-resolver`, which forwards public names for containers — the one place a public name passes
|
||||
through the mesh
|
||||
([ADR 0194](../../02-DECISIONS/0194-the-mesh-has-one-resolver-and-every-node-asks-it-for-the-meshs-names.md)).
|
||||
`<node>.internal` and everything under it — and listens on the private network only. It answers the
|
||||
mesh's names from what it holds and forwards every other name, giving the public answer.
|
||||
|
||||
**Every node asks it for everything, and a public resolver only when it is silent.** The module
|
||||
holding `node-resolver-config` writes `/etc/resolv.conf` naming `mesh-resolver` first and a public
|
||||
resolver second, with a short timeout and one attempt: the C library moves to the second only when the
|
||||
first does not answer — the anchor or the tunnel down, a captive portal holding the tunnel back — so
|
||||
public names keep resolving then, and `.internal` is never asked of a public resolver while the mesh's
|
||||
answers. Containers take the same two from their machine, the runtime copying non-loopback resolvers
|
||||
into every container, so the runtime is given no `dns` of its own
|
||||
([ADR 0196](../../02-DECISIONS/0196-a-node-asks-the-meshs-resolver-first-and-a-public-one-only-when-it-is-silent.md),
|
||||
replacing ADR 0194's per-node `systemd-resolved` stub).
|
||||
|
||||
**No node holds a copy.** The per-node resolver, its zones file and the mesh's region of `/etc/hosts`
|
||||
go: every resolution fault found on 2026-10-03 was a copy disagreeing with the truth — a hosts file
|
||||
read once at start, an operator's old line beside the mesh's, a node's resolver lent to a LAN. No
|
||||
member's resolver answers a LAN; a router pointing at one is moved first. *Checked by `resolvectl` on
|
||||
each node (the tunnel's link, `mesh-resolver`, the suffix as routing domain), by no node but the
|
||||
holder answering DNS on a private or LAN address, and by the router's DHCP DNS option naming no node.*
|
||||
member's resolver answers a LAN; a router pointing at one is moved first. *Checked by each node's
|
||||
`/etc/resolv.conf` naming `mesh-resolver` then a public resolver, by no node but the holder answering
|
||||
DNS on any address, and by the router's DHCP DNS option naming the router.*
|
||||
|
||||
*What follows describes the per-node resolver this replaces — how it was built and why the roles were
|
||||
split. The split stands; the serving role's scope is what moved.*
|
||||
|
||||
Reference in New Issue
Block a user