summaryrefslogtreecommitdiffstats
path: root/krebs/3modules/zones.nix
blob: e68482d777bf33f698df1ccdab360ea4b5d4d3e3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
{ config, pkgs, lib, ... }:
with lib; {

  options.krebs.zone-head-config = mkOption {
    type = lib.types.attrsOf lib.types.str;
    description = ''
      The zone configuration head which is being used to create the
      zone files. The string for each key is pre-pended to the zone file.
    '';
    default = {
      "krebsco.de" = /* bindzone */ ''
        $TTL 60
        @ 3600 IN SOA spam.krebsco.de. spam.krebsco.de. 0 7200 3600 86400 3600
        @ 3600 IN NS ns1
        @ 3600 IN NS ni
        @ 3600 IN NS ns2.he.net.
        @ 3600 IN NS ns3.he.net.
        @ 3600 IN NS ns2.hosting.de.
      '';
    };
  };

  config = {
    environment.etc =
      mapAttrs'
        (name: pkg: {
          name = "zones/${name}";
          value.source = pkg;
        })
        pkgs.krebs.zones;

    nixpkgs.overlays = [
      # Explicit zones generated from config.krebs.hosts.*.extraZones
      (self: super: let
        stripEmptyLines = s: (concatStringsSep "\n"
          (remove "\n" (remove "" (splitString "\n" s)))) + "\n";
        all-zones = foldAttrs (sum: current: sum + "\n" + current) ""
          ([config.krebs.zone-head-config] ++ combined-hosts);
        combined-hosts =
          mapAttrsToList (name: getAttr "extraZones") config.krebs.hosts;
      in {
        krebs = super.krebs or {} // {
          zones = super.krebs.zones or {} //
            mapAttrs'
              (name: value: {
                name = name;
                value = self.writeText "${name}.zone" (stripEmptyLines value);
              })
              all-zones;
        };
      })

      # Implicit zones generated from config.krebs.hosts.*.nets.*.ip{4,6}.addr
      (self: super: let
        # record : { name : str, type : enum [ "A" "AAAA" ], data : str }

        # toRecord : record.name -> record.type -> record.data -> record
        toRecord = name: type: data:
          { inherit name type data; };

        # toRecords : str -> host -> [record]
        toRecords = netname: host:
          let
            net = host.nets.${netname};
          in
          optionals
            (hasAttr netname host.nets)
            (filter
              (x: x.data != null)
              (concatLists [
                (map
                  (name: toRecord name "A" (net.ip4.addr or null))
                  (concatMap
                    (name: [ "${name}." "4.${name}." ])
                    (net.aliases or [])))
                (map
                  (name: toRecord name "AAAA" (net.ip6.addr or null))
                  (concatMap
                    (name: [ "${name}." "6.${name}." ])
                    (net.aliases or [])))
              ]));

        # formatRecord : record -> str
        formatRecord = { name, type, data }: "${name} IN ${type} ${data}";

        # writeZone : attrs -> package
        writeZone =
          { name ? "${domain}.zone"
          , domain ? substring 0 1 netname
          , nameservers ? [ "ni" ]
          , netname
          , hosts ? config.krebs.hosts
          }:
          self.writeText name /* bindzone */ ''
            $TTL 60
            @ IN SOA ns admin 1 3600 600 86400 60
            @ IN NS ns
            ${concatMapStringsSep "\n"
              (name: /* bindzone */ "ns IN CNAME ${name}")
              nameservers
            }
            ${concatMapStringsSep
                "\n"
                formatRecord
                (concatMap
                  (toRecords netname)
                  (attrValues hosts))
            }
          '';
      in {
        krebs = super.krebs or {} // {
          zones = super.krebs.zones or {} // {
            i = writeZone { netname = "internet"; };
            r = writeZone { netname = "retiolum"; };
            w = writeZone { netname = "wiregrill"; };
          };
        };
      })
    ];
  };

}