network/nix/nixos-module/container/dns.nix

172 行
4.7 KiB
Nix

{ hostName, config, lib, pkgs, self, inputs, ... }:
let
serial =
let
timestamp = toString self.lastModified;
datePkg = pkgs.runCommandLocal "date-${timestamp}" {} ''
date -d @${timestamp} +%Y%m%d%H > $out
'';
in
toString (import datePkg);
generateZoneFile = { name, ns, records, dynamic }:
builtins.toFile "${name}.zone" ''
$ORIGIN ${name}.
$TTL 1h
@ IN SOA ${lib.dns.ns}. astro.spaceboyz.net. (
${serial} ; serial
1h ; refresh
1m ; retry
2h ; expire
1m ; minimum
)
${lib.concatMapStrings (ns: " IN NS ${ns}.\n") ns}
${lib.concatMapStrings ({ name, type, data }:
"${name} IN ${type} ${data}\n"
) records}
'';
in
{
options =
with lib;
let
recordOpts = {
name = mkOption {
description = "DNS label";
type = types.str;
};
type = mkOption {
type = types.enum [ "A" "AAAA" "PTR" ];
};
data = mkOption {
type = types.str;
};
};
zoneOpts = {
name = mkOption {
description = "DNS FQDN w/o trailing dot";
type = types.str;
};
ns = mkOption {
type = with types; listOf str;
};
records = mkOption {
type = with types; listOf (submodule {
options = recordOpts;
});
};
dynamic = mkOption {
type = types.bool;
default = false;
};
};
in {
site.dns.localZones = mkOption {
type = with types; listOf (submodule {
options = zoneOpts;
});
};
};
config = {
site.dns.localZones = lib.dns.localZones;
services.bind = 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"
# ns.spaceboyz.net
"172.22.24.4" "2a01:4f9:4b:39ec::4"
];
file =
if dynamic
then "/var/db/bind/${name}.zone"
else generateZoneFile zone;
extraConfig = ''
also-notify {
# ns.c3d2.de
217.197.84.53;
2001:67c:1400:2240::a;
# ns.spaceboyz.net
95.217.229.209;
2a01:4f9:4b:39ec::4;
};
notify-source ${config.site.net.serv.hosts4.dns};
notify-source-v6 ${config.site.net.serv.hosts6.up1.dns};
'' + lib.optionalString dynamic ''
allow-update { key "dyndns"; };
'';
};
in {
enable = true;
zones = map generateZone config.site.dns.localZones;
extraConfig = ''
key "dyndns" {
algorithm hmac-sha256;
secret "${inputs.zentralwerk-network-key.lib.dyndnsKey}";
};
'';
extraOptions = ''
# allow underscores in dynamic hostnames
${lib.concatMapStringsSep "\n" (type: ''
check-names ${type} ignore;
'') [ "master" "slave" "response" ]}
'';
});
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
${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 -y "hmac-sha256:dyndns:${inputs.zentralwerk-network-key.lib.dyndnsKey}" <<EOF
server localhost
${lib.concatMapStringsSep "\n" ({ name, type, data }: ''
delete ${name}.${zone.name}. IN ${type}
add ${name}.${zone.name}. 3600 IN ${type} ${data}
'') zone.records}
send
EOF
'') (
builtins.filter ({ dynamic, ... }: dynamic) config.site.dns.localZones
)}
'';
};
};
}