Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/nix/host-modules/hive-gateway/dnsmasq.nix

94 lines
4.6 KiB
Nix

# Hive-internal DNS resolver + DHCP, running on the host alongside the
# gateway's nginx — single front-door for both DNS and HTTP, and no
# container of its own. Listens on the bridge interface from
# `services.hyperhive.network`; authoritative for the hive domain +
# sub-domains, forwards everything else upstream. Returns the
# `services.dnsmasq` value (see ./default.nix); the DHCP pool bounds
# are computed by hive-network.
{
lib,
cfg, # services.hyperhive.gateway
networkCfg,
hyperhiveDomain,
}:
let
# The domains this resolver answers itself: the hive domain and every
# name a module contributed.
localDomains = lib.optional (hyperhiveDomain != null) hyperhiveDomain ++ lib.unique cfg.localNames;
in
{
enable = true;
# ON for its *plumbing*, not for the address it publishes.
#
# This flag does two separable things upstream. The one that matters
# here: it points dnsmasq's own upstream servers at a SEPARATE file
# (`resolv-file = /etc/dnsmasq-resolv.conf`, kept current by
# resolvconf). Without that, dnsmasq reads `/etc/resolv.conf` for its
# upstreams — so the moment the host's resolver is pointed at dnsmasq,
# every non-hive query goes in a circle.
#
# The other thing it does is publish `127.0.0.1` as the host's
# nameserver, which is the wrong address for this hive: see the
# `nameservers` override in ./default.nix, where the reason lives.
resolveLocalQueries = true;
settings = {
# Bind only on the bridge interface (and lo for health-checks).
# Outside hosts can't even see the listener.
interface = [
networkCfg.bridgeName
"lo"
];
bind-interfaces = true;
port = 53;
# Authoritative for the hive domain via the `address` rules below —
# must not fall back to the host's /etc/hosts. dnsmasq reads
# /etc/hosts by default, and `gateway.localHostsEntry` populates it
# with 127.0.0.1 for every hive name (host-side dev convenience,
# see default.nix). Since moving dnsmasq onto the host, that
# file is now the *same* /etc/hosts dnsmasq reads for agent queries
# — its entries win over `address=`, so every agent resolves the
# hive's own domains back to itself (127.0.0.1 in its own netns)
# instead of the bridge IP, and can't reach the forge, matrix, or
# dashboard at all. `no-hosts = true` keeps the authoritative
# `address=` rules in charge for containers while leaving
# `networking.hosts` (the actual /etc/hosts entries) untouched for
# host-side browsing.
no-hosts = true;
# Hive authoritative records — answer queries for the hive domain
# + its sub-domains with the bridge IP, where nginx is reachable
# from every container netns.
#
# Names contributed by the modules that own them
# (`gateway.localNames`) get the same address — the bridge IP is the
# gateway's answer for anything it fronts, and a contributing module
# neither knows nor should know it.
#
# `unique` is not tidiness: two modules claiming one name would
# otherwise emit two `address=` rules for it, and dnsmasq resolves
# that by precedence rather than by complaining. An assertion in
# ./default.nix makes the collision loud instead.
address = map (name: "/${name}/${networkCfg.bridgeIp}") localDomains;
# Every domain above is also `local=`. Since 2.86 an `address=` rule
# answers only the queries of its own address family and sends the rest
# upstream, so an AAAA query for a name answered with an IPv4 address
# waits on the host's upstream resolver, and a host with none that
# answers (no network) leaves the client to its own timeout. `local=`
# with the same domain keeps those queries here: the A answer is
# unchanged and the other types get an empty answer.
local = map (name: "/${name}/") localDomains;
# DHCP pool covering all usable host addresses on the bridge
# subnet — bounds computed by hive-network.nix from
# bridgeIp/bridgePrefixLength. All containers (agents and service
# containers such as swarm-ci-runner) receive their IPs dynamically.
dhcp-range = "${networkCfg.dhcpRangeStart},${networkCfg.dhcpRangeEnd},1h";
dhcp-leasefile = "/var/lib/dnsmasq/dnsmasq.leases";
# No explicit upstream: non-hive queries follow dnsmasq's
# resolv.conf default — the host's own `/etc/resolv.conf`, so the
# hive always uses the host's resolvers and follows them live with
# no copy to go stale. Deliberately no fallback
# `server=`: dnsmasq queries
# all known upstreams in parallel, so a hardcoded public resolver
# would take a share of *normal* traffic, not just fill in when the
# host file is empty.
};
}