Checked why ADR 0104's forward-to-predecessor shape doesn't transfer to the resolver the way it did the proxy: DNS is one process on one port, and assigning the mesh's dnsmasq module replaces it in place, so there is no predecessor process left standing to forward to. But /etc/dnsmasq.d/hal-dns.conf's static address= lines for ace/shanks/g14 match the mesh's own carried-peer addresses from overlay show exactly. The name a carried peer needs isn't a guess the operator has to make under pressure — it's a transcription of a record the predecessor already has and has been correctly serving for six days. Located in mesh-controller (no way to attach a name to a carried peer today) and the dnsmasq module (doesn't emit a wildcard for a named-but-uncarried peer). Not implemented.
4.0 KiB
Diagnosis
2026-09-24 — where the mesh's own record ends, and what stands beside it
Checked the mechanism first. The resolver module's config (mesh-catalog modules/dnsmasq) is
generated whole from nodes.conf, the dnsmasq.fact-node-zones fact mesh-controller computes:
one address=/<node>.<suffix>/<address> wildcard per node the mesh has a name for, plus
local=/<suffix>/ — which tells dnsmasq it is authoritative for the whole suffix, so anything
under it that is not one of those wildcards is refused, not forwarded. That is the exact mechanism
the report describes: the mesh does not lack an upstream to ask, it has told itself there is
nothing to ask.
Checked whether "forward to the resolver it replaced" (the third open question, ADR 0104's shape)
is literal here the way it was for the proxy. It is not, and the difference matters: the proxy's
predecessor kept running throughout its migration, a separate process on ports the mesh's proxy did
not yet hold. DNS has one process on one port. mesh-catalog's dnsmasq module, on assignment,
replaces /etc/dnsmasq.conf whole and restarts the one dnsmasq.service unit — the same unit the
predecessor's own resolver is running as, right now, on this control-node:
$ systemctl status dnsmasq
● dnsmasq.service ... Active: active (running) since Fri 2026-09-18 ...
There is no predecessor process left standing after that assignment for a forward rule to reach. An adapter in ADR 0104's literal shape — a second thing running, written into by a first — does not fit; whatever answers this has to be data carried across the cutover, not a live thing forwarded to across it.
What is actually missing, and where it already exists
The report's first open question — should a carried peer be nameable, the operator saying which machine a carried address is, before it enrols — turns out not to need a guess. The predecessor's own resolver config, still live on this control-node, already states it:
# /etc/dnsmasq.d/hal-dns.conf — Generated by HAL dnsmasq-app
address=/novox.internal/10.10.0.1
address=/ace.internal/10.10.0.2
address=/g14.internal/10.10.0.4
address=/shanks.internal/10.10.0.3
Checked against what the mesh itself recorded when it took the tunnel over (overlay show):
a peer of the tunnel (zTKYP6Sz…) 10.10.0.2 not yet enrolled
a peer of the tunnel (XT1l25Z0…) 10.10.0.3 not yet enrolled
a peer of the tunnel (mq76YPW0…) 10.10.0.4 not yet enrolled
10.10.0.2/.3/.4 match ace/shanks/g14 exactly, one for one. This is not the operator
inventing a fact under time pressure — it is the predecessor's own record, current, and it has been
correctly serving these three names for six days without correction. Recording it is transcription,
not assertion.
located-in, tentatively: mesh-controller internal/catalogue (where a carried peer's fact would
need a name field) and cmd/mesh-controller (a command to set it — nothing today lets an operator
attach a name to a carried-tunnel-peer record; node add is for enrolling nodes, not naming
peers). mesh-catalog modules/dnsmasq would then need to emit an address= wildcard for a named
carried peer the same way it does for a node, which the module's own generation code does not
distinguish today.
What is still open
- The mechanism for recording the name is not designed — a new field on the carried-peer record, a new CLI verb, and what happens if the name later disagrees with what the peer states on enrolling (it should win; nothing says so yet).
- Whether this generalises: the predecessor's static hosts file was the answer here because it happened to be readable and correct. A migration without one still has the report's harder second option (refuse the resolver until every peer enrols) as its fallback.
- Not implemented. This diagnosis is what the fix would touch and why the ADR 0104 framing in the report's third option does not transfer directly — not the fix itself.