From 9b2b8250c4564d05881b02bf122f47b40d187459 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sandro=20J=C3=A4ckel?= Date: Sun, 21 Apr 2024 18:17:41 +0200 Subject: [PATCH] dns: switch to knot --- nix/nixos-module/container/dns.nix | 235 ++++++++++++++++++----------- 1 file changed, 145 insertions(+), 90 deletions(-) diff --git a/nix/nixos-module/container/dns.nix b/nix/nixos-module/container/dns.nix index 71684f8..dd2defa 100644 --- a/nix/nixos-module/container/dns.nix +++ b/nix/nixos-module/container/dns.nix @@ -5,7 +5,7 @@ let generateZoneFile = let util = dns-nix.util.${pkgs.system}; - in { name, ns, records, ... }: util.writeZone name (with dns-nix.lib.combinators; { + in { name, ns, records, ... }: util.writeZone name { TTL = 60*60; SOA = { nameServer = "${lib.dns.ns}."; @@ -20,7 +20,7 @@ let subdomains = lib.foldl (a: b: lib.recursiveUpdate a b) { } (map ({ name, type, data }: { ${name}.${type} = [ data ]; }) records); - }); + }; in { options = @@ -69,108 +69,163 @@ in config = { site.dns.localZones = lib.dns.localZones; - services.bind = lib.mkIf config.site.hosts.${hostName}.services.dns.enable ( + services.knot = lib.mkIf config.site.hosts.${hostName}.services.dns.enable ( let generateZone = zone@{ name, dynamic, ... }: { - inherit name; - master = true; - # allowed for zone-transfer - slaves = [ - # ns.c3d2.de - "217.197.84.53" "2001:67c:1400:2240::a" - config.site.net.serv.hosts4.knot - config.site.net.serv.hosts6.dn42.knot - config.site.net.serv.hosts6.up4.knot - # ns.spaceboyz.net - "172.22.24.4" "2a01:4f9:4b:39ec::4" - # ns1.supersandro.de - "188.34.196.104" "2a01:4f8:1c1c:1d38::1" - ]; - file = - if dynamic - then "/var/db/bind/${name}.zone" + domain = name; + template = "zentralwerk"; + acl = [ "zone_xfr" ] ++ lib.optional dynamic "dyndns"; + file = if dynamic + then "/var/lib/knot/zones/${name}.zone" else generateZoneFile zone; - extraConfig = '' - also-notify { - # ns.c3d2.de - 217.197.84.53; - 2001:67c:1400:2240::a; - ${config.site.net.serv.hosts4.knot}; - ${config.site.net.serv.hosts6.dn42.knot}; - ${config.site.net.serv.hosts6.up4.knot}; - # ns.spaceboyz.net - 172.22.24.4; - 95.217.229.209; - 2a01:4f9:4b:39ec::4; - # ns1.supersandro.de - 188.34.196.104; - 2a01:4f8:1c1c:1d38::1; - }; - notify-source ${config.site.net.serv.hosts4.dns}; - notify-source-v6 ${config.site.net.serv.hosts6.up4.dns}; - '' + lib.optionalString dynamic '' - allow-update { key "dyndns"; }; - ''; + notify = [ "all" ]; }; in { enable = true; - zones = map generateZone config.site.dns.localZones; + settings = { + acl = [ + { + id = "dyndns"; + action = "update"; + } + { + id = "zone_xfr"; + address = with config.site.net.serv; [ + # ns.c3d2.de + hosts4.knot hosts6.dn42.knot hosts6.up4.knot + # ns.spaceboyz.net + "172.22.24.4" "2a01:4f9:4b:39ec::4" + # ns1.supersandro.de + "188.34.196.104" "2a01:4f8:1c1c:1d38::1" + ]; + action = "transfer"; + } + ]; - extraConfig = '' - key "dyndns" { - algorithm hmac-sha256; - secret "${config.site.dyndnsKey}"; + key = [ { + id = "dyndns"; + algorithm = "hmac-sha256"; + secret = config.site.dyndnsKey; + } ]; + + log = [ { + target = "syslog"; + any = "info"; + } ]; + + mod-stats = [ { + id = "default"; + query-type = "on"; + } ]; + + remote = let + via = with config.site.net.serv; [ hosts4.dns hosts6.up4.dns ]; + in [ + { + id = "ns.c3d2.de"; + address = with config.site.net.serv; [ hosts4.knot hosts6.dn42.knot hosts6.up4.knot ]; + inherit via; + } { + id = "ns.spaceboyz.net"; + address = [ "172.22.24.4" "2a01:4f9:4b:39ec::4" ]; + inherit via; + } { + id = "ns1.supersandro.de"; + address = [ "188.34.196.104" "2a01:4f8:1c1c:1d38::1" ]; + inherit via; + } + ]; + + remotes = [ { + id = "all"; + remote = [ "ns.c3d2.de" "ns.spaceboyz.net" "ns1.supersandro.de" ]; + } ]; + + server = { + answer-rotation = true; + automatic-acl = true; + identity = "dns.serv.zentralwerk.org"; + tcp-fastopen = true; + version = null; }; - ''; - extraOptions = '' - # allow underscores in dynamic hostnames - ${lib.concatMapStringsSep "\n" (type: '' - check-names ${type} ignore; - '') [ "master" "slave" "response" ]} - ''; + + template = [ + { + # default is a magic name and is always loaded. + # Because we want to use catalog-role/catalog-zone settings for all zones *except* the catalog zone itself, we must split the templates + id = "default"; + global-module = [ "mod-stats" ]; + } + { + id = "zentralwerk"; + catalog-role = "member"; + catalog-zone = "zentralwerk."; + dnssec-signing = true; + journal-content = "all"; # required for zonefile-load=difference-no-serial and makes cold starts like zone reloads + module = "mod-stats/default"; + semantic-checks = true; + serial-policy = "dateserial"; + storage = "/var/lib/knot/zones"; + zonefile-load = "difference-no-serial"; + } + ]; + + zone = [ + { + acl = "zone_xfr"; + catalog-role = "generate"; + domain = "zentralwerk."; + notify = [ "ns1.supersandro.de" ]; + storage = "/var/lib/knot/catalog"; + } + ] ++ map generateZone config.site.dns.localZones; + }; }); - systemd.services.create-dynamic-zones = { - description = "Creates dynamic zone files"; - requiredBy = [ "bind.service" ]; - before = [ "bind.service" ]; - serviceConfig.Type = "oneshot"; - script = '' - mkdir -p /var/db/bind + systemd.services = { + create-dynamic-zones = { + description = "Creates dynamic zone files"; + requiredBy = [ "knot.service" ]; + before = [ "knot.service" ]; + serviceConfig.Type = "oneshot"; + script = '' + mkdir -p /var/lib/knot/zones - ${lib.concatMapStringsSep "\n" (zone@{ name, ... }: '' - [ -e /var/db/bind/${name}.zone ] || \ - cp ${generateZoneFile zone} /var/db/bind/${name}.zone - chown -R named /var/db/bind - chmod -R u+rwX /var/db/bind - '') ( - builtins.filter ({ dynamic, ... }: dynamic) config.site.dns.localZones - )} - ''; - }; - systemd.services.update-dynamic-zones = { - description = "Creates initial records in dynamic zone files"; - requiredBy = [ "bind.service" ]; - after = [ "bind.service" ]; - serviceConfig.Type = "oneshot"; - path = [ pkgs.dnsutils ]; - script = '' - ${lib.concatMapStrings (zone: '' - nsupdate -v -y "hmac-sha256:dyndns:${config.site.dyndnsKey}" <