lib/dns: refactor localZones

このコミットが含まれているのは:
Astro 2021-05-06 16:24:31 +02:00
コミット 4d41e241b3
3個のファイルの変更232行の追加221行の削除

ファイルの表示

@ -1,6 +1,6 @@
{ self, gpgKey, pkgs }:
{
rec {
config = import ./config { inherit self pkgs gpgKey; };
saltPillarFor = import ./salt-support/salt-pillar.nix {
@ -12,4 +12,6 @@
netmasks = import ./netmasks.nix;
subnet = import ./subnet { inherit pkgs; };
dns = import ./dns.nix { inherit pkgs config; };
}

227
nix/lib/dns.nix ノーマルファイル
ファイルの表示

@ -0,0 +1,227 @@
{ pkgs, config }:
let
lib = pkgs.lib;
in
rec {
ns = "dns.serv.zentralwerk.org";
internalNS = [ ns ];
# public servers (slaves)
publicNS = [ "ns.c3d2.de" "ns.spaceboyz.net" ];
dynamicReverseZones = [
"74.20.172.in-addr.arpa"
"75.20.172.in-addr.arpa"
"76.20.172.in-addr.arpa"
"77.20.172.in-addr.arpa"
"78.20.172.in-addr.arpa"
"79.20.172.in-addr.arpa"
];
localZones =
let
# ip6.arpa aggregation size in CIDR bits
reverseZone6Size = 60;
hosts4Records = hosts4:
builtins.attrValues (
builtins.mapAttrs (name: addr: {
inherit name;
type = "A";
data = addr;
}) hosts4
);
hosts6Records = hosts6:
builtins.attrValues (
builtins.mapAttrs (name: addr: {
inherit name;
type = "AAAA";
data = addr;
}) hosts6
);
# generate zones only for nets with hosts
namedNets = lib.filterAttrs (name: { hosts4, hosts6, dynamicDomain, ... }:
(hosts4 != [] && hosts6 != []) ||
dynamicDomain
) config.site.net;
# converts an IPv4 address to its reverse DNS form
ipv4ToReverse = ipv4:
builtins.concatStringsSep "." (
lib.reverseList (
builtins.filter builtins.isString (
builtins.split "\\." ipv4
)
)
) + ".in-addr.arpa";
# `{ "1,0.0.127.in-addr.arpa" = "lo.core.zentralwerk.dn42"; }`
reverseHosts4 = builtins.foldl' (result: { hosts4, domainName, ... }:
builtins.foldl' (result: host: result // {
"${ipv4ToReverse hosts4.${host}}" = "${host}.${domainName}";
}) result (builtins.attrNames hosts4)
) {} (builtins.attrValues namedNets);
# `[ "0.0.127.in-addr.arpa" ]`
reverseZones4 = builtins.attrNames (
builtins.foldl' (result: rname:
let
zone = builtins.head (
builtins.match "[[:digit:]]+\\.(.+)" rname
);
in result // {
"${zone}" = true;
}
) {} (builtins.attrNames reverseHosts4)
);
# turns `::` into `0000:0000:0000:0000:0000:0000:0000:0000`
expandIpv6 = ipv6:
if lib.hasPrefix "::" ipv6
then expandIpv6 "0${ipv6}"
else if lib.hasSuffix "::" ipv6
then expandIpv6 "${ipv6}0"
else let
words = builtins.filter builtins.isString (
builtins.split ":" ipv6
);
fillWordCount = 8 - builtins.length words;
fillWords = n:
if n >= 0
then [ "0000" ] ++ fillWords (n - 1)
else [];
words' = builtins.concatMap (word:
if word == ""
then fillWords fillWordCount
else [ word ]
) words;
leftPad = padding: target: s:
if builtins.stringLength s < target
then leftPad padding target "${padding}${s}"
else s;
words'' = map (leftPad "0" 4) words';
in
builtins.concatStringsSep ":" words'';
# turns `::1` into `1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa`
ipv6ToReverse = ipv6:
builtins.concatStringsSep "." (
lib.reverseList (
lib.stringToCharacters (
builtins.replaceStrings [":"] [""] (expandIpv6 ipv6)
)
)
) + ".ip6.arpa";
# `{ dn42 = { "...ip6.arpa" = "lo.core.zentralwerk.dn42"; }; }`
reverseHosts6 = builtins.foldl' (result: net: lib.recursiveUpdate result (
builtins.mapAttrs (ctx: hosts:
builtins.foldl' (result: host:
let
domain =
if ctx == "dn42"
then namedNets.${net}.domainName
else if builtins.match "up.*" ctx != null
then "${net}.zentralwerk.org"
else throw "Invalid IPv6 context: ${ctx}";
in
lib.recursiveUpdate result {
"${ipv6ToReverse hosts.${host}}" = "${host}.${domain}";
}
) {} (builtins.attrNames hosts)
) namedNets.${net}.hosts6
)) {} (builtins.attrNames namedNets);
# `{ dn42 = [ "....ip6.arpa" ]; }`
reverseZones6 = builtins.mapAttrs (ctx: reverseHosts6ctx:
builtins.attrNames (
builtins.foldl' (result: rname: result // {
"${builtins.substring ((128 - reverseZone6Size) / 2) (72 - ((128 - reverseZone6Size) / 2)) rname}" = true;
}) {} (builtins.attrNames reverseHosts6ctx)
)
) reverseHosts6;
in [ {
name = "zentralwerk.org";
ns = publicNS;
records = [];
} {
name = "zentralwerk.dn42";
ns = internalNS;
records = [ {
name = "ipa";
type = "A";
data = config.site.net.serv.hosts4.ipa;
} ];
} {
name = "dyn.zentralwerk.org";
ns = publicNS;
records = [ {
name = "upstream1";
type = "A";
data = "24.134.104.53";
} {
name = "upstream2";
type = "A";
data = "24.134.252.105";
} ];
} ] ++ builtins.concatLists (
builtins.attrValues (
builtins.mapAttrs (net: { dynamicDomain, hosts4, hosts6, ... }: [
{
name = "${net}.zentralwerk.dn42";
ns = internalNS;
records =
hosts4Records hosts4 ++
lib.optionals (hosts6 ? dn42) (hosts6Records hosts6.dn42);
dynamic = dynamicDomain;
}
{
name = "${net}.zentralwerk.org";
ns = publicNS;
records =
lib.optionals (hosts6 ? up1) (hosts6Records hosts6.up1) ++
lib.optionals (hosts6 ? up2) (hosts6Records hosts6.up2);
}
]) namedNets
)
) ++ map (zone: {
name = zone;
ns = internalNS;
records =
map (reverse: {
name = builtins.head (
builtins.match "([[:digit:]]+)\\..*" reverse
);
type = "PTR";
data = "${reverseHosts4.${reverse}}.";
}) (
builtins.filter (lib.hasSuffix ".${zone}")
(builtins.attrNames reverseHosts4)
);
dynamic = builtins.elem zone dynamicReverseZones;
}) reverseZones4
++ builtins.concatMap (ctx:
map (zone: {
name = zone;
ns =
if ctx == "dn42"
then internalNS
else if builtins.match "up.*" ctx != null
then publicNS
else throw "Invalid IPv6 context: ${ctx}";
records =
map (reverse: {
name = builtins.substring 0 ((128 - reverseZone6Size) / 2 - 1) reverse;
type = "PTR";
data = "${reverseHosts6.${ctx}.${reverse}}.";
}) (
builtins.filter (lib.hasSuffix ".${zone}")
(builtins.attrNames reverseHosts6.${ctx})
);
}) reverseZones6.${ctx}
) (builtins.attrNames reverseZones6);
}

ファイルの表示

@ -1,18 +1,6 @@
{ hostName, config, lib, pkgs, self, inputs, ... }:
let
fqdn = "${hostName}.serv.zentralwerk.org";
# public servers (slaves)
publicNS = [ "ns.c3d2.de" "ns.spaceboyz.net" ];
dynamicReverseZones = [
"74.20.172.in-addr.arpa"
"75.20.172.in-addr.arpa"
"76.20.172.in-addr.arpa"
"77.20.172.in-addr.arpa"
"78.20.172.in-addr.arpa"
"79.20.172.in-addr.arpa"
];
serial =
let
timestamp = toString self.lastModified;
@ -27,7 +15,7 @@ let
$ORIGIN ${name}.
$TTL 1h
@ IN SOA ${fqdn}. astro.spaceboyz.net. (
@ IN SOA ${lib.dns.ns}. astro.spaceboyz.net. (
${serial} ; serial
1h ; refresh
1m ; retry
@ -86,213 +74,7 @@ in
};
config = {
site.dns.localZones =
let
# ip6.arpa aggregation size in CIDR bits
reverseZone6Size = 60;
hosts4Records = hosts4:
builtins.attrValues (
builtins.mapAttrs (name: addr: {
inherit name;
type = "A";
data = addr;
}) hosts4
);
hosts6Records = hosts6:
builtins.attrValues (
builtins.mapAttrs (name: addr: {
inherit name;
type = "AAAA";
data = addr;
}) hosts6
);
# generate zones only for nets with hosts
namedNets = lib.filterAttrs (name: { hosts4, hosts6, dynamicDomain, ... }:
(hosts4 != [] && hosts6 != []) ||
dynamicDomain
) config.site.net;
# converts an IPv4 address to its reverse DNS form
ipv4ToReverse = ipv4:
builtins.concatStringsSep "." (
lib.reverseList (
builtins.filter builtins.isString (
builtins.split "\\." ipv4
)
)
) + ".in-addr.arpa";
# `{ "1,0.0.127.in-addr.arpa" = "lo.core.zentralwerk.dn42"; }`
reverseHosts4 = builtins.foldl' (result: { hosts4, domainName, ... }:
builtins.foldl' (result: host: result // {
"${ipv4ToReverse hosts4.${host}}" = "${host}.${domainName}";
}) result (builtins.attrNames hosts4)
) {} (builtins.attrValues namedNets);
# `[ "0.0.127.in-addr.arpa" ]`
reverseZones4 = builtins.attrNames (
builtins.foldl' (result: rname:
let
zone = builtins.head (
builtins.match "[[:digit:]]+\\.(.+)" rname
);
in result // {
"${zone}" = true;
}
) {} (builtins.attrNames reverseHosts4)
);
# turns `::` into `0000:0000:0000:0000:0000:0000:0000:0000`
expandIpv6 = ipv6:
if lib.hasPrefix "::" ipv6
then expandIpv6 "0${ipv6}"
else if lib.hasSuffix "::" ipv6
then expandIpv6 "${ipv6}0"
else let
words = builtins.filter builtins.isString (
builtins.split ":" ipv6
);
fillWordCount = 8 - builtins.length words;
fillWords = n:
if n >= 0
then [ "0000" ] ++ fillWords (n - 1)
else [];
words' = builtins.concatMap (word:
if word == ""
then fillWords fillWordCount
else [ word ]
) words;
leftPad = padding: target: s:
if builtins.stringLength s < target
then leftPad padding target "${padding}${s}"
else s;
words'' = map (leftPad "0" 4) words';
in
builtins.concatStringsSep ":" words'';
# turns `::1` into `1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa`
ipv6ToReverse = ipv6:
builtins.concatStringsSep "." (
lib.reverseList (
lib.stringToCharacters (
builtins.replaceStrings [":"] [""] (expandIpv6 ipv6)
)
)
) + ".ip6.arpa";
# `{ dn42 = { "...ip6.arpa" = "lo.core.zentralwerk.dn42"; }; }`
reverseHosts6 = builtins.foldl' (result: net: lib.recursiveUpdate result (
builtins.mapAttrs (ctx: hosts:
builtins.foldl' (result: host:
let
domain =
if ctx == "dn42"
then namedNets.${net}.domainName
else if builtins.match "up.*" ctx != null
then "${net}.zentralwerk.org"
else throw "Invalid IPv6 context: ${ctx}";
in
lib.recursiveUpdate result {
"${ipv6ToReverse hosts.${host}}" = "${host}.${domain}";
}
) {} (builtins.attrNames hosts)
) namedNets.${net}.hosts6
)) {} (builtins.attrNames namedNets);
# `{ dn42 = [ "....ip6.arpa" ]; }`
reverseZones6 = builtins.mapAttrs (ctx: reverseHosts6ctx:
builtins.attrNames (
builtins.foldl' (result: rname: result // {
"${builtins.substring ((128 - reverseZone6Size) / 2) (72 - ((128 - reverseZone6Size) / 2)) rname}" = true;
}) {} (builtins.attrNames reverseHosts6ctx)
)
) reverseHosts6;
in [ {
name = "zentralwerk.org";
ns = publicNS;
records = [];
} {
name = "zentralwerk.dn42";
ns = [ fqdn ];
records = [ {
name = "ipa";
type = "A";
data = config.site.net.serv.hosts4.ipa;
} ];
} {
name = "dyn.zentralwerk.org";
ns = publicNS;
# TODO: implement dyndns
records = [ {
name = "upstream1";
type = "A";
data = "24.134.104.53";
} {
name = "upstream2";
type = "A";
data = "24.134.252.105";
} ];
} ] ++ builtins.concatLists (
builtins.attrValues (
builtins.mapAttrs (net: { dynamicDomain, hosts4, hosts6, ... }: [
{
name = "${net}.zentralwerk.dn42";
ns = [ fqdn ];
records =
hosts4Records hosts4 ++
lib.optionals (hosts6 ? dn42) (hosts6Records hosts6.dn42);
dynamic = dynamicDomain;
}
{
name = "${net}.zentralwerk.org";
ns = publicNS;
records =
lib.optionals (hosts6 ? up1) (hosts6Records hosts6.up1) ++
lib.optionals (hosts6 ? up2) (hosts6Records hosts6.up2);
}
]) namedNets
)
) ++ map (zone: {
name = zone;
ns = [ fqdn ];
records =
map (reverse: {
name = builtins.head (
builtins.match "([[:digit:]]+)\\..*" reverse
);
type = "PTR";
data = "${reverseHosts4.${reverse}}.";
}) (
builtins.filter (lib.hasSuffix ".${zone}")
(builtins.attrNames reverseHosts4)
);
dynamic = builtins.elem zone dynamicReverseZones;
}) reverseZones4
++ builtins.concatMap (ctx:
map (zone: {
name = zone;
ns =
if ctx == "dn42"
then [ fqdn ]
else if builtins.match "up.*" ctx != null
then publicNS
else throw "Invalid IPv6 context: ${ctx}";
records =
map (reverse: {
name = builtins.substring 0 ((128 - reverseZone6Size) / 2 - 1) reverse;
type = "PTR";
data = "${reverseHosts6.${ctx}.${reverse}}.";
}) (
builtins.filter (lib.hasSuffix ".${zone}")
(builtins.attrNames reverseHosts6.${ctx})
);
}) reverseZones6.${ctx}
) (builtins.attrNames reverseZones6);
site.dns.localZones = lib.dns.localZones;
services.bind = lib.mkIf config.site.hosts.${hostName}.services.dns.enable (
let