python3Packages.xknx: 1.1.0 -> 1.2.0
[NixPkgs.git] / nixos / tests / common / resolver.nix
blob3ddf730668c4fdb2fd927c5e80b89d98d12f24cc
1 # This module automatically discovers zones in BIND and NSD NixOS
2 # configurations and creates zones for all definitions of networking.extraHosts
3 # (except those that point to 127.0.0.1 or ::1) within the current test network
4 # and delegates these zones using a fake root zone served by a BIND recursive
5 # name server.
6 { config, nodes, pkgs, lib, ... }:
9   options.test-support.resolver.enable = lib.mkOption {
10     type = lib.types.bool;
11     default = true;
12     internal = true;
13     description = lib.mdDoc ''
14       Whether to enable the resolver that automatically discovers zone in the
15       test network.
17       This option is `true` by default, because the module
18       defining this option needs to be explicitly imported.
20       The reason this option exists is for the
21       {file}`nixos/tests/common/acme/server` module, which
22       needs that option to disable the resolver once the user has set its own
23       resolver.
24     '';
25   };
27   config = lib.mkIf config.test-support.resolver.enable {
28     networking.firewall.enable = false;
29     services.bind.enable = true;
30     services.bind.cacheNetworks = lib.mkForce [ "any" ];
31     services.bind.forwarders = lib.mkForce [];
32     services.bind.zones = lib.singleton {
33       name = ".";
34       file = let
35         addDot = zone: zone + lib.optionalString (!lib.hasSuffix "." zone) ".";
36         mkNsdZoneNames = zones: map addDot (lib.attrNames zones);
37         mkBindZoneNames = zones: map (zone: addDot zone.name) zones;
38         getZones = cfg: mkNsdZoneNames cfg.services.nsd.zones
39                      ++ mkBindZoneNames cfg.services.bind.zones;
41         getZonesForNode = attrs: {
42           ip = attrs.config.networking.primaryIPAddress;
43           zones = lib.filter (zone: zone != ".") (getZones attrs.config);
44         };
46         zoneInfo = lib.mapAttrsToList (lib.const getZonesForNode) nodes;
48         # A and AAAA resource records for all the definitions of
49         # networking.extraHosts except those for 127.0.0.1 or ::1.
50         #
51         # The result is an attribute set with keys being the host name and the
52         # values are either { ipv4 = ADDR; } or { ipv6 = ADDR; } where ADDR is
53         # the IP address for the corresponding key.
54         recordsFromExtraHosts = let
55           getHostsForNode = lib.const (n: n.config.networking.extraHosts);
56           allHostsList = lib.mapAttrsToList getHostsForNode nodes;
57           allHosts = lib.concatStringsSep "\n" allHostsList;
59           reIp = "[a-fA-F0-9.:]+";
60           reHost = "[a-zA-Z0-9.-]+";
62           matchAliases = str: let
63             matched = builtins.match "[ \t]+(${reHost})(.*)" str;
64             continue = lib.singleton (lib.head matched)
65                     ++ matchAliases (lib.last matched);
66           in if matched == null then [] else continue;
68           matchLine = str: let
69             result = builtins.match "[ \t]*(${reIp})[ \t]+(${reHost})(.*)" str;
70           in if result == null then null else {
71             ipAddr = lib.head result;
72             hosts = lib.singleton (lib.elemAt result 1)
73                  ++ matchAliases (lib.last result);
74           };
76           skipLine = str: let
77             rest = builtins.match "[^\n]*\n(.*)" str;
78           in if rest == null then "" else lib.head rest;
80           getEntries = str: acc: let
81             result = matchLine str;
82             next = getEntries (skipLine str);
83             newEntry = acc ++ lib.singleton result;
84             continue = if result == null then next acc else next newEntry;
85           in if str == "" then acc else continue;
87           isIPv6 = str: builtins.match ".*:.*" str != null;
88           loopbackIps = [ "127.0.0.1" "::1" ];
89           filterLoopback = lib.filter (e: !lib.elem e.ipAddr loopbackIps);
91           allEntries = lib.concatMap (entry: map (host: {
92             inherit host;
93             ${if isIPv6 entry.ipAddr then "ipv6" else "ipv4"} = entry.ipAddr;
94           }) entry.hosts) (filterLoopback (getEntries (allHosts + "\n") []));
96           mkRecords = entry: let
97             records = lib.optional (entry ? ipv6) "AAAA ${entry.ipv6}"
98                    ++ lib.optional (entry ? ipv4) "A ${entry.ipv4}";
99             mkRecord = typeAndData: "${entry.host}. IN ${typeAndData}";
100           in lib.concatMapStringsSep "\n" mkRecord records;
102         in lib.concatMapStringsSep "\n" mkRecords allEntries;
104         # All of the zones that are subdomains of existing zones.
105         # For example if there is only "example.com" the following zones would
106         # be 'subZones':
107         #
108         #  * foo.example.com.
109         #  * bar.example.com.
110         #
111         # While the following would *not* be 'subZones':
112         #
113         #  * example.com.
114         #  * com.
115         #
116         subZones = let
117           allZones = lib.concatMap (zi: zi.zones) zoneInfo;
118           isSubZoneOf = z1: z2: lib.hasSuffix z2 z1 && z1 != z2;
119         in lib.filter (z: lib.any (isSubZoneOf z) allZones) allZones;
121         # All the zones without 'subZones'.
122         filteredZoneInfo = map (zi: zi // {
123           zones = lib.filter (x: !lib.elem x subZones) zi.zones;
124         }) zoneInfo;
126       in pkgs.writeText "fake-root.zone" ''
127         $TTL 3600
128         . IN SOA ns.fakedns. admin.fakedns. ( 1 3h 1h 1w 1d )
129         ns.fakedns. IN A ${config.networking.primaryIPAddress}
130         . IN NS ns.fakedns.
131         ${lib.concatImapStrings (num: { ip, zones }: ''
132           ns${toString num}.fakedns. IN A ${ip}
133           ${lib.concatMapStrings (zone: ''
134           ${zone} IN NS ns${toString num}.fakedns.
135           '') zones}
136         '') (lib.filter (zi: zi.zones != []) filteredZoneInfo)}
137         ${recordsFromExtraHosts}
138       '';
139     };
140   };