# Managed by the mesh. dnsmasq's own defaults are replaced whole rather than # patched, because this module owns the file and a patch would leave whatever # was there before to be discovered later. # # This is one of the mesh's resolvers (novox/hq ADR 0194, 0223): it holds the # `mesh-dns-resolver` seat, which more than one machine may hold, each answering # the same names from the same roster. Every node and every container lists every # holder and no public resolver, so whichever answers first gives the one answer. # It holds the mesh's own names and nothing else (ADR 0191) — the roster is the # mesh's, rendered into each holder; no other copy lives on any machine. # What the mesh computed: one wildcard per machine — its name and everything # under it — and the mesh's own suffix as a local domain, so a name under it is # answered here or not at all and is never asked upstream. Rewritten whenever a # machine joins or leaves, which is why the service below restarts on it: a # reload makes dnsmasq re-read hosts files, not its configuration, and a # wildcard is configuration. conf-file=/etc/mesh-resolver/nodes.conf # Every zone a module answers itself (ADR 0199): one forwarding line per zone, to # the private address of the machine its module runs on and the port its # answerer is published on. Nothing in a zone is answered here; what names a zone # holds is the module's. Rewritten whenever a zone is declared or moves, and the # service restarts on it for the same reason as above. conf-file=/etc/mesh-resolver/zones.conf # Where it answers: this machine's private address, so every node — and every # container on every node, which copies its machine's resolvers — can ask; and # loopback, for this machine's own use. Never a LAN address: a device that is # not a member cannot reach what the mesh's names point at, and a LAN's resolver # is its router's (ADR 0194). # # Named as an ADDRESS and not as the interface that carries it, on purpose. A # container's query is addressed to this address but arrives on the runtime's # bridge, and dnsmasq checks every query against what it was told to answer on: # an `interface=` line admits queries by the interface they arrive on, a # `listen-address=` line by the address they are sent to. With `interface=mesh0` # alone, a query from a container was received and dropped without a word # (novox/hq 04-ISSUES/110). The address admits it whatever bridge it comes in on. # # bind-interfaces, and never bind-dynamic (novox/hq issue 348). bind-dynamic # re-reads the machine's addresses on every change of any link and closes each # listener whose interface that reading did not find; a reading made while the # container runtime deletes a bridge's virtual links fails ("index gone"), and # then every listener is closed until a later change reads cleanly. On # 2026-10-09 the private address was left unbound for twenty minutes, the daemon # running and silent. bind-interfaces binds each address once, at start, and # never closes it. It cannot bind an address that is not there yet, so the unit # waits for it (the drop-in below); a new private address restarts the unit, as # this file changing always did. bind-interfaces listen-address=${machine:address} listen-address=127.0.0.1 # **It must never read resolv.conf to find out where to forward.** This # machine's resolv.conf names this resolver — so a resolver that read it for # upstreams would find itself, and every query it could not answer locally would # loop until its receive queue filled. That is not theoretical: it filled with # 15KB of queries and every lookup on the machine hung. no-resolv makes that loop # impossible: the upstreams are the two lines below, and nothing on the machine # can redirect them. The mesh's own names never reach them: the local= line in # the file above stops them here, answered or refused. no-resolv server=1.1.1.1 server=8.8.8.8 # Both upstreams validate DNSSEC and say so with the Authenticated Data bit, # and this passes that bit down rather than dropping it, which dnsmasq does # unless told. It does not validate itself: an answer's trust is the upstream's # and the path to it, which is what a forwarding resolver's trust always was. # Without it a program that refuses to run behind a resolver that does not # validate — a mail system's admin does exactly that check at start — cannot # use this resolver (novox/hq 04-ISSUES/171). proxy-dnssec # A name without a dot is never forwarded, and reverse lookups of private ranges # are answered here rather than asking the world who 10.x is. domain-needed bogus-priv # **No hosts file, and no operator's files.** This machine's /etc/hosts is its # own — the hosts module's block and the operator's lines (ADR 0199) — and the # mesh's resolver answers every node, so a line written for one machine's own # programs must not become an answer for all of them. Every per-node resolver # went wrong exactly here: a hosts file read once at start, an operator's old # line beside the mesh's, a drop-in read from a directory nobody owned. no-hosts