dnsmasq read /etc/resolv.conf to find where to forward. Whatever points a machine at the mesh writes its own address into that file — so dnsmasq's upstream was dnsmasq, and every query it could not answer locally looped. Its receive queue filled with 15KB of them and every lookup on the machine hung, which is why this arrived as a thirty-second timeout rather than a wrong answer. It needs no upstream at all: the asking module routes only the mesh's suffix here and leaves everything else where the machine already sent it. And it names none, because choosing one would send every query this machine makes somewhere nobody agreed to. Also corrected: the comment claiming it takes only 127.0.0.55. Listening on a loopback address makes dnsmasq take the rest of loopback with it, 127.0.0.1 included — which is what claiming `the-dns-port` already says, and which the comment was quietly denying. That is the same comfortable claim as ".54 is free", in the same file, made twice.
Example modules
Manifests, not programs. They are here because the contract is easier to read as something that works than as a description of something that would.
Third-party software runs on the mesh, not of it (novox/hq ADR 0001). dnsmasq is not the mesh's, and neither is systemd-resolved — what is the mesh's is the fact only it can know, which is which machines exist and where they are. So the mesh writes that to a file and these read it.
Resolving a service named under a machine
postgres.novox.internal, plex.ace.internal. The first label is the service and the rest is the
node, so anything under a node's name must resolve to that node and a proxy there routes by
the name it was asked for. That routing is a separate concern and stays separate.
Two roles, and they are genuinely different things:
| claims | ||
|---|---|---|
| serving | the-dns-port |
answers the wildcards — dnsmasq.json |
| asking | the-resolver-configuration |
decides what the machine asks — resolved-split-dns.json, resolv-conf.json |
systemd-resolved cannot serve a wildcard, so it is only ever an asking module: it routes the mesh's suffix to something that can. Treating the two roles as one would produce a module that cannot work, which is the mistake worth naming.
Assign one of each. Two of either is refused by the mesh rather than fought over on the machine:
resolved-split-dns and resolv-conf both claim "the-resolver-configuration", and only one thing may hold it per node
ADR 0009's table names that resource /etc/resolv.conf, which is what it is, the way it writes
the seat. A claim is a name in the catalogue's own form, so it is written as one.
Why neither needs to know the machine's address
Both would ordinarily need it — a resolver must bind somewhere, and a stub must be pointed somewhere — and a static manifest cannot know it.
Neither does, because both name things the mesh itself named: the private network's interface
is mesh0 on every machine, and the address a resolver listens on for the machine's own use is
127.0.0.54 on every machine. A name the mesh chose is a name a manifest can use.