# Names inside the VPN. Every swarm name, the public ones included, resolves to # the VPN addresses (IPv4 and IPv6) of the machine serving it, through a static # table written on each host. Identical on every host. # # Two readers need the table. Processes on the host read /etc/hosts # (`networking.hosts`). Containers (agents, swarm services) ask the hive's # dnsmasq, which ignores /etc/hosts, so it also reads the table through # `addn-hosts`. # # A host leaves out the names it serves itself: hyperhive already answers # those with the bridge address, and a table entry would override it. { config, lib, ... }: let mesh = import ./mesh.nix; self = config.networking.hostName; swarm = config.services.hyperhive.swarm; # Which machine serves which name. A hive's machine is `hive-` and it # serves the hive's own names: its dashboard and its domain. servedBy = lib.mapAttrs' ( hive: entry: lib.nameValuePair "hive-${hive}" [ swarm.dashboardDomains.${hive} entry.domain ] ) swarm.hives // { swarm-central = [ swarm.domain swarm.bao.domain swarm.bao.ui.domain ]; swarm-services = [ swarm.forge.domain swarm.matrix.gatewayHost swarm.authelia.domain swarm.nats.domain swarm.otel.domain swarm.grafana.domain swarm.victoriametrics.domain swarm.victorialogs.domain ]; swarm-heavyduty = [ swarm.attic.ownDomain ]; }; elsewhere = removeAttrs servedBy [ self ]; # Each machine's names, once per address family: A and AAAA answers. addressesOf = machine: [ mesh.${machine}.address mesh.${machine}.address6 ]; table = lib.concatMap ( machine: map (address: lib.nameValuePair address elsewhere.${machine}) (addressesOf machine) ) (builtins.attrNames elsewhere); in { networking.hosts = lib.listToAttrs table; services.dnsmasq.settings.addn-hosts = "${builtins.toFile "swarm-vpn-hosts" ( lib.concatMapStrings (entry: "${entry.name} ${lib.concatStringsSep " " entry.value}\n") table )}"; }