vuls: init at 0.27.0
[NixPkgs.git] / nixos / modules / services / networking / bind.nix
blob6079062db6c3705e91201344e31b883cb6c67ddf
1 { config, lib, pkgs, ... }:
2 let
4   cfg = config.services.bind;
6   bindPkg = config.services.bind.package;
8   bindUser = "named";
10   bindZoneCoerce = list: builtins.listToAttrs (lib.forEach list (zone: { name = zone.name; value = zone; }));
12   bindZoneOptions = { name, config, ... }: {
13     options = {
14       name = lib.mkOption {
15         type = lib.types.str;
16         default = name;
17         description = "Name of the zone.";
18       };
19       master = lib.mkOption {
20         description = "Master=false means slave server";
21         type = lib.types.bool;
22       };
23       file = lib.mkOption {
24         type = lib.types.either lib.types.str lib.types.path;
25         description = "Zone file resource records contain columns of data, separated by whitespace, that define the record.";
26       };
27       masters = lib.mkOption {
28         type = lib.types.listOf lib.types.str;
29         description = "List of servers for inclusion in stub and secondary zones.";
30       };
31       slaves = lib.mkOption {
32         type = lib.types.listOf lib.types.str;
33         description = "Addresses who may request zone transfers.";
34         default = [ ];
35       };
36       allowQuery = lib.mkOption {
37         type = lib.types.listOf lib.types.str;
38         description = ''
39           List of address ranges allowed to query this zone. Instead of the address(es), this may instead
40           contain the single string "any".
42           NOTE: This overrides the global-level `allow-query` setting, which is set to the contents
43           of `cachenetworks`.
44         '';
45         default = [ "any" ];
46       };
47       extraConfig = lib.mkOption {
48         type = lib.types.lines;
49         description = "Extra zone config to be appended at the end of the zone section.";
50         default = "";
51       };
52     };
53   };
55   confFile = pkgs.writeText "named.conf"
56     ''
57       include "/etc/bind/rndc.key";
58       controls {
59         inet 127.0.0.1 allow {localhost;} keys {"rndc-key";};
60       };
62       acl cachenetworks { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.cacheNetworks} };
63       acl badnetworks { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.blockedNetworks} };
65       options {
66         listen-on { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.listenOn} };
67         listen-on-v6 { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.listenOnIpv6} };
68         allow-query { cachenetworks; };
69         blackhole { badnetworks; };
70         forward ${cfg.forward};
71         forwarders { ${lib.concatMapStrings (entry: " ${entry}; ") cfg.forwarders} };
72         directory "${cfg.directory}";
73         pid-file "/run/named/named.pid";
74         ${cfg.extraOptions}
75       };
77       ${cfg.extraConfig}
79       ${ lib.concatMapStrings
80           ({ name, file, master ? true, slaves ? [], masters ? [], allowQuery ? [], extraConfig ? "" }:
81             ''
82               zone "${name}" {
83                 type ${if master then "master" else "slave"};
84                 file "${file}";
85                 ${ if master then
86                    ''
87                      allow-transfer {
88                        ${lib.concatMapStrings (ip: "${ip};\n") slaves}
89                      };
90                    ''
91                    else
92                    ''
93                      masters {
94                        ${lib.concatMapStrings (ip: "${ip};\n") masters}
95                      };
96                    ''
97                 }
98                 allow-query { ${lib.concatMapStrings (ip: "${ip}; ") allowQuery}};
99                 ${extraConfig}
100               };
101             '')
102           (lib.attrValues cfg.zones) }
103     '';
109   ###### interface
111   options = {
113     services.bind = {
115       enable = lib.mkEnableOption "BIND domain name server";
118       package = lib.mkPackageOption pkgs "bind" { };
120       cacheNetworks = lib.mkOption {
121         default = [ "127.0.0.0/24" "::1/128" ];
122         type = lib.types.listOf lib.types.str;
123         description = ''
124           What networks are allowed to use us as a resolver.  Note
125           that this is for recursive queries -- all networks are
126           allowed to query zones configured with the `zones` option
127           by default (although this may be overridden within each
128           zone's configuration, via the `allowQuery` option).
129           It is recommended that you limit cacheNetworks to avoid your
130           server being used for DNS amplification attacks.
131         '';
132       };
134       blockedNetworks = lib.mkOption {
135         default = [ ];
136         type = lib.types.listOf lib.types.str;
137         description = ''
138           What networks are just blocked.
139         '';
140       };
142       ipv4Only = lib.mkOption {
143         default = false;
144         type = lib.types.bool;
145         description = ''
146           Only use ipv4, even if the host supports ipv6.
147         '';
148       };
150       forwarders = lib.mkOption {
151         default = config.networking.nameservers;
152         defaultText = lib.literalExpression "config.networking.nameservers";
153         type = lib.types.listOf lib.types.str;
154         description = ''
155           List of servers we should forward requests to.
156         '';
157       };
159       forward = lib.mkOption {
160         default = "first";
161         type = lib.types.enum ["first" "only"];
162         description = ''
163           Whether to forward 'first' (try forwarding but lookup directly if forwarding fails) or 'only'.
164         '';
165       };
167       listenOn = lib.mkOption {
168         default = [ "any" ];
169         type = lib.types.listOf lib.types.str;
170         description = ''
171           Interfaces to listen on.
172         '';
173       };
175       listenOnIpv6 = lib.mkOption {
176         default = [ "any" ];
177         type = lib.types.listOf lib.types.str;
178         description = ''
179           Ipv6 interfaces to listen on.
180         '';
181       };
183       directory = lib.mkOption {
184         type = lib.types.str;
185         default = "/run/named";
186         description = "Working directory of BIND.";
187       };
189       zones = lib.mkOption {
190         default = [ ];
191         type = with lib.types; coercedTo (listOf attrs) bindZoneCoerce (attrsOf (lib.types.submodule bindZoneOptions));
192         description = ''
193           List of zones we claim authority over.
194         '';
195         example = {
196           "example.com" = {
197             master = false;
198             file = "/var/dns/example.com";
199             masters = [ "192.168.0.1" ];
200             slaves = [ ];
201             extraConfig = "";
202           };
203         };
204       };
206       extraConfig = lib.mkOption {
207         type = lib.types.lines;
208         default = "";
209         description = ''
210           Extra lines to be added verbatim to the generated named configuration file.
211         '';
212       };
214       extraOptions = lib.mkOption {
215         type = lib.types.lines;
216         default = "";
217         description = ''
218           Extra lines to be added verbatim to the options section of the
219           generated named configuration file.
220         '';
221       };
223       configFile = lib.mkOption {
224         type = lib.types.path;
225         default = confFile;
226         defaultText = lib.literalExpression "confFile";
227         description = ''
228           Overridable config file to use for named. By default, that
229           generated by nixos.
230         '';
231       };
233     };
235   };
238   ###### implementation
240   config = lib.mkIf cfg.enable {
242     networking.resolvconf.useLocalResolver = lib.mkDefault true;
244     users.users.${bindUser} =
245       {
246         group = bindUser;
247         description = "BIND daemon user";
248         isSystemUser = true;
249       };
250     users.groups.${bindUser} = {};
252     systemd.services.bind = {
253       description = "BIND Domain Name Server";
254       after = [ "network.target" ];
255       wantedBy = [ "multi-user.target" ];
257       preStart = ''
258         mkdir -m 0755 -p /etc/bind
259         if ! [ -f "/etc/bind/rndc.key" ]; then
260           ${bindPkg.out}/sbin/rndc-confgen -c /etc/bind/rndc.key -u ${bindUser} -a -A hmac-sha256 2>/dev/null
261         fi
263         ${pkgs.coreutils}/bin/mkdir -p /run/named
264         chown ${bindUser} /run/named
266         ${pkgs.coreutils}/bin/mkdir -p ${cfg.directory}
267         chown ${bindUser} ${cfg.directory}
268       '';
270       serviceConfig = {
271         Type = "forking"; # Set type to forking, see https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=900788
272         ExecStart = "${bindPkg.out}/sbin/named -u ${bindUser} ${lib.optionalString cfg.ipv4Only "-4"} -c ${cfg.configFile}";
273         ExecReload = "${bindPkg.out}/sbin/rndc -k '/etc/bind/rndc.key' reload";
274         ExecStop = "${bindPkg.out}/sbin/rndc -k '/etc/bind/rndc.key' stop";
275       };
277       unitConfig.Documentation = "man:named(8)";
278     };
279   };