summaryrefslogtreecommitdiff
path: root/sys/ns/ns.nix
diff options
context:
space:
mode:
Diffstat (limited to 'sys/ns/ns.nix')
-rw-r--r--sys/ns/ns.nix153
1 files changed, 153 insertions, 0 deletions
diff --git a/sys/ns/ns.nix b/sys/ns/ns.nix
new file mode 100644
index 0000000..e5b30e8
--- /dev/null
+++ b/sys/ns/ns.nix
@@ -0,0 +1,153 @@
+{
+ config,
+ lib,
+ ...
+}:
+with lib; let
+ inherit (config.networking) domain;
+ inherit (config.local.nets) gate-public;
+ inherit (config.local.ns.server) tsigName;
+
+ ptrNets = config.local.ns.ptr;
+in {
+ options.local.ns.zones = mkOption {
+ type = with lib.types;
+ attrsOf
+ (submodule
+ ({
+ config,
+ name,
+ ...
+ }: let
+ inherit (config.soa) primary;
+
+ cfg = config.localNS;
+ ptrDomain = cfg.ptrNet.v4 != null || cfg.ptrNet.v6 != null;
+ in {
+ options.localNS = {
+ enable = mkEnableOption "local NS settings";
+
+ acme = mkOption {
+ default = {};
+ type = attrsOf str;
+ };
+
+ ptrNet = {
+ v4 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+
+ v6 = mkOption {
+ type = nullOr str;
+ default = null;
+ };
+ };
+ };
+
+ config =
+ mkIf cfg.enable
+ {
+ ptrName = let
+ name =
+ if cfg.ptrNet.v6 != null
+ then "${cfg.ptrNet.v6}-v6"
+ else "${cfg.ptrNet.v4}-v4";
+ in
+ mkIf ptrDomain name;
+
+ # https://docs.gandi.net/en/domain_names/advanced_users/secondary_nameserver.html
+ nsdConfig = let
+ providerSecondary = [
+ "37.205.15.45 ${tsigName}" # ns3.vpsfree.cz
+ "37.205.11.85 ${tsigName}" # ns4.vpsfree.cz
+ "2a03:3b40:fe:2be::1 ${tsigName}" # ns3.vpsfree.cz
+ "2a03:3b40:101:4::1 ${tsigName}" # ns4.vpsfree.cz
+ ];
+ in {
+ notify = providerSecondary;
+ provideXFR = providerSecondary;
+ };
+
+ ns = [
+ {
+ name = "@";
+ host = primary;
+ }
+ {
+ name = "@";
+ host = "ns3.vpsfree.cz.";
+ }
+ {
+ name = "@";
+ host = "ns4.vpsfree.cz.";
+ }
+ ];
+
+ a =
+ optional (!ptrDomain)
+ {
+ name = primary;
+ ipv4 = gate-public.hosts.gate.v4.address;
+ ptr = null;
+ };
+
+ aaaa =
+ optional (!ptrDomain)
+ {
+ name = primary;
+ ipv6 = gate-public.hosts.gate.v6.address;
+ ptr = null;
+ };
+
+ ptr = let
+ ptrsToRecords = mapAttrsToList (suffix: target: {
+ name = suffix;
+ inherit target;
+ });
+
+ v4Net = cfg.ptrNet.v4;
+ v6Net = cfg.ptrNet.v6;
+
+ v4Records = optionals (v4Net != null) (ptrsToRecords ptrNets.${v4Net}.v4.targets);
+ v6Records = optionals (v6Net != null) (ptrsToRecords ptrNets.${v6Net}.v6.targets);
+ in
+ v4Records ++ v6Records;
+
+ soa = mkIf ptrDomain {
+ authorityZone = mkDefault "${domain}.";
+ };
+
+ cname =
+ mapAttrsToList
+ (name: id: {
+ name = "_acme-challenge" + optionalString (name != "@") ".${name}";
+ target = "${id}.acme-challenge.${domain}.";
+ })
+ cfg.acme;
+ };
+ }));
+ };
+
+ config = {
+ assertions =
+ mapAttrsToList
+ (name: zone: {
+ assertion = zone.localNS.ptrNet.v4 != null -> zone.localNS.ptrNet.v6 == null;
+ message = "zone '${name}' defined as both a v4 and v6 PTR zone";
+ })
+ config.local.ns.zones;
+
+ local.ns.ptr = let
+ zonePtrNets = name: zone:
+ optionalAttrs (zone.localNS.ptrNet.v4 != null)
+ {
+ ${zone.localNS.ptrNet.v4}.v4.zone = name;
+ }
+ // optionalAttrs (zone.localNS.ptrNet.v6 != null) {
+ ${zone.localNS.ptrNet.v6}.v6.zone = name;
+ };
+ in
+ mkMerge (flatten (mapAttrsToList zonePtrNets (filterAttrs (_: zone: zone.localNS.enable) config.local.ns.zones)));
+ };
+}