Browse Source

nixos-module/container/dns: factor zones out into config.site.dns.localZones

master
Astro 1 month ago
parent
commit
b800691dad
1 changed files with 209 additions and 163 deletions
  1. 209
    163
      nix/nixos-module/container/dns.nix

+ 209
- 163
nix/nixos-module/container/dns.nix View File

@@ -1,180 +1,182 @@
1 1
 { hostName, config, lib, pkgs, self, ... }:
2 2
 
3
-lib.mkIf config.site.hosts.${hostName}.services.dns.enable {
4
-  services.bind =
3
+let
4
+  fqdn = "${hostName}.serv.zentralwerk.org";
5
+  # public servers (slaves)
6
+  publicNS = [ "ns.c3d2.de" "ns.spaceboyz.net" ];
7
+in
8
+{
9
+  options =
10
+    with lib;
5 11
     let
6
-      fqdn = "${hostName}.serv.zentralwerk.org";
7
-      # public servers (slaves)
8
-      publicNS = [ "ns.c3d2.de" "ns.spaceboyz.net" ];
9
-      # allowed for zone-transfer
10
-      slaves = [
11
-        # ns.c3d2.de
12
-        "217.197.84.53" "2001:67c:1400:2240::a"
13
-        # ns.spaceboyz.net
14
-        "172.22.24.4" "2a01:4f9:4b:39ec::4"
15
-      ];
16
-      # ip6.arpa aggregation size in CIDR bits
17
-      reverseZone6Size = 60;
18
-
19
-      serial =
20
-        let
21
-          timestamp = toString self.lastModified;
22
-          datePkg = pkgs.runCommandLocal "date-${timestamp}" {} ''
23
-            date -d @${timestamp} +%Y%m%d%H > $out
24
-          '';
25
-        in
26
-          toString (import datePkg);
27
-
28
-      staticZone = { name, ns, records }: {
29
-        inherit name;
30
-        master = true;
31
-        file = builtins.toFile "${name}.zone" ''
32
-          $ORIGIN ${name}.
33
-          $TTL 1h
12
+      recordOpts = {
13
+        name = mkOption {
14
+          description = "DNS label";
15
+          type = types.str;
16
+        };
17
+        type = mkOption {
18
+          type = types.enum [ "A" "AAAA" "PTR" ];
19
+        };
20
+        data = mkOption {
21
+          type = types.str;
22
+        };
23
+      };
34 24
 
35
-          @ IN SOA ${fqdn}. astro.spaceboyz.net. (
36
-              ${serial} ; serial
37
-              1h ; refresh
38
-              1m ; retry
39
-              2h ; expire
40
-              1m ; minimum
41
-            )
42
-          ${lib.concatMapStrings (ns: "  IN NS ${ns}.\n") ns}
25
+      zoneOpts = {
26
+        name = mkOption {
27
+          description = "DNS FQDN w/o trailing dot";
28
+          type = types.str;
29
+        };
30
+        ns = mkOption {
31
+          type = with types; listOf str;
32
+        };
33
+        records = mkOption {
34
+          type = with types; listOf (submodule {
35
+            options = recordOpts;
36
+          });
37
+        };
38
+      };
43 39
 
44
-          ${lib.concatMapStrings ({ name, type, data }:
45
-            "${name} IN ${type} ${data}\n"
46
-          ) records}
47
-        '';
40
+    in {
41
+      site.dns.localZones = mkOption {
42
+        type = with types; listOf (submodule {
43
+          options = zoneOpts;
44
+        });
48 45
       };
46
+    };
49 47
 
50
-      hosts4Records = hosts4:
51
-        builtins.attrValues (
52
-          builtins.mapAttrs (name: addr: {
53
-            inherit name;
54
-            type = "A";
55
-            data = addr;
56
-          }) hosts4
57
-        );
58
-      hosts6Records = hosts6:
59
-        builtins.attrValues (
60
-          builtins.mapAttrs (name: addr: {
61
-            inherit name;
62
-            type = "AAAA";
63
-            data = addr;
64
-          }) hosts6
65
-        );
48
+  config = {
49
+    site.dns.localZones =
50
+      let
51
+        # ip6.arpa aggregation size in CIDR bits
52
+        reverseZone6Size = 60;
66 53
 
67
-      # generate zones only for nets with hosts
68
-      namedNets = lib.filterAttrs (_: { hosts4, hosts6, dynamicDomain, ... }:
69
-        (hosts4 != [] && hosts6 != []) ||
70
-        dynamicDomain
71
-      ) config.site.net;
54
+        hosts4Records = hosts4:
55
+          builtins.attrValues (
56
+            builtins.mapAttrs (name: addr: {
57
+              inherit name;
58
+              type = "A";
59
+              data = addr;
60
+            }) hosts4
61
+          );
62
+        hosts6Records = hosts6:
63
+          builtins.attrValues (
64
+            builtins.mapAttrs (name: addr: {
65
+              inherit name;
66
+              type = "AAAA";
67
+              data = addr;
68
+            }) hosts6
69
+          );
72 70
 
73
-      # converts an IPv4 address to its reverse DNS form
74
-      ipv4ToReverse = ipv4:
75
-        builtins.concatStringsSep "." (
76
-          lib.reverseList (
77
-            builtins.filter builtins.isString (
78
-              builtins.split "\\." ipv4
71
+        # generate zones only for nets with hosts
72
+        namedNets = lib.filterAttrs (_: { hosts4, hosts6, dynamicDomain, ... }:
73
+          (hosts4 != [] && hosts6 != []) ||
74
+          dynamicDomain
75
+        ) config.site.net;
76
+
77
+        # converts an IPv4 address to its reverse DNS form
78
+        ipv4ToReverse = ipv4:
79
+          builtins.concatStringsSep "." (
80
+            lib.reverseList (
81
+              builtins.filter builtins.isString (
82
+                builtins.split "\\." ipv4
83
+              )
79 84
             )
80
-          )
81
-        ) + ".in-addr.arpa";
85
+          ) + ".in-addr.arpa";
82 86
 
83
-      # `{ "1,0.0.127.in-addr.arpa" = "lo.core.zentralwerk.dn42"; }`
84
-      reverseHosts4 = builtins.foldl' (result: { hosts4, domainName, ... }:
85
-        builtins.foldl' (result: host: result // {
86
-          "${ipv4ToReverse hosts4.${host}}" = "${host}.${domainName}";
87
-        }) result (builtins.attrNames hosts4)
88
-      ) {} (builtins.attrValues namedNets);
87
+        # `{ "1,0.0.127.in-addr.arpa" = "lo.core.zentralwerk.dn42"; }`
88
+        reverseHosts4 = builtins.foldl' (result: { hosts4, domainName, ... }:
89
+          builtins.foldl' (result: host: result // {
90
+            "${ipv4ToReverse hosts4.${host}}" = "${host}.${domainName}";
91
+          }) result (builtins.attrNames hosts4)
92
+        ) {} (builtins.attrValues namedNets);
89 93
 
90
-      # `[ "0.0.127.in-addr.arpa" ]`
91
-      reverseZones4 = builtins.attrNames (
92
-        builtins.foldl' (result: rname:
93
-          let
94
-            zone = builtins.head (
95
-              builtins.match "[[:digit:]]+\\.(.+)" rname
96
-            );
97
-          in result // {
98
-            "${zone}" = true;
99
-          }
100
-        ) {} (builtins.attrNames reverseHosts4)
101
-      );
94
+        # `[ "0.0.127.in-addr.arpa" ]`
95
+        reverseZones4 = builtins.attrNames (
96
+          builtins.foldl' (result: rname:
97
+            let
98
+              zone = builtins.head (
99
+                builtins.match "[[:digit:]]+\\.(.+)" rname
100
+              );
101
+            in result // {
102
+              "${zone}" = true;
103
+            }
104
+          ) {} (builtins.attrNames reverseHosts4)
105
+        );
102 106
 
103
-      # turns `::` into `0000:0000:0000:0000:0000:0000:0000:0000`
104
-      expandIpv6 = ipv6:
105
-        if lib.hasPrefix "::" ipv6
106
-        then expandIpv6 "0${ipv6}"
107
+        # turns `::` into `0000:0000:0000:0000:0000:0000:0000:0000`
108
+        expandIpv6 = ipv6:
109
+          if lib.hasPrefix "::" ipv6
110
+          then expandIpv6 "0${ipv6}"
107 111
 
108
-        else if lib.hasSuffix "::" ipv6
109
-        then expandIpv6 "${ipv6}0"
112
+          else if lib.hasSuffix "::" ipv6
113
+          then expandIpv6 "${ipv6}0"
110 114
 
111
-        else let
112
-          words = builtins.filter builtins.isString (
113
-            builtins.split ":" ipv6
114
-          );
115
-          fillWordCount = 8 - builtins.length words;
116
-          fillWords = n:
117
-            if n >= 0
118
-            then [ "0000" ] ++ fillWords (n - 1)
119
-            else [];
120
-          words' = builtins.concatMap (word:
121
-            if word == ""
122
-            then fillWords fillWordCount
123
-            else [ word ]
124
-          ) words;
125
-          leftPad = padding: target: s:
126
-            if builtins.stringLength s < target
127
-            then leftPad padding target "${padding}${s}"
128
-            else s;
129
-          words'' = map (leftPad "0" 4) words';
130
-        in
131
-          builtins.concatStringsSep ":" words'';
115
+          else let
116
+            words = builtins.filter builtins.isString (
117
+              builtins.split ":" ipv6
118
+            );
119
+            fillWordCount = 8 - builtins.length words;
120
+            fillWords = n:
121
+              if n >= 0
122
+              then [ "0000" ] ++ fillWords (n - 1)
123
+              else [];
124
+            words' = builtins.concatMap (word:
125
+              if word == ""
126
+              then fillWords fillWordCount
127
+              else [ word ]
128
+            ) words;
129
+            leftPad = padding: target: s:
130
+              if builtins.stringLength s < target
131
+              then leftPad padding target "${padding}${s}"
132
+              else s;
133
+            words'' = map (leftPad "0" 4) words';
134
+          in
135
+            builtins.concatStringsSep ":" words'';
132 136
 
133
-      # 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`
134
-      ipv6ToReverse = ipv6:
135
-        builtins.concatStringsSep "." (
136
-          lib.reverseList (
137
-            lib.stringToCharacters (
138
-              builtins.replaceStrings [":"] [""] (expandIpv6 ipv6)
137
+        # 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`
138
+        ipv6ToReverse = ipv6:
139
+          builtins.concatStringsSep "." (
140
+            lib.reverseList (
141
+              lib.stringToCharacters (
142
+                builtins.replaceStrings [":"] [""] (expandIpv6 ipv6)
143
+              )
139 144
             )
140
-          )
141
-        ) + ".ip6.arpa";
145
+          ) + ".ip6.arpa";
142 146
 
143
-      # `{ dn42 = { "...ip6.arpa" = "lo.core.zentralwerk.dn42"; }; }`
144
-      reverseHosts6 = builtins.foldl' (result: net: lib.recursiveUpdate result (
145
-        builtins.mapAttrs (ctx: hosts:
146
-          builtins.foldl' (result: host:
147
-            let
148
-              domain =
149
-                if ctx == "dn42"
150
-                then namedNets.${net}.domainName
151
-                else if builtins.match "up.*" ctx != null
152
-                then "${net}.zentralwerk.org"
153
-                else throw "Invalid IPv6 context: ${ctx}";
154
-            in
155
-              lib.recursiveUpdate result {
156
-                "${ipv6ToReverse hosts.${host}}" = "${host}.${domain}";
157
-              }
158
-          ) {} (builtins.attrNames hosts)
159
-        ) namedNets.${net}.hosts6
160
-      )) {} (builtins.attrNames namedNets);
147
+        # `{ dn42 = { "...ip6.arpa" = "lo.core.zentralwerk.dn42"; }; }`
148
+        reverseHosts6 = builtins.foldl' (result: net: lib.recursiveUpdate result (
149
+          builtins.mapAttrs (ctx: hosts:
150
+            builtins.foldl' (result: host:
151
+              let
152
+                domain =
153
+                  if ctx == "dn42"
154
+                  then namedNets.${net}.domainName
155
+                  else if builtins.match "up.*" ctx != null
156
+                  then "${net}.zentralwerk.org"
157
+                  else throw "Invalid IPv6 context: ${ctx}";
158
+              in
159
+                lib.recursiveUpdate result {
160
+                  "${ipv6ToReverse hosts.${host}}" = "${host}.${domain}";
161
+                }
162
+            ) {} (builtins.attrNames hosts)
163
+          ) namedNets.${net}.hosts6
164
+        )) {} (builtins.attrNames namedNets);
161 165
 
162
-      # `{ dn42 = [ "....ip6.arpa" ]; }`
163
-      reverseZones6 = builtins.mapAttrs (ctx: reverseHosts6ctx:
164
-        builtins.attrNames (
165
-          builtins.foldl' (result: rname: result // {
166
-            "${builtins.substring ((128 - reverseZone6Size) / 2) (72 - ((128 - reverseZone6Size) / 2)) rname}" = true;
167
-          }) {} (builtins.attrNames reverseHosts6ctx)
168
-        )
169
-      ) reverseHosts6;
166
+        # `{ dn42 = [ "....ip6.arpa" ]; }`
167
+        reverseZones6 = builtins.mapAttrs (ctx: reverseHosts6ctx:
168
+          builtins.attrNames (
169
+            builtins.foldl' (result: rname: result // {
170
+              "${builtins.substring ((128 - reverseZone6Size) / 2) (72 - ((128 - reverseZone6Size) / 2)) rname}" = true;
171
+            }) {} (builtins.attrNames reverseHosts6ctx)
172
+          )
173
+        ) reverseHosts6;
170 174
 
171
-    in {
172
-      enable = true;
173
-      zones = [ (staticZone {
175
+      in [ {
174 176
         name = "zentralwerk.org";
175 177
         ns = publicNS;
176 178
         records = [];
177
-      }) (staticZone {
179
+      } {
178 180
         name = "zentralwerk.dn42";
179 181
         ns = [ fqdn ];
180 182
         records = [ {
@@ -182,7 +184,7 @@ lib.mkIf config.site.hosts.${hostName}.services.dns.enable {
182 184
           type = "A";
183 185
           data = config.site.net.serv.hosts4.ipa;
184 186
         } ];
185
-      }) (staticZone {
187
+      } {
186 188
         name = "dyn.zentralwerk.org";
187 189
         ns = publicNS;
188 190
         # TODO: implement dyndns
@@ -195,28 +197,28 @@ lib.mkIf config.site.hosts.${hostName}.services.dns.enable {
195 197
           type = "A";
196 198
           data = "24.134.252.105";
197 199
         } ];
198
-      }) ] ++ builtins.concatLists (
200
+      } ] ++ builtins.concatLists (
199 201
         builtins.attrValues (
200 202
           builtins.mapAttrs (net: { dynamicDomain, hosts4, hosts6, ... }: [
201 203
             (if dynamicDomain
202 204
              then throw "TODO"
203
-             else staticZone {
205
+             else {
204 206
                name = "${net}.zentralwerk.dn42";
205 207
                ns = [ fqdn ];
206 208
                records =
207 209
                  hosts4Records hosts4 ++
208 210
                  lib.optionals (hosts6 ? dn42) (hosts6Records hosts6.dn42);
209 211
              })
210
-            (staticZone {
212
+            {
211 213
               name = "${net}.zentralwerk.org";
212 214
               ns = publicNS;
213 215
               records =
214 216
                 lib.optionals (hosts6 ? up1) (hosts6Records hosts6.up1) ++
215 217
                 lib.optionals (hosts6 ? up2) (hosts6Records hosts6.up2);
216
-            })
218
+            }
217 219
           ]) namedNets
218 220
         )
219
-      ) ++ map (zone: staticZone {
221
+      ) ++ map (zone: {
220 222
         name = zone;
221 223
         ns = [ fqdn ];
222 224
         records =
@@ -232,7 +234,7 @@ lib.mkIf config.site.hosts.${hostName}.services.dns.enable {
232 234
           );
233 235
       }) reverseZones4
234 236
       ++ builtins.concatMap (ctx:
235
-        map (zone: staticZone {
237
+        map (zone: {
236 238
           name = zone;
237 239
           ns =
238 240
             if ctx == "dn42"
@@ -251,7 +253,51 @@ lib.mkIf config.site.hosts.${hostName}.services.dns.enable {
251 253
             );
252 254
         }) reverseZones6.${ctx}
253 255
       ) (builtins.attrNames reverseZones6);
254
-    };
255 256
 
256
-  # TODO: dyn
257
+    services.bind = lib.mkIf config.site.hosts.${hostName}.services.dns.enable (
258
+      let
259
+        serial =
260
+          let
261
+            timestamp = toString self.lastModified;
262
+            datePkg = pkgs.runCommandLocal "date-${timestamp}" {} ''
263
+            date -d @${timestamp} +%Y%m%d%H > $out
264
+          '';
265
+          in
266
+            toString (import datePkg);
267
+
268
+        generateZone = { name, ns, records }: {
269
+          inherit name;
270
+          master = true;
271
+          # allowed for zone-transfer
272
+          slaves = [
273
+            # ns.c3d2.de
274
+            "217.197.84.53" "2001:67c:1400:2240::a"
275
+            # ns.spaceboyz.net
276
+            "172.22.24.4" "2a01:4f9:4b:39ec::4"
277
+          ];
278
+          file = builtins.toFile "${name}.zone" ''
279
+            $ORIGIN ${name}.
280
+            $TTL 1h
281
+
282
+            @ IN SOA ${fqdn}. astro.spaceboyz.net. (
283
+                ${serial} ; serial
284
+                1h ; refresh
285
+                1m ; retry
286
+                2h ; expire
287
+                1m ; minimum
288
+            )
289
+            ${lib.concatMapStrings (ns: "  IN NS ${ns}.\n") ns}
290
+
291
+            ${lib.concatMapStrings ({ name, type, data }:
292
+              "${name} IN ${type} ${data}\n"
293
+            ) records}
294
+          '';
295
+        };
296
+      in {
297
+        enable = true;
298
+        zones = map generateZone config.site.dns.localZones;
299
+      });
300
+
301
+    # TODO: dyn
302
+  };
257 303
 }

Loading…
Cancel
Save