{ "module": "systemd-resolved", "version": "1", "upgrade": { "policy": "record", "why": "the machine's names: a build that breaks this resolver stops every name resolving on a machine a person works on, the bus's included, and then neither the gate's rollback nor a push reaches it (hq ADR 0236, ADR 0247)" }, "provides": [ { "name": "split-dns", "reach": "machine" } ], "requires": [ "wildcard-resolution" ], "capabilities": [ "service-manager" ], "claims": [ { "name": "node-resolver", "scope": "node", "serves": [ "routes", "route", "unroute" ] } ], "listens": [ { "name": "dns-udp", "port": 53, "protocol": "udp", "from": "machine", "fixed": true, "why": "this machine's own resolver (ADR 0247), on loopback and on its private address for its own containers; never another machine's, so a VPN's domains routed here are asked by nothing beyond this machine" }, { "name": "dns-tcp", "port": 53, "protocol": "tcp", "from": "machine", "fixed": true, "why": "the same names over tcp, which a resolver answers on for an answer too large for a datagram" } ], "facts": { "kept": { "path": "/etc/node-resolver/resolv.conf", "template": "# Managed by the mesh, and written by the module holding this machine's own resolver\n# (module systemd-resolved, novox/hq ADR 0247). On every other machine the module holding\n# the uplink writes this file, listing the mesh's resolvers (ADR 0223); here something\n# requires names routed by domain - a VPN client's domains to its own servers - so the file\n# names this machine's own resolver alone, which sends those domains over the VPN's link and\n# every other name to the mesh's resolvers. One server listed, so one answer per name.\n#\n# Its address on the private network, not loopback: a container copies this file, and\n# this address is one it can reach. Another program writing this file is put back by the\n# module's guard, which keeps what it wrote for whoever handles it on this machine.\n# Replaced on every push; edit nothing here.\n{{$own := \"\"}}{{range .Machines}}{{if eq .Name $.Node}}{{$own = .Address}}{{end}}{{end}}nameserver {{if $own}}{{$own}}{{else}}127.0.0.53{{end}}\noptions timeout:1 attempts:2 edns0\n" }, "resolved": { "path": "/etc/systemd/resolved.conf.d/50-mesh.conf", "template": "# Managed by the mesh (module systemd-resolved, novox/hq ADR 0247). Replaced on every\n# push; a drop-in of the operator's that sorts after this one overrides it, and is theirs.\n#\n# The mesh's resolvers, every one of them (ADR 0223): they answer every name no link's own\n# domains route elsewhere. ~. makes them the default route for names, and a link's servers\n# answer only the domains routed to them (the module's verb `route`).\n[Resolve]\nDNS={{range index .Holders \"mesh-dns-resolver\"}}{{.Address}} {{end}}\nDomains=~.\n# No compiled-in public fallback: a public resolver beside the mesh's is what ADR 0223\n# removed, because one of them said \"no such name\" for a mesh name and was believed.\nFallbackDNS=\n# The stub on loopback for this machine, and on its private address for its containers,\n# which cannot reach loopback. The packet filter admits this machine's own guests and\n# nobody else: another machine never asks this resolver (ADR 0247).\nDNSStubListener=yes\n{{$own := \"\"}}{{range .Machines}}{{if eq .Name $.Node}}{{$own = .Address}}{{end}}{{end}}DNSStubListenerExtra={{$own}}\n# No cache: nothing on this machine keeps a copy of a mesh name or of a \"no such name\",\n# as before this resolver - each question is asked again (ADR 0223's objection to a\n# local forwarder was a copy disagreeing with the truth).\nCache=no\n# What this machine's own programs read from /etc/hosts they read themselves; containers\n# asking here get what the mesh's resolvers say, as before.\nReadEtcHosts=no\n# Names are the mesh's resolvers' and a routed link's to answer, never the local network's\n# guesses; validation stays the upstreams' (the mesh's resolvers pass the bit through).\nLLMNR=no\nMulticastDNS=no\nDNSSEC=no\nDNSOverTLS=no\n" }, "resolvers": { "path": "/etc/resolv.conf", "template": "# Managed by the mesh, and written by the module holding this machine's own resolver\n# (module systemd-resolved, novox/hq ADR 0247). On every other machine the module holding\n# the uplink writes this file, listing the mesh's resolvers (ADR 0223); here something\n# requires names routed by domain - a VPN client's domains to its own servers - so the file\n# names this machine's own resolver alone, which sends those domains over the VPN's link and\n# every other name to the mesh's resolvers. One server listed, so one answer per name.\n#\n# Its address on the private network, not loopback: a container copies this file, and\n# this address is one it can reach. Another program writing this file is put back by the\n# module's guard, which keeps what it wrote for whoever handles it on this machine.\n# Replaced on every push; edit nothing here.\n{{$own := \"\"}}{{range .Machines}}{{if eq .Name $.Node}}{{$own = .Address}}{{end}}{{end}}nameserver {{if $own}}{{$own}}{{else}}127.0.0.53{{end}}\noptions timeout:1 attempts:2 edns0\n" }, "suffix": { "path": "/etc/node-resolver/suffix", "template": "{{.Suffix}}\n" } }, "resources": [ { "id": "service", "type": "service", "unit": "systemd-resolved.service", "state": "running", "boot": "enabled", "restart-on": [ "systemd-resolved.fact-resolved" ], "health": { "kind": "unit" } }, { "id": "guard", "type": "process", "name": "systemd-resolved-guard", "artifact": "tools", "run": [ "./resolver-tools", "guard" ], "health": { "kind": "unit" } } ], "build": { "artifacts": [ { "name": "tools", "kind": "bundle", "language": "go", "system": "arch", "from": "cmd/resolver-tools", "binary": "resolver-tools", "loads": [ "resolver-tools" ] } ] } }