// dnsmasq's own code, living in the module (novox/hq ADR 0039). dnsmasq here answers the mesh's // generated wildcard names (..) itself and forwards everything else to fixed // upstreams — the predecessor's arrangement, so the machine and its containers ask it for the world. // Its code reads what it was told to answer, and can resolve through itself to prove that it does. import { readFile } from "node:fs/promises"; import { Resolver } from "node:dns/promises"; export interface AnsweredName { /** A machine's internal name, e.g. "anchor.internal" — it and everything under it resolve here. */ name: string; address: string; } export class DnsmasqClient { constructor( private readonly resolverPath: string, private readonly address: string, ) {} /** * Build from the environment. Both values are node-local facts with mesh-chosen defaults — the * wildcard file the module is sent, and the loopback address its config listens on (127.0.0.1, * where the predecessor's resolver answered and every machine's resolv.conf already points) — so * there is nothing to be unconfigured about; it never throws. */ static fromEnv(env: NodeJS.ProcessEnv = process.env): DnsmasqClient { return new DnsmasqClient( env.MESH_DNSMASQ_RESOLVER_PATH ?? "/etc/mesh-resolver/nodes.conf", env.MESH_DNSMASQ_ADDRESS ?? "127.0.0.1", ); } /** The names this resolver answers, read from the mesh-generated wildcard file. */ async answeredNames(): Promise { let text: string; try { text = await readFile(this.resolverPath, "utf8"); } catch { return []; // not yet on the network, or the file has not been written — no names, not an error } const names: AnsweredName[] = []; for (const line of text.split("\n")) { // dnsmasq wildcard syntax the mesh writes: address=/./
. The file also // carries local=//, which names no machine and is not matched here. const match = line.match(/^address=\/([^/]+)\/(.+)$/); if (match) names.push({ name: match[1], address: match[2] }); } return names; } /** Resolve a name through this node's own resolver — the check that wildcard-resolution answers. */ async resolve(name: string): Promise { const resolver = new Resolver(); resolver.setServers([this.address]); try { return await resolver.resolve4(name); } catch { return await resolver.resolve6(name); } } }