{ inputs, povSelf, hostConfig, config, lib, pkgs, ... }: let inherit (lib) types; cfg = lib.getAttrFromPath povSelf config; dnsServerAddresses = isPrimary: lib.flatten ( inputs.self.nixosConfigurations |> lib.filterAttrs ( hostName: hostConfig: let cfgModule = lib.getAttrFromPath povSelf hostConfig.config; in (cfgModule.enable && cfgModule.primary == isPrimary) ) |> lib.mapAttrsToList ( hostName: hostConfig: [ (lib.mkIf (inputs.self.hosts."${hostName}".networking.ip6Address != "") inputs.self.hosts."${hostName}".networking.ip6Address ) (lib.mkIf (inputs.self.hosts."${hostName}".networking.ip4Address != "") inputs.self.hosts."${hostName}".networking.ip4Address ) ] ) ); dnsServerSecondaries = ( inputs.self.nixosConfigurations |> lib.filterAttrs ( hostName: hostConfig: let cfgModule = lib.getAttrFromPath povSelf hostConfig.config; in (cfgModule.enable && !cfgModule.primary) ) |> lib.mapAttrs ( hostName: hostConfig: { address = [ (lib.mkIf (inputs.self.hosts."${hostName}".networking.ip6Address != "") inputs.self.hosts."${hostName}".networking.ip6Address ) (lib.mkIf (inputs.self.hosts."${hostName}".networking.ip4Address != "") inputs.self.hosts."${hostName}".networking.ip4Address ) ]; } ) ); in { options = { enable = { type = types.bool; default = false; }; primary = { type = types.bool; default = false; }; dataDir = { type = types.str; default = "/var/lib/knot"; }; keyFiles = { type = types.listOf types.path; default = [ ]; }; zones = { type = (pkgs.formats.yaml { }).type; default = { }; }; extraACL = { type = (pkgs.formats.yaml { }).type; default = { }; }; }; config = lib.mkIf cfg.enable { networking.firewall.allowedTCPPorts = [ 53 ]; networking.firewall.allowedUDPPorts = [ 53 ]; modules.filesystem.impermanence.system.dirs = [ { directory = cfg.dataDir; mode = "0770"; user = "knot"; group = "knot"; } ]; systemd.tmpfiles.settings = { knotDataDir."${cfg.dataDir}".d = { group = "knot"; user = "knot"; mode = "770"; age = "-"; }; }; services.knot = let primaryAddresses = dnsServerAddresses true; secondaryAddresses = dnsServerAddresses false; secondaries = dnsServerSecondaries; in { enable = true; keyFiles = lib.mkIf (cfg.keyFiles != [ ]) cfg.keyFiles; settings = { log.syslog.any = "info"; server.listen = [ (lib.mkIf (hostConfig.networking.ip6Address != "") "${hostConfig.networking.ip6Address}@53") (lib.mkIf (hostConfig.networking.ip4Address != "") "${hostConfig.networking.ip4Address}@53") "::1@53" "127.0.0.2@53" ]; mod-rrl.default.rate-limit = 200; mod-rrl.default.slip = 2; remote = { primary.address = primaryAddresses; } // secondaries; acl = { allowTransfer = lib.mkIf (secondaryAddresses != [ ]) { address = secondaryAddresses; action = "transfer"; }; allowNotify.address = primaryAddresses; allowNotify.action = "notify"; } // cfg.extraACL; template = let notify = { acl = lib.mkIf (config.services.knot.settings.acl ? allowTransfer) "allowTransfer"; notify = lib.mkIf (config.services.knot.settings.acl ? allowTransfer) ( builtins.attrNames secondaries ); }; catalog = { catalog-role = "member"; catalog-zone = "catalog."; }; in { default = { semantic-checks = true; global-module = "mod-rrl/default"; }; notifyZone = notify; nixZone = notify // catalog; secondaryZone = { master = "primary"; acl = "allowNotify"; journal-content = "all"; zonefile-sync = -1; zonefile-load = "none"; }; }; zone = ( if !cfg.primary then { "catalog.".catalog-role = "interpret"; "catalog.".catalog-template = "secondaryZone"; "catalog.".template = "secondaryZone"; } else { "catalog.".catalog-role = "generate"; "catalog.".template = "notifyZone"; } ) // (lib.mapAttrs ( name: zone: zone // { template = "nixZone"; acl = lib.mkIf (zone ? acl) ( if (config.services.knot.settings.acl ? allowTransfer) then lib.flatten [ [ "allowTransfer" ] zone.acl ] else zone.acl ); } ) cfg.zones); }; }; }; }