Browse Source

lib/dns: refactor localZones

master
Astro 1 month ago
parent
commit
4d41e241b3
3 changed files with 232 additions and 221 deletions
  1. 3
    1
      nix/lib/default.nix
  2. 227
    0
      nix/lib/dns.nix
  3. 2
    220
      nix/nixos-module/container/dns.nix

+ 3
- 1
nix/lib/default.nix View File

@@ -1,6 +1,6 @@
1 1
 { self, gpgKey, pkgs }:
2 2
 
3
-{
3
+rec {
4 4
   config = import ./config { inherit self pkgs gpgKey; };
5 5
 
6 6
   saltPillarFor = import ./salt-support/salt-pillar.nix {
@@ -12,4 +12,6 @@
12 12
   netmasks = import ./netmasks.nix;
13 13
 
14 14
   subnet = import ./subnet { inherit pkgs; };
15
+
16
+  dns = import ./dns.nix { inherit pkgs config; };
15 17
 }

+ 227
- 0
nix/lib/dns.nix View File

@@ -0,0 +1,227 @@
1
+{ pkgs, config }:
2
+
3
+let
4
+  lib = pkgs.lib;
5
+in
6
+rec {
7
+  ns = "dns.serv.zentralwerk.org";
8
+  internalNS = [ ns ];
9
+  # public servers (slaves)
10
+  publicNS = [ "ns.c3d2.de" "ns.spaceboyz.net" ];
11
+  
12
+  dynamicReverseZones = [
13
+    "74.20.172.in-addr.arpa"
14
+    "75.20.172.in-addr.arpa"
15
+    "76.20.172.in-addr.arpa"
16
+    "77.20.172.in-addr.arpa"
17
+    "78.20.172.in-addr.arpa"
18
+    "79.20.172.in-addr.arpa"
19
+  ];
20
+
21
+  localZones =
22
+    let
23
+      # ip6.arpa aggregation size in CIDR bits
24
+      reverseZone6Size = 60;
25
+
26
+      hosts4Records = hosts4:
27
+        builtins.attrValues (
28
+          builtins.mapAttrs (name: addr: {
29
+            inherit name;
30
+            type = "A";
31
+            data = addr;
32
+          }) hosts4
33
+        );
34
+      hosts6Records = hosts6:
35
+        builtins.attrValues (
36
+          builtins.mapAttrs (name: addr: {
37
+            inherit name;
38
+            type = "AAAA";
39
+            data = addr;
40
+          }) hosts6
41
+        );
42
+
43
+      # generate zones only for nets with hosts
44
+      namedNets = lib.filterAttrs (name: { hosts4, hosts6, dynamicDomain, ... }:
45
+        (hosts4 != [] && hosts6 != []) ||
46
+        dynamicDomain
47
+      ) config.site.net;
48
+
49
+      # converts an IPv4 address to its reverse DNS form
50
+      ipv4ToReverse = ipv4:
51
+        builtins.concatStringsSep "." (
52
+          lib.reverseList (
53
+            builtins.filter builtins.isString (
54
+              builtins.split "\\." ipv4
55
+            )
56
+          )
57
+        ) + ".in-addr.arpa";
58
+
59
+      # `{ "1,0.0.127.in-addr.arpa" = "lo.core.zentralwerk.dn42"; }`
60
+      reverseHosts4 = builtins.foldl' (result: { hosts4, domainName, ... }:
61
+        builtins.foldl' (result: host: result // {
62
+          "${ipv4ToReverse hosts4.${host}}" = "${host}.${domainName}";
63
+        }) result (builtins.attrNames hosts4)
64
+      ) {} (builtins.attrValues namedNets);
65
+
66
+      # `[ "0.0.127.in-addr.arpa" ]`
67
+      reverseZones4 = builtins.attrNames (
68
+        builtins.foldl' (result: rname:
69
+          let
70
+            zone = builtins.head (
71
+              builtins.match "[[:digit:]]+\\.(.+)" rname
72
+            );
73
+          in result // {
74
+            "${zone}" = true;
75
+          }
76
+        ) {} (builtins.attrNames reverseHosts4)
77
+      );
78
+
79
+      # turns `::` into `0000:0000:0000:0000:0000:0000:0000:0000`
80
+      expandIpv6 = ipv6:
81
+        if lib.hasPrefix "::" ipv6
82
+        then expandIpv6 "0${ipv6}"
83
+
84
+        else if lib.hasSuffix "::" ipv6
85
+        then expandIpv6 "${ipv6}0"
86
+
87
+        else let
88
+          words = builtins.filter builtins.isString (
89
+            builtins.split ":" ipv6
90
+          );
91
+          fillWordCount = 8 - builtins.length words;
92
+          fillWords = n:
93
+            if n >= 0
94
+            then [ "0000" ] ++ fillWords (n - 1)
95
+            else [];
96
+          words' = builtins.concatMap (word:
97
+            if word == ""
98
+            then fillWords fillWordCount
99
+            else [ word ]
100
+          ) words;
101
+          leftPad = padding: target: s:
102
+            if builtins.stringLength s < target
103
+            then leftPad padding target "${padding}${s}"
104
+            else s;
105
+          words'' = map (leftPad "0" 4) words';
106
+        in
107
+          builtins.concatStringsSep ":" words'';
108
+
109
+      # 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`
110
+      ipv6ToReverse = ipv6:
111
+        builtins.concatStringsSep "." (
112
+          lib.reverseList (
113
+            lib.stringToCharacters (
114
+              builtins.replaceStrings [":"] [""] (expandIpv6 ipv6)
115
+            )
116
+          )
117
+        ) + ".ip6.arpa";
118
+
119
+      # `{ dn42 = { "...ip6.arpa" = "lo.core.zentralwerk.dn42"; }; }`
120
+      reverseHosts6 = builtins.foldl' (result: net: lib.recursiveUpdate result (
121
+        builtins.mapAttrs (ctx: hosts:
122
+          builtins.foldl' (result: host:
123
+            let
124
+              domain =
125
+                if ctx == "dn42"
126
+                then namedNets.${net}.domainName
127
+                else if builtins.match "up.*" ctx != null
128
+                then "${net}.zentralwerk.org"
129
+                else throw "Invalid IPv6 context: ${ctx}";
130
+            in
131
+              lib.recursiveUpdate result {
132
+                "${ipv6ToReverse hosts.${host}}" = "${host}.${domain}";
133
+              }
134
+          ) {} (builtins.attrNames hosts)
135
+        ) namedNets.${net}.hosts6
136
+      )) {} (builtins.attrNames namedNets);
137
+
138
+      # `{ dn42 = [ "....ip6.arpa" ]; }`
139
+      reverseZones6 = builtins.mapAttrs (ctx: reverseHosts6ctx:
140
+        builtins.attrNames (
141
+          builtins.foldl' (result: rname: result // {
142
+            "${builtins.substring ((128 - reverseZone6Size) / 2) (72 - ((128 - reverseZone6Size) / 2)) rname}" = true;
143
+          }) {} (builtins.attrNames reverseHosts6ctx)
144
+        )
145
+      ) reverseHosts6;
146
+
147
+    in [ {
148
+      name = "zentralwerk.org";
149
+      ns = publicNS;
150
+      records = [];
151
+    } {
152
+      name = "zentralwerk.dn42";
153
+      ns = internalNS;
154
+      records = [ {
155
+        name = "ipa";
156
+        type = "A";
157
+        data = config.site.net.serv.hosts4.ipa;
158
+      } ];
159
+    } {
160
+      name = "dyn.zentralwerk.org";
161
+      ns = publicNS;
162
+      records = [ {
163
+        name = "upstream1";
164
+        type = "A";
165
+        data = "24.134.104.53";
166
+      } {
167
+        name = "upstream2";
168
+        type = "A";
169
+        data = "24.134.252.105";
170
+      } ];
171
+    } ] ++ builtins.concatLists (
172
+      builtins.attrValues (
173
+        builtins.mapAttrs (net: { dynamicDomain, hosts4, hosts6, ... }: [
174
+          {
175
+            name = "${net}.zentralwerk.dn42";
176
+            ns = internalNS;
177
+            records =
178
+              hosts4Records hosts4 ++
179
+              lib.optionals (hosts6 ? dn42) (hosts6Records hosts6.dn42);
180
+            dynamic = dynamicDomain;
181
+          }
182
+          {
183
+            name = "${net}.zentralwerk.org";
184
+            ns = publicNS;
185
+            records =
186
+              lib.optionals (hosts6 ? up1) (hosts6Records hosts6.up1) ++
187
+              lib.optionals (hosts6 ? up2) (hosts6Records hosts6.up2);
188
+          }
189
+        ]) namedNets
190
+      )
191
+    ) ++ map (zone: {
192
+      name = zone;
193
+      ns = internalNS;
194
+      records =
195
+        map (reverse: {
196
+          name = builtins.head (
197
+            builtins.match "([[:digit:]]+)\\..*" reverse
198
+          );
199
+          type = "PTR";
200
+          data = "${reverseHosts4.${reverse}}.";
201
+        }) (
202
+          builtins.filter (lib.hasSuffix ".${zone}")
203
+            (builtins.attrNames reverseHosts4)
204
+        );
205
+      dynamic = builtins.elem zone dynamicReverseZones;
206
+    }) reverseZones4
207
+    ++ builtins.concatMap (ctx:
208
+      map (zone: {
209
+        name = zone;
210
+        ns =
211
+          if ctx == "dn42"
212
+          then internalNS
213
+          else if builtins.match "up.*" ctx != null
214
+          then publicNS
215
+          else throw "Invalid IPv6 context: ${ctx}";
216
+        records =
217
+          map (reverse: {
218
+            name = builtins.substring 0 ((128 - reverseZone6Size) / 2 - 1) reverse;
219
+            type = "PTR";
220
+            data = "${reverseHosts6.${ctx}.${reverse}}.";
221
+          }) (
222
+            builtins.filter (lib.hasSuffix ".${zone}")
223
+              (builtins.attrNames reverseHosts6.${ctx})
224
+          );
225
+      }) reverseZones6.${ctx}
226
+    ) (builtins.attrNames reverseZones6);
227
+}

+ 2
- 220
nix/nixos-module/container/dns.nix View File

@@ -1,18 +1,6 @@
1 1
 { hostName, config, lib, pkgs, self, inputs, ... }:
2 2
 
3 3
 let
4
-  fqdn = "${hostName}.serv.zentralwerk.org";
5
-  # public servers (slaves)
6
-  publicNS = [ "ns.c3d2.de" "ns.spaceboyz.net" ];
7
-  dynamicReverseZones = [
8
-    "74.20.172.in-addr.arpa"
9
-    "75.20.172.in-addr.arpa"
10
-    "76.20.172.in-addr.arpa"
11
-    "77.20.172.in-addr.arpa"
12
-    "78.20.172.in-addr.arpa"
13
-    "79.20.172.in-addr.arpa"
14
-  ];
15
-
16 4
   serial =
17 5
     let
18 6
       timestamp = toString self.lastModified;
@@ -27,7 +15,7 @@ let
27 15
       $ORIGIN ${name}.
28 16
       $TTL 1h
29 17
 
30
-      @ IN SOA ${fqdn}. astro.spaceboyz.net. (
18
+      @ IN SOA ${lib.dns.ns}. astro.spaceboyz.net. (
31 19
           ${serial} ; serial
32 20
           1h ; refresh
33 21
           1m ; retry
@@ -86,213 +74,7 @@ in
86 74
     };
87 75
 
88 76
   config = {
89
-    site.dns.localZones =
90
-      let
91
-        # ip6.arpa aggregation size in CIDR bits
92
-        reverseZone6Size = 60;
93
-
94
-        hosts4Records = hosts4:
95
-          builtins.attrValues (
96
-            builtins.mapAttrs (name: addr: {
97
-              inherit name;
98
-              type = "A";
99
-              data = addr;
100
-            }) hosts4
101
-          );
102
-        hosts6Records = hosts6:
103
-          builtins.attrValues (
104
-            builtins.mapAttrs (name: addr: {
105
-              inherit name;
106
-              type = "AAAA";
107
-              data = addr;
108
-            }) hosts6
109
-          );
110
-
111
-        # generate zones only for nets with hosts
112
-        namedNets = lib.filterAttrs (name: { hosts4, hosts6, dynamicDomain, ... }:
113
-          (hosts4 != [] && hosts6 != []) ||
114
-           dynamicDomain
115
-        ) config.site.net;
116
-
117
-        # converts an IPv4 address to its reverse DNS form
118
-        ipv4ToReverse = ipv4:
119
-          builtins.concatStringsSep "." (
120
-            lib.reverseList (
121
-              builtins.filter builtins.isString (
122
-                builtins.split "\\." ipv4
123
-              )
124
-            )
125
-          ) + ".in-addr.arpa";
126
-
127
-        # `{ "1,0.0.127.in-addr.arpa" = "lo.core.zentralwerk.dn42"; }`
128
-        reverseHosts4 = builtins.foldl' (result: { hosts4, domainName, ... }:
129
-          builtins.foldl' (result: host: result // {
130
-            "${ipv4ToReverse hosts4.${host}}" = "${host}.${domainName}";
131
-          }) result (builtins.attrNames hosts4)
132
-        ) {} (builtins.attrValues namedNets);
133
-
134
-        # `[ "0.0.127.in-addr.arpa" ]`
135
-        reverseZones4 = builtins.attrNames (
136
-          builtins.foldl' (result: rname:
137
-            let
138
-              zone = builtins.head (
139
-                builtins.match "[[:digit:]]+\\.(.+)" rname
140
-              );
141
-            in result // {
142
-              "${zone}" = true;
143
-            }
144
-          ) {} (builtins.attrNames reverseHosts4)
145
-        );
146
-
147
-        # turns `::` into `0000:0000:0000:0000:0000:0000:0000:0000`
148
-        expandIpv6 = ipv6:
149
-          if lib.hasPrefix "::" ipv6
150
-          then expandIpv6 "0${ipv6}"
151
-
152
-          else if lib.hasSuffix "::" ipv6
153
-          then expandIpv6 "${ipv6}0"
154
-
155
-          else let
156
-            words = builtins.filter builtins.isString (
157
-              builtins.split ":" ipv6
158
-            );
159
-            fillWordCount = 8 - builtins.length words;
160
-            fillWords = n:
161
-              if n >= 0
162
-              then [ "0000" ] ++ fillWords (n - 1)
163
-              else [];
164
-            words' = builtins.concatMap (word:
165
-              if word == ""
166
-              then fillWords fillWordCount
167
-              else [ word ]
168
-            ) words;
169
-            leftPad = padding: target: s:
170
-              if builtins.stringLength s < target
171
-              then leftPad padding target "${padding}${s}"
172
-              else s;
173
-            words'' = map (leftPad "0" 4) words';
174
-          in
175
-            builtins.concatStringsSep ":" words'';
176
-
177
-        # 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`
178
-        ipv6ToReverse = ipv6:
179
-          builtins.concatStringsSep "." (
180
-            lib.reverseList (
181
-              lib.stringToCharacters (
182
-                builtins.replaceStrings [":"] [""] (expandIpv6 ipv6)
183
-              )
184
-            )
185
-          ) + ".ip6.arpa";
186
-
187
-        # `{ dn42 = { "...ip6.arpa" = "lo.core.zentralwerk.dn42"; }; }`
188
-        reverseHosts6 = builtins.foldl' (result: net: lib.recursiveUpdate result (
189
-          builtins.mapAttrs (ctx: hosts:
190
-            builtins.foldl' (result: host:
191
-              let
192
-                domain =
193
-                  if ctx == "dn42"
194
-                  then namedNets.${net}.domainName
195
-                  else if builtins.match "up.*" ctx != null
196
-                  then "${net}.zentralwerk.org"
197
-                  else throw "Invalid IPv6 context: ${ctx}";
198
-              in
199
-                lib.recursiveUpdate result {
200
-                  "${ipv6ToReverse hosts.${host}}" = "${host}.${domain}";
201
-                }
202
-            ) {} (builtins.attrNames hosts)
203
-          ) namedNets.${net}.hosts6
204
-        )) {} (builtins.attrNames namedNets);
205
-
206
-        # `{ dn42 = [ "....ip6.arpa" ]; }`
207
-        reverseZones6 = builtins.mapAttrs (ctx: reverseHosts6ctx:
208
-          builtins.attrNames (
209
-            builtins.foldl' (result: rname: result // {
210
-              "${builtins.substring ((128 - reverseZone6Size) / 2) (72 - ((128 - reverseZone6Size) / 2)) rname}" = true;
211
-            }) {} (builtins.attrNames reverseHosts6ctx)
212
-          )
213
-        ) reverseHosts6;
214
-
215
-      in [ {
216
-        name = "zentralwerk.org";
217
-        ns = publicNS;
218
-        records = [];
219
-      } {
220
-        name = "zentralwerk.dn42";
221
-        ns = [ fqdn ];
222
-        records = [ {
223
-          name = "ipa";
224
-          type = "A";
225
-          data = config.site.net.serv.hosts4.ipa;
226
-        } ];
227
-      } {
228
-        name = "dyn.zentralwerk.org";
229
-        ns = publicNS;
230
-        # TODO: implement dyndns
231
-        records = [ {
232
-          name = "upstream1";
233
-          type = "A";
234
-          data = "24.134.104.53";
235
-        } {
236
-          name = "upstream2";
237
-          type = "A";
238
-          data = "24.134.252.105";
239
-        } ];
240
-      } ] ++ builtins.concatLists (
241
-        builtins.attrValues (
242
-          builtins.mapAttrs (net: { dynamicDomain, hosts4, hosts6, ... }: [
243
-            {
244
-              name = "${net}.zentralwerk.dn42";
245
-              ns = [ fqdn ];
246
-              records =
247
-                hosts4Records hosts4 ++
248
-                lib.optionals (hosts6 ? dn42) (hosts6Records hosts6.dn42);
249
-              dynamic = dynamicDomain;
250
-            }
251
-            {
252
-              name = "${net}.zentralwerk.org";
253
-              ns = publicNS;
254
-              records =
255
-                lib.optionals (hosts6 ? up1) (hosts6Records hosts6.up1) ++
256
-                lib.optionals (hosts6 ? up2) (hosts6Records hosts6.up2);
257
-            }
258
-          ]) namedNets
259
-        )
260
-      ) ++ map (zone: {
261
-        name = zone;
262
-        ns = [ fqdn ];
263
-        records =
264
-          map (reverse: {
265
-            name = builtins.head (
266
-              builtins.match "([[:digit:]]+)\\..*" reverse
267
-            );
268
-            type = "PTR";
269
-            data = "${reverseHosts4.${reverse}}.";
270
-          }) (
271
-            builtins.filter (lib.hasSuffix ".${zone}")
272
-              (builtins.attrNames reverseHosts4)
273
-          );
274
-        dynamic = builtins.elem zone dynamicReverseZones;
275
-      }) reverseZones4
276
-      ++ builtins.concatMap (ctx:
277
-        map (zone: {
278
-          name = zone;
279
-          ns =
280
-            if ctx == "dn42"
281
-            then [ fqdn ]
282
-            else if builtins.match "up.*" ctx != null
283
-            then publicNS
284
-            else throw "Invalid IPv6 context: ${ctx}";
285
-          records =
286
-            map (reverse: {
287
-              name = builtins.substring 0 ((128 - reverseZone6Size) / 2 - 1) reverse;
288
-              type = "PTR";
289
-              data = "${reverseHosts6.${ctx}.${reverse}}.";
290
-            }) (
291
-              builtins.filter (lib.hasSuffix ".${zone}")
292
-                (builtins.attrNames reverseHosts6.${ctx})
293
-            );
294
-        }) reverseZones6.${ctx}
295
-      ) (builtins.attrNames reverseZones6);
77
+    site.dns.localZones = lib.dns.localZones;
296 78
 
297 79
     services.bind = lib.mkIf config.site.hosts.${hostName}.services.dns.enable (
298 80
       let

Loading…
Cancel
Save