2023-10-04 09:31:17 -07:00
|
|
|
{ config, lib, pkgs, ... }:
|
|
|
|
|
|
|
|
with lib;
|
|
|
|
let
|
|
|
|
cfg = config.services.authoritative-dns;
|
|
|
|
|
|
|
|
zoneOpts = import ./zone-definition.nix { inherit lib; };
|
|
|
|
|
2023-10-05 11:49:21 -07:00
|
|
|
zoneToZonefile = import ./zone-to-zonefile.nix { inherit lib; };
|
|
|
|
|
2023-11-01 10:13:33 -07:00
|
|
|
reverseZonefile = import ./reverse-zone.nix { inherit pkgs; };
|
|
|
|
|
2023-10-04 09:31:17 -07:00
|
|
|
domainOpts = { name, ... }: {
|
|
|
|
options = with types; {
|
|
|
|
domain = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = "Domain name.";
|
|
|
|
default = name;
|
|
|
|
};
|
|
|
|
|
|
|
|
ksk = {
|
|
|
|
key-file = mkOption {
|
|
|
|
type = nullOr str;
|
|
|
|
description =
|
|
|
|
"Key-signing key for this zone. DNSSEC disabled when null.";
|
|
|
|
default = null;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
zone = mkOption {
|
|
|
|
type = submodule zoneOpts;
|
|
|
|
description = "Definition of network zone to be served.";
|
|
|
|
};
|
2023-11-01 10:13:33 -07:00
|
|
|
|
|
|
|
reverse-zones = mkOption {
|
|
|
|
type = listOf str;
|
|
|
|
description =
|
|
|
|
"List of subnets for which to generate reverse lookup zones.";
|
|
|
|
default = [ ];
|
|
|
|
};
|
2023-10-04 09:31:17 -07:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
in {
|
|
|
|
options.services.authoritative-dns = with types; {
|
|
|
|
enable = mkEnableOption "Enable authoritative DNS service.";
|
|
|
|
|
2023-10-05 10:53:17 -07:00
|
|
|
identity = mkOption {
|
2023-10-04 09:31:17 -07:00
|
|
|
type = str;
|
|
|
|
description = "The identity (CH TXT ID.SERVER) of this host.";
|
|
|
|
};
|
|
|
|
|
|
|
|
domains = mkOption {
|
|
|
|
type = attrsOf (submodule domainOpts);
|
|
|
|
default = { };
|
|
|
|
description = "A map of domain to domain options.";
|
|
|
|
};
|
|
|
|
|
|
|
|
listen-ips = mkOption {
|
|
|
|
type = listOf str;
|
|
|
|
description =
|
|
|
|
"List of IP addresses on which to listen. If empty, listen on all addresses.";
|
|
|
|
default = [ ];
|
|
|
|
};
|
|
|
|
|
|
|
|
state-directory = mkOption {
|
|
|
|
type = str;
|
|
|
|
description =
|
|
|
|
"Path on which to store nameserver state, including DNSSEC keys.";
|
|
|
|
};
|
|
|
|
|
|
|
|
timestamp = mkOption {
|
|
|
|
type = str;
|
|
|
|
description = "Timestamp to attach to zone record.";
|
|
|
|
};
|
2023-11-03 11:07:26 -07:00
|
|
|
|
|
|
|
ip-host-map = mkOption {
|
|
|
|
type = attrsOf str;
|
|
|
|
description =
|
|
|
|
"Map of IP address to authoritative hostname. Unneeded hosts will be ignored.";
|
|
|
|
default = { };
|
|
|
|
};
|
2023-10-04 09:31:17 -07:00
|
|
|
};
|
|
|
|
|
2023-10-05 12:16:17 -07:00
|
|
|
imports = [ ./nsd.nix ];
|
2023-10-04 09:31:17 -07:00
|
|
|
|
|
|
|
config = mkIf cfg.enable {
|
2023-10-05 13:20:54 -07:00
|
|
|
services.fudo-nsd = {
|
|
|
|
enable = true;
|
|
|
|
identity = cfg.identity;
|
|
|
|
interfaces = cfg.listen-ips;
|
|
|
|
stateDirectory = cfg.state-directory;
|
2023-11-01 10:13:33 -07:00
|
|
|
zones = let
|
|
|
|
forwardZones = mapAttrs' (domain: domainCfg:
|
|
|
|
nameValuePair "${domain}." {
|
|
|
|
dnssec = domainCfg.ksk.key-file != null;
|
|
|
|
ksk.keyFile =
|
|
|
|
mkIf (domainCfg.ksk.key-file != null) domainCfg.ksk.key-file;
|
|
|
|
data = zoneToZonefile {
|
|
|
|
inherit domain;
|
|
|
|
inherit (cfg) timestamp;
|
|
|
|
inherit (domainCfg) zone;
|
|
|
|
};
|
|
|
|
}) cfg.domains;
|
|
|
|
reverseZones = concatMapAttrs (domain: domainOpts:
|
2023-11-03 10:59:11 -07:00
|
|
|
listToAttrs (map (network:
|
2023-11-01 10:13:33 -07:00
|
|
|
reverseZonefile {
|
|
|
|
inherit domain network;
|
|
|
|
inherit (domainOpts.zone) nameservers;
|
|
|
|
ipHostMap = cfg.ip-host-map;
|
|
|
|
serial = cfg.timestamp;
|
2023-11-03 10:59:11 -07:00
|
|
|
}) domainOpts.reverse-zones)) cfg.domains;
|
2023-11-01 10:13:33 -07:00
|
|
|
in forwardZones // reverseZones;
|
2023-10-05 13:20:54 -07:00
|
|
|
};
|
2023-10-04 09:31:17 -07:00
|
|
|
};
|
|
|
|
}
|