From 2713d657fbd8080ae5f37e4ddc7cded0fbc3aa99 Mon Sep 17 00:00:00 2001 From: Felix Albrigtsen Date: Wed, 21 Jan 2026 20:46:14 +0100 Subject: [PATCH] Add duplicate detection when reading hosts.nix --- hosts.nix | 13 +++---------- pvv-subdomains.nix | 42 +++++++++++++++++++++++++++--------------- zones/pvv.ntnu.no.nix | 42 ++++++++++++++++++++++++++---------------- 3 files changed, 56 insertions(+), 41 deletions(-) diff --git a/hosts.nix b/hosts.nix index 27687f0..0cae0b4 100644 --- a/hosts.nix +++ b/hosts.nix @@ -80,21 +80,14 @@ in "homepvvm" "homepvvt" "homepvvz" - "list" # MX/A record handled in ./zones/pvv.ntnu.no.nix - "mail" "samba" # TODO: Remove? "sambapvv" # TODO: Remove? + + "list" # MX/A record handled in ./zones/pvv.ntnu.no.nix + "mail" # Special alias handled in ./zones/pvv.ntnu.no.nix ]; }; - mail.aliases = [ - "drift" - "imap" - "mailhost" - "pop" - "smtp" - ]; - tom = pvvHost 180; knutsen.ipv4 = pvvv4 190; diff --git a/pvv-subdomains.nix b/pvv-subdomains.nix index af598f6..819f943 100644 --- a/pvv-subdomains.nix +++ b/pvv-subdomains.nix @@ -4,6 +4,7 @@ with dns.lib.combinators; let hosts = import ./hosts.nix; + duplicateKeys = lhs: rhs: builtins.attrNames (builtins.intersectAttrs lhs rhs); # Normal host forward records hostRecords = lib.mapAttrs ( @@ -19,20 +20,31 @@ let } ) hosts; - # TODO: - # Above can be replaced using dns.nix helpers, without support for roundrobin, custom TTL, etc; - # (lib.mapAttrs (name: host: dns.lib.host (host.ipv4 or null) (host.ipv6 or null)) hosts) - # CNAMEs - aliasRecords = lib.concatMapAttrs ( - target: host: - builtins.listToAttrs ( - builtins.map (alias: { - name = alias; - value.CNAME = [ target ]; - }) host.aliases or [ ] - ) - ) hosts; + allAliases = lib.flatten (lib.mapAttrsToList (_: host: host.aliases or [ ]) hosts); + duplicateAliases = lib.pipe allAliases [ + (lib.groupBy lib.id) + (lib.filterAttrs (_: list: lib.length list > 1)) + lib.attrNames + ]; + + aliasRecords = + if builtins.length duplicateAliases > 0 then + throw "Duplicate aliases: '${builtins.concatStringsSep ", " duplicateAliases}' exist as aliases for multiple different hosts. If this is intentional, add an exception or configure the aliases directly in the zone config." + else + lib.concatMapAttrs ( + target: host: + builtins.listToAttrs ( + builtins.map (alias: { + name = alias; + value.CNAME = [ target ]; + }) host.aliases or [ ] + ) + ) hosts; + + setCollisions = duplicateKeys hostRecords aliasRecords; in -# TODO: Merge such that an error is raised if a label exists in more than one of these sets: -(hostRecords // aliasRecords) +if builtins.length setCollisions > 0 then + throw "Duplicate keys: '${builtins.concatStringsSep ", " setCollisions}' exist as both a host (A/AAAA) and alias (CNAME)" +else + (hostRecords // aliasRecords) diff --git a/zones/pvv.ntnu.no.nix b/zones/pvv.ntnu.no.nix index 4cb902a..5fec1ee 100644 --- a/zones/pvv.ntnu.no.nix +++ b/zones/pvv.ntnu.no.nix @@ -56,22 +56,7 @@ in "ns2.stack.it.ntnu.no." ]; - "mail._domainkey".TXT = [ - "v=DKIM1; h=sha256; k=rsa; " - "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsLAI4Fj8lGS1gQbumMCftoynu9G5LCOrs8G/EzbXysKuV5EtCCS3ioJVdt3Bbu5RoTZq0lv0KbIClzW7qPa3u0spt9skOQswkSOhzoraPIwPacEUBRMyc2NYSmnIPthKyb6BTAYB1qcKpRswrNzZ6zbsG8DFD8zEJsbpPGjYSxbluLm+FsQXiX21Biha+psCpDTAGcQODri+Fh5UChYi7MnT7UGd8rvNIYlVPAYPeU0xoUcRRZxHfxLNyOU6TrFQ3MhjSKq06p35y3nN2z/6hjbkxQ8aKc30GB+y2SPrTE8TAXKmIMlWbmhaReFHhOS25XGWfzNVhUfNxa21b5UY7wIDAQAB" - ]; - - _dmarc.TXT = [ "v=DMARC1; p=quarantine; fo=1;" ]; - - list = { - A = pvvHostRecords.microbel.A; - MX = [ - { - preference = 10; - exchange = "microbel.pvv.ntnu.no."; - } - ]; - }; + # Special services: minecraft.SRV = [ { @@ -83,5 +68,30 @@ in ]; _kerberos.TXT = [ "PVV.NTNU.NO" ]; + + # E-mail: + + "mail._domainkey".TXT = [ + "v=DKIM1; h=sha256; k=rsa; " + "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsLAI4Fj8lGS1gQbumMCftoynu9G5LCOrs8G/EzbXysKuV5EtCCS3ioJVdt3Bbu5RoTZq0lv0KbIClzW7qPa3u0spt9skOQswkSOhzoraPIwPacEUBRMyc2NYSmnIPthKyb6BTAYB1qcKpRswrNzZ6zbsG8DFD8zEJsbpPGjYSxbluLm+FsQXiX21Biha+psCpDTAGcQODri+Fh5UChYi7MnT7UGd8rvNIYlVPAYPeU0xoUcRRZxHfxLNyOU6TrFQ3MhjSKq06p35y3nN2z/6hjbkxQ8aKc30GB+y2SPrTE8TAXKmIMlWbmhaReFHhOS25XGWfzNVhUfNxa21b5UY7wIDAQAB" + ]; + + _dmarc.TXT = [ "v=DMARC1; p=quarantine; fo=1;" ]; + drift.CNAME = [ "mail" ]; + imap.CNAME = [ "mail" ]; + mailhost.CNAME = [ "mail" ]; + pop.CNAME = [ "mail" ]; + smtp.CNAME = [ "mail" ]; + + list = { + A = pvvHostRecords.microbel.A; + MX = [ + { + preference = 10; + exchange = "microbel.pvv.ntnu.no."; + } + ]; + }; + }; }