···226226 was removed. Please review the currently available options.</para>
227227 </listitem>
228228229229+ <listitem>
230230+ <para>
231231+ The option <option>services.nsd.zones.<name>.data</option> no
232232+ longer interpret the dollar sign ($) as a shell variable, as such it
233233+ should not be escaped anymore. Thus the following zone data:
234234+ </para>
235235+ <programlisting>
236236+\$ORIGIN example.com.
237237+\$TTL 1800
238238+@ IN SOA ns1.vpn.nbp.name. admin.example.com. (
239239+ </programlisting>
240240+ <para>
241241+ Should modified to look like the actual file expected by nsd:
242242+ </para>
243243+ <programlisting>
244244+$ORIGIN example.com.
245245+$TTL 1800
246246+@ IN SOA ns1.vpn.nbp.name. admin.example.com. (
247247+ </programlisting>
248248+ </listitem>
249249+229250</itemizedlist>
230251231252
+493-416
nixos/modules/services/networking/nsd.nix
···7788 username = "nsd";
99 stateDir = "/var/lib/nsd";
1010- pidFile = stateDir + "/var/nsd.pid";
1010+ pidFile = stateDir + "/var/nsd.pid";
11111212+ # build nsd with the options needed for the given config
1213 nsdPkg = pkgs.nsd.override {
1314 bind8Stats = cfg.bind8Stats;
1414- ipv6 = cfg.ipv6;
1515- ratelimit = cfg.ratelimit.enable;
1515+ ipv6 = cfg.ipv6;
1616+ ratelimit = cfg.ratelimit.enable;
1617 rootServer = cfg.rootServer;
1717- zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0;
1818+ zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0;
1819 };
19202020- zoneFiles = pkgs.stdenv.mkDerivation {
2121- preferLocalBuild = true;
2121+2222+ nsdEnv = pkgs.buildEnv {
2223 name = "nsd-env";
2323- buildCommand = concatStringsSep "\n"
2424- [ "mkdir -p $out"
2525- (concatStrings (mapAttrsToList (zoneName: zoneOptions: ''
2626- cat > "$out/${zoneName}" <<_EOF_
2727- ${zoneOptions.data}
2828- _EOF_
2929- '') zoneConfigs))
3030- ];
2424+2525+ paths = [ configFile ]
2626+ ++ mapAttrsToList (name: zone: writeZoneData name zone.data) zoneConfigs;
2727+2828+ postBuild = ''
2929+ echo "checking zone files"
3030+ cd $out/zones
3131+3232+ for zoneFile in *; do
3333+ ${nsdPkg}/sbin/nsd-checkzone "$zoneFile" "$zoneFile" || {
3434+ if grep -q \\\\\\$ "$zoneFile"; then
3535+ echo zone "$zoneFile" contains escaped dollar signes \\\$
3636+ echo Escaping them is not needed any more. Please make shure \
3737+ to unescape them where they prefix a variable name
3838+ fi
3939+4040+ exit 1
4141+ }
4242+ done
4343+4444+ echo "checking configuration file"
4545+ ${nsdPkg}/sbin/nsd-checkconf $out/nsd.conf
4646+ '';
3147 };
32483333- configFile = pkgs.writeText "nsd.conf" ''
4949+ writeZoneData = name: text: pkgs.writeTextFile {
5050+ inherit name text;
5151+ destination = "/zones/${name}";
5252+ };
5353+5454+5555+ # options are ordered alphanumerically by the nixos option name
5656+ configFile = pkgs.writeTextDir "nsd.conf" ''
3457 server:
5858+ chroot: "${stateDir}"
3559 username: ${username}
3636- chroot: "${stateDir}"
37603861 # The directory for zonefile: files. The daemon chdirs here.
3962 zonesdir: "${stateDir}"
40634164 # the list of dynamically added zones.
4242- zonelistfile: "${stateDir}/var/zone.list"
4365 database: "${stateDir}/var/nsd.db"
4466 pidfile: "${pidFile}"
4567 xfrdfile: "${stateDir}/var/xfrd.state"
4668 xfrdir: "${stateDir}/tmp"
6969+ zonelistfile: "${stateDir}/var/zone.list"
47704871 # interfaces
4972 ${forEach " ip-address: " cfg.interfaces}
50735151- server-count: ${toString cfg.serverCount}
7474+ hide-version: ${yesOrNo cfg.hideVersion}
7575+ identity: "${cfg.identity}"
5276 ip-transparent: ${yesOrNo cfg.ipTransparent}
5377 do-ip4: ${yesOrNo cfg.ipv4}
7878+ ipv4-edns-size: ${toString cfg.ipv4EDNSSize}
5479 do-ip6: ${yesOrNo cfg.ipv6}
8080+ ipv6-edns-size: ${toString cfg.ipv6EDNSSize}
8181+ log-time-ascii: ${yesOrNo cfg.logTimeAscii}
8282+ ${maybeString "nsid: " cfg.nsid}
5583 port: ${toString cfg.port}
5656- verbosity: ${toString cfg.verbosity}
5757- hide-version: ${yesOrNo cfg.hideVersion}
5858- identity: "${cfg.identity}"
5959- ${maybeString "nsid: " cfg.nsid}
8484+ reuseport: ${yesOrNo cfg.reuseport}
8585+ round-robin: ${yesOrNo cfg.roundRobin}
8686+ server-count: ${toString cfg.serverCount}
8787+ ${if cfg.statistics == null then "" else "statistics: ${toString cfg.statistics}"}
6088 tcp-count: ${toString cfg.tcpCount}
6189 tcp-query-count: ${toString cfg.tcpQueryCount}
6290 tcp-timeout: ${toString cfg.tcpTimeout}
6363- ipv4-edns-size: ${toString cfg.ipv4EDNSSize}
6464- ipv6-edns-size: ${toString cfg.ipv6EDNSSize}
6565- ${if cfg.statistics == null then "" else "statistics: ${toString cfg.statistics}"}
9191+ verbosity: ${toString cfg.verbosity}
9292+ ${maybeString "version: " cfg.version}
6693 xfrd-reload-timeout: ${toString cfg.xfrdReloadTimeout}
6794 zonefiles-check: ${yesOrNo cfg.zonefilesCheck}
68956969- rrl-size: ${toString cfg.ratelimit.size}
7070- rrl-ratelimit: ${toString cfg.ratelimit.ratelimit}
7171- rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit}
7272- ${maybeString "rrl-slip: " cfg.ratelimit.slip}
7396 ${maybeString "rrl-ipv4-prefix-length: " cfg.ratelimit.ipv4PrefixLength}
7497 ${maybeString "rrl-ipv6-prefix-length: " cfg.ratelimit.ipv6PrefixLength}
9898+ rrl-ratelimit: ${toString cfg.ratelimit.ratelimit}
9999+ ${maybeString "rrl-slip: " cfg.ratelimit.slip}
100100+ rrl-size: ${toString cfg.ratelimit.size}
101101+ rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit}
7510276103 ${keyConfigFile}
7710478105 remote-control:
79106 control-enable: ${yesOrNo cfg.remoteControl.enable}
107107+ control-key-file: "${cfg.remoteControl.controlKeyFile}"
108108+ control-cert-file: "${cfg.remoteControl.controlCertFile}"
80109 ${forEach " control-interface: " cfg.remoteControl.interfaces}
8181- control-port: ${toString cfg.port}
110110+ control-port: ${toString cfg.remoteControl.port}
82111 server-key-file: "${cfg.remoteControl.serverKeyFile}"
83112 server-cert-file: "${cfg.remoteControl.serverCertFile}"
8484- control-key-file: "${cfg.remoteControl.controlKeyFile}"
8585- control-cert-file: "${cfg.remoteControl.controlCertFile}"
861138787- # zone files reside in "${zoneFiles}" linked to "${stateDir}/zones"
88114 ${concatStrings (mapAttrsToList zoneConfigFile zoneConfigs)}
8911590116 ${cfg.extraConfig}
91117 '';
921189393- yesOrNo = b: if b then "yes" else "no";
119119+ yesOrNo = b: if b then "yes" else "no";
94120 maybeString = pre: s: if s == null then "" else ''${pre} "${s}"'';
9595- forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
121121+ forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
961229712398124 keyConfigFile = concatStrings (mapAttrsToList (keyName: keyOptions: ''
···106132 secret=$(cat "${keyOptions.keyFile}")
107133 dest="${stateDir}/private/${keyName}"
108134 echo " secret: \"$secret\"" > "$dest"
109109- ${pkgs.coreutils}/bin/chown ${username}:${username} "$dest"
110110- ${pkgs.coreutils}/bin/chmod 0400 "$dest"
135135+ chown ${username}:${username} "$dest"
136136+ chmod 0400 "$dest"
111137 '') cfg.keys);
112138113139140140+ # options are ordered alphanumerically by the nixos option name
114141 zoneConfigFile = name: zone: ''
115142 zone:
116143 name: "${name}"
117144 zonefile: "${stateDir}/zones/${name}"
118118- ${maybeString "zonestats: " zone.zoneStats}
119145 ${maybeString "outgoing-interface: " zone.outgoingInterface}
120146 ${forEach " rrl-whitelist: " zone.rrlWhitelist}
147147+ ${maybeString "zonestats: " zone.zoneStats}
121148149149+ allow-axfr-fallback: ${yesOrNo zone.allowAXFRFallback}
122150 ${forEach " allow-notify: " zone.allowNotify}
123151 ${forEach " request-xfr: " zone.requestXFR}
124124- allow-axfr-fallback: ${yesOrNo zone.allowAXFRFallback}
125152126153 ${forEach " notify: " zone.notify}
127154 notify-retry: ${toString zone.notifyRetry}
···142169 );
143170144171 # fighting infinite recursion
145145- zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true;
172172+ zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true;
146173 zoneOptions1 = zoneOptionsRaw // childConfig zoneOptions2 false;
147174 zoneOptions2 = zoneOptionsRaw // childConfig zoneOptions3 false;
148175 zoneOptions3 = zoneOptionsRaw // childConfig zoneOptions4 false;
···152179153180 childConfig = x: v: { options.children = { type = types.attrsOf x; visible = v; }; };
154181182182+ # options are ordered alphanumerically
155183 zoneOptionsRaw = types.submodule {
156184 options = {
157157- children = mkOption {
158158- default = {};
185185+186186+ allowAXFRFallback = mkOption {
187187+ type = types.bool;
188188+ default = true;
159189 description = ''
160160- Children zones inherit all options of their parents. Attributes
161161- defined in a child will overwrite the ones of its parent. Only
162162- leaf zones will be actually served. This way it's possible to
163163- define maybe zones which share most attributes without
164164- duplicating everything. This mechanism replaces nsd's patterns
165165- in a save and functional way.
190190+ If NSD as secondary server should be allowed to AXFR if the primary
191191+ server does not allow IXFR.
166192 '';
167193 };
168194169195 allowNotify = mkOption {
170170- type = types.listOf types.str;
171171- default = [ ];
172172- example = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name"
173173- "10.0.3.4&255.255.0.0 BLOCKED"
174174- ];
196196+ type = types.listOf types.str;
197197+ default = [ ];
198198+ example = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name"
199199+ "10.0.3.4&255.255.0.0 BLOCKED"
200200+ ];
175201 description = ''
176202 Listed primary servers are allowed to notify this secondary server.
177203 <screen><![CDATA[
···193219 '';
194220 };
195221196196- requestXFR = mkOption {
197197- type = types.listOf types.str;
198198- default = [];
199199- example = [];
222222+ children = mkOption {
223223+ default = {};
200224 description = ''
201201- Format: <code>[AXFR|UDP] <ip-address> <key-name | NOKEY></code>
225225+ Children zones inherit all options of their parents. Attributes
226226+ defined in a child will overwrite the ones of its parent. Only
227227+ leaf zones will be actually served. This way it's possible to
228228+ define maybe zones which share most attributes without
229229+ duplicating everything. This mechanism replaces nsd's patterns
230230+ in a save and functional way.
202231 '';
203232 };
204233205205- allowAXFRFallback = mkOption {
206206- type = types.bool;
207207- default = true;
234234+ data = mkOption {
235235+ type = types.str;
236236+ default = "";
237237+ example = "";
208238 description = ''
209209- If NSD as secondary server should be allowed to AXFR if the primary
210210- server does not allow IXFR.
239239+ The actual zone data. This is the content of your zone file.
240240+ Use imports or pkgs.lib.readFile if you don't want this data in your config file.
211241 '';
212242 };
213243214244 notify = mkOption {
215215- type = types.listOf types.str;
216216- default = [];
217217- example = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ];
245245+ type = types.listOf types.str;
246246+ default = [];
247247+ example = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ];
218248 description = ''
219249 This primary server will notify all given secondary servers about
220250 zone changes.
···231261 };
232262233263 notifyRetry = mkOption {
234234- type = types.int;
235235- default = 5;
264264+ type = types.int;
265265+ default = 5;
236266 description = ''
237267 Specifies the number of retries for failed notifies. Set this along with notify.
238268 '';
239269 };
240270271271+ outgoingInterface = mkOption {
272272+ type = types.nullOr types.str;
273273+ default = null;
274274+ example = "2000::1@1234";
275275+ description = ''
276276+ This address will be used for zone-transfere requests if configured
277277+ as a secondary server or notifications in case of a primary server.
278278+ Supply either a plain IPv4 or IPv6 address with an optional port
279279+ number (ip@port).
280280+ '';
281281+ };
282282+241283 provideXFR = mkOption {
242242- type = types.listOf types.str;
243243- default = [];
244244- example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ];
284284+ type = types.listOf types.str;
285285+ default = [];
286286+ example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ];
245287 description = ''
246288 Allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED
247289 address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40
248290 '';
249291 };
250292251251- outgoingInterface = mkOption {
252252- type = types.nullOr types.str;
253253- default = null;
254254- example = "2000::1@1234";
293293+ requestXFR = mkOption {
294294+ type = types.listOf types.str;
295295+ default = [];
296296+ example = [];
255297 description = ''
256256- This address will be used for zone-transfere requests if configured
257257- as a secondary server or notifications in case of a primary server.
258258- Supply either a plain IPv4 or IPv6 address with an optional port
259259- number (ip@port).
298298+ Format: <code>[AXFR|UDP] <ip-address> <key-name | NOKEY></code>
260299 '';
261300 };
262301263302 rrlWhitelist = mkOption {
264264- type = types.listOf types.str;
265265- default = [];
303303+ type = types.listOf types.str;
304304+ default = [];
266305 description = ''
267306 Whitelists the given rrl-types.
268307 The RRL classification types are: nxdomain, error, referral, any,
···270309 '';
271310 };
272311273273- data = mkOption {
274274- type = types.str;
275275- default = "";
276276- example = "";
277277- description = ''
278278- The actual zone data. This is the content of your zone file.
279279- Use imports or pkgs.lib.readFile if you don't want this data in your config file.
280280- '';
281281- };
282282-283312 zoneStats = mkOption {
284284- type = types.nullOr types.str;
285285- default = null;
286286- example = "%s";
313313+ type = types.nullOr types.str;
314314+ default = null;
315315+ example = "%s";
287316 description = ''
288317 When set to something distinct to null NSD is able to collect
289318 statistics per zone. All statistics of this zone(s) will be added
···292321 and stats_noreset.
293322 '';
294323 };
324324+295325 };
296326 };
297327298328in
299329{
300300- options = {
301301- services.nsd = {
330330+ # options are ordered alphanumerically
331331+ options.services.nsd = {
332332+333333+ enable = mkEnableOption "NSD authoritative DNS server";
334334+335335+ bind8Stats = mkEnableOption "BIND8 like statistics";
336336+337337+ extraConfig = mkOption {
338338+ type = types.str;
339339+ default = "";
340340+ description = ''
341341+ Extra nsd config.
342342+ '';
343343+ };
344344+345345+ hideVersion = mkOption {
346346+ type = types.bool;
347347+ default = true;
348348+ description = ''
349349+ Wheter NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries.
350350+ '';
351351+ };
352352+353353+ identity = mkOption {
354354+ type = types.str;
355355+ default = "unidentified server";
356356+ description = ''
357357+ Identify the server (CH TXT ID.SERVER entry).
358358+ '';
359359+ };
360360+361361+ interfaces = mkOption {
362362+ type = types.listOf types.str;
363363+ default = [ "127.0.0.0" "::1" ];
364364+ description = ''
365365+ What addresses the server should listen to.
366366+ '';
367367+ };
368368+369369+ ipTransparent = mkOption {
370370+ type = types.bool;
371371+ default = false;
372372+ description = ''
373373+ Allow binding to non local addresses.
374374+ '';
375375+ };
376376+377377+ ipv4 = mkOption {
378378+ type = types.bool;
379379+ default = true;
380380+ description = ''
381381+ Wheter to listen on IPv4 connections.
382382+ '';
383383+ };
384384+385385+ ipv4EDNSSize = mkOption {
386386+ type = types.int;
387387+ default = 4096;
388388+ description = ''
389389+ Preferred EDNS buffer size for IPv4.
390390+ '';
391391+ };
392392+393393+ ipv6 = mkOption {
394394+ type = types.bool;
395395+ default = true;
396396+ description = ''
397397+ Wheter to listen on IPv6 connections.
398398+ '';
399399+ };
400400+401401+ ipv6EDNSSize = mkOption {
402402+ type = types.int;
403403+ default = 4096;
404404+ description = ''
405405+ Preferred EDNS buffer size for IPv6.
406406+ '';
407407+ };
408408+409409+ logTimeAscii = mkOption {
410410+ type = types.bool;
411411+ default = true;
412412+ description = ''
413413+ Log time in ascii, if false then in unix epoch seconds.
414414+ '';
415415+ };
416416+417417+ nsid = mkOption {
418418+ type = types.nullOr types.str;
419419+ default = null;
420420+ description = ''
421421+ NSID identity (hex string, or "ascii_somestring").
422422+ '';
423423+ };
424424+425425+ port = mkOption {
426426+ type = types.int;
427427+ default = 53;
428428+ description = ''
429429+ Port the service should bind do.
430430+ '';
431431+ };
432432+433433+ reuseport = mkOption {
434434+ type = types.bool;
435435+ default = pkgs.stdenv.isLinux;
436436+ description = ''
437437+ Wheter to enable SO_REUSEPORT on all used sockets. This lets multiple
438438+ processes bind to the same port. This speeds up operation especially
439439+ if the server count is greater than one and makes fast restarts less
440440+ prone to fail
441441+ '';
442442+ };
443443+444444+ rootServer = mkOption {
445445+ type = types.bool;
446446+ default = false;
447447+ description = ''
448448+ Wheter if this server will be a root server (a DNS root server, you
449449+ usually don't want that).
450450+ '';
451451+ };
452452+453453+ roundRobin = mkEnableOption "round robin rotation of records";
454454+455455+ serverCount = mkOption {
456456+ type = types.int;
457457+ default = 1;
458458+ description = ''
459459+ Number of NSD servers to fork. Put the number of CPUs to use here.
460460+ '';
461461+ };
462462+463463+ statistics = mkOption {
464464+ type = types.nullOr types.int;
465465+ default = null;
466466+ description = ''
467467+ Statistics are produced every number of seconds. Prints to log.
468468+ If null no statistics are logged.
469469+ '';
470470+ };
471471+472472+ tcpCount = mkOption {
473473+ type = types.int;
474474+ default = 100;
475475+ description = ''
476476+ Maximum number of concurrent TCP connections per server.
477477+ '';
478478+ };
479479+480480+ tcpQueryCount = mkOption {
481481+ type = types.int;
482482+ default = 0;
483483+ description = ''
484484+ Maximum number of queries served on a single TCP connection.
485485+ 0 means no maximum.
486486+ '';
487487+ };
488488+489489+ tcpTimeout = mkOption {
490490+ type = types.int;
491491+ default = 120;
492492+ description = ''
493493+ TCP timeout in seconds.
494494+ '';
495495+ };
496496+497497+ verbosity = mkOption {
498498+ type = types.int;
499499+ default = 0;
500500+ description = ''
501501+ Verbosity level.
502502+ '';
503503+ };
504504+505505+ version = mkOption {
506506+ type = types.nullOr types.str;
507507+ default = null;
508508+ description = ''
509509+ The version string replied for CH TXT version.server and version.bind
510510+ queries. Will use the compiled package version on null.
511511+ See hideVersion for enabling/disabling this responses.
512512+ '';
513513+ };
302514303303- enable = mkEnableOption "NSD authoritative DNS server";
304304- bind8Stats = mkEnableOption "BIND8 like statistics";
515515+ xfrdReloadTimeout = mkOption {
516516+ type = types.int;
517517+ default = 1;
518518+ description = ''
519519+ Number of seconds between reloads triggered by xfrd.
520520+ '';
521521+ };
305522306306- rootServer = mkOption {
307307- type = types.bool;
308308- default = false;
309309- description = ''
310310- Wheter if this server will be a root server (a DNS root server, you
311311- usually don't want that).
312312- '';
313313- };
523523+ zonefilesCheck = mkOption {
524524+ type = types.bool;
525525+ default = true;
526526+ description = ''
527527+ Wheter to check mtime of all zone files on start and sighup.
528528+ '';
529529+ };
530530+531531+532532+ keys = mkOption {
533533+ type = types.attrsOf (types.submodule {
534534+ options = {
535535+536536+ algorithm = mkOption {
537537+ type = types.str;
538538+ default = "hmac-sha256";
539539+ description = ''
540540+ Authentication algorithm for this key.
541541+ '';
542542+ };
543543+544544+ keyFile = mkOption {
545545+ type = types.path;
546546+ description = ''
547547+ Path to the file which contains the actual base64 encoded
548548+ key. The key will be copied into "${stateDir}/private" before
549549+ NSD starts. The copied file is only accessibly by the NSD
550550+ user.
551551+ '';
552552+ };
553553+554554+ };
555555+ });
556556+ default = {};
557557+ example = literalExample ''
558558+ { "tsig.example.org" = {
559559+ algorithm = "hmac-md5";
560560+ keyFile = "/path/to/my/key";
561561+ };
562562+ };
563563+ '';
564564+ description = ''
565565+ Define your TSIG keys here.
566566+ '';
567567+ };
314568315315- interfaces = mkOption {
316316- type = types.listOf types.str;
317317- default = [ "127.0.0.0" "::1" ];
318318- description = ''
319319- What addresses the server should listen to.
320320- '';
321321- };
322569323323- serverCount = mkOption {
324324- type = types.int;
325325- default = 1;
326326- description = ''
327327- Number of NSD servers to fork. Put the number of CPUs to use here.
328328- '';
329329- };
570570+ ratelimit = {
330571331331- ipTransparent = mkOption {
332332- type = types.bool;
333333- default = false;
334334- description = ''
335335- Allow binding to non local addresses.
336336- '';
337337- };
572572+ enable = mkEnableOption "ratelimit capabilities";
338573339339- ipv4 = mkOption {
340340- type = types.bool;
341341- default = true;
574574+ ipv4PrefixLength = mkOption {
575575+ type = types.nullOr types.int;
576576+ default = null;
342577 description = ''
343343- Wheter to listen on IPv4 connections.
578578+ IPv4 prefix length. Addresses are grouped by netblock.
344579 '';
345580 };
346581347347- ipv6 = mkOption {
348348- type = types.bool;
349349- default = true;
582582+ ipv6PrefixLength = mkOption {
583583+ type = types.nullOr types.int;
584584+ default = null;
350585 description = ''
351351- Wheter to listen on IPv6 connections.
586586+ IPv6 prefix length. Addresses are grouped by netblock.
352587 '';
353588 };
354589355355- port = mkOption {
356356- type = types.int;
357357- default = 53;
590590+ ratelimit = mkOption {
591591+ type = types.int;
592592+ default = 200;
358593 description = ''
359359- Port the service should bind do.
594594+ Max qps allowed from any query source.
595595+ 0 means unlimited. With an verbosity of 2 blocked and
596596+ unblocked subnets will be logged.
360597 '';
361598 };
362599363363- verbosity = mkOption {
364364- type = types.int;
365365- default = 0;
600600+ slip = mkOption {
601601+ type = types.nullOr types.int;
602602+ default = null;
366603 description = ''
367367- Verbosity level.
604604+ Number of packets that get discarded before replying a SLIP response.
605605+ 0 disables SLIP responses. 1 will make every response a SLIP response.
368606 '';
369607 };
370608371371- hideVersion = mkOption {
372372- type = types.bool;
373373- default = true;
609609+ size = mkOption {
610610+ type = types.int;
611611+ default = 1000000;
374612 description = ''
375375- Wheter NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries.
613613+ Size of the hashtable. More buckets use more memory but lower
614614+ the chance of hash hash collisions.
376615 '';
377616 };
378617379379- identity = mkOption {
380380- type = types.str;
381381- default = "unidentified server";
618618+ whitelistRatelimit = mkOption {
619619+ type = types.int;
620620+ default = 2000;
382621 description = ''
383383- Identify the server (CH TXT ID.SERVER entry).
622622+ Max qps allowed from whitelisted sources.
623623+ 0 means unlimited. Set the rrl-whitelist option for specific
624624+ queries to apply this limit instead of the default to them.
384625 '';
385626 };
386627387387- nsid = mkOption {
388388- type = types.nullOr types.str;
389389- default = null;
390390- description = ''
391391- NSID identity (hex string, or "ascii_somestring").
392392- '';
393393- };
628628+ };
394629395395- tcpCount = mkOption {
396396- type = types.int;
397397- default = 100;
398398- description = ''
399399- Maximum number of concurrent TCP connections per server.
400400- '';
401401- };
402630403403- tcpQueryCount = mkOption {
404404- type = types.int;
405405- default = 0;
406406- description = ''
407407- Maximum number of queries served on a single TCP connection.
408408- 0 means no maximum.
409409- '';
410410- };
631631+ remoteControl = {
411632412412- tcpTimeout = mkOption {
413413- type = types.int;
414414- default = 120;
415415- description = ''
416416- TCP timeout in seconds.
417417- '';
418418- };
633633+ enable = mkEnableOption "remote control via nsd-control";
419634420420- ipv4EDNSSize = mkOption {
421421- type = types.int;
422422- default = 4096;
635635+ controlCertFile = mkOption {
636636+ type = types.path;
637637+ default = "/etc/nsd/nsd_control.pem";
423638 description = ''
424424- Preferred EDNS buffer size for IPv4.
639639+ Path to the client certificate signed with the server certificate.
640640+ This file is used by nsd-control and generated by nsd-control-setup.
425641 '';
426642 };
427643428428- ipv6EDNSSize = mkOption {
429429- type = types.int;
430430- default = 4096;
644644+ controlKeyFile = mkOption {
645645+ type = types.path;
646646+ default = "/etc/nsd/nsd_control.key";
431647 description = ''
432432- Preferred EDNS buffer size for IPv6.
648648+ Path to the client private key, which is used by nsd-control
649649+ but not by the server. This file is generated by nsd-control-setup.
433650 '';
434651 };
435652436436- statistics = mkOption {
437437- type = types.nullOr types.int;
438438- default = null;
653653+ interfaces = mkOption {
654654+ type = types.listOf types.str;
655655+ default = [ "127.0.0.1" "::1" ];
439656 description = ''
440440- Statistics are produced every number of seconds. Prints to log.
441441- If null no statistics are logged.
657657+ Which interfaces NSD should bind to for remote control.
442658 '';
443659 };
444660445445- xfrdReloadTimeout = mkOption {
446446- type = types.int;
447447- default = 1;
661661+ port = mkOption {
662662+ type = types.int;
663663+ default = 8952;
448664 description = ''
449449- Number of seconds between reloads triggered by xfrd.
665665+ Port number for remote control operations (uses TLS over TCP).
450666 '';
451667 };
452668453453- zonefilesCheck = mkOption {
454454- type = types.bool;
455455- default = true;
669669+ serverCertFile = mkOption {
670670+ type = types.path;
671671+ default = "/etc/nsd/nsd_server.pem";
456672 description = ''
457457- Wheter to check mtime of all zone files on start and sighup.
673673+ Path to the server self signed certificate, which is used by the server
674674+ but and by nsd-control. This file is generated by nsd-control-setup.
458675 '';
459676 };
460677461461-462462- extraConfig = mkOption {
463463- type = types.str;
464464- default = "";
678678+ serverKeyFile = mkOption {
679679+ type = types.path;
680680+ default = "/etc/nsd/nsd_server.key";
465681 description = ''
466466- Extra nsd config.
682682+ Path to the server private key, which is used by the server
683683+ but not by nsd-control. This file is generated by nsd-control-setup.
467684 '';
468685 };
469686470470-471471- ratelimit = {
472472- enable = mkEnableOption "ratelimit capabilities";
473473-474474- size = mkOption {
475475- type = types.int;
476476- default = 1000000;
477477- description = ''
478478- Size of the hashtable. More buckets use more memory but lower
479479- the chance of hash hash collisions.
480480- '';
481481- };
482482-483483- ratelimit = mkOption {
484484- type = types.int;
485485- default = 200;
486486- description = ''
487487- Max qps allowed from any query source.
488488- 0 means unlimited. With an verbosity of 2 blocked and
489489- unblocked subnets will be logged.
490490- '';
491491- };
492492-493493- whitelistRatelimit = mkOption {
494494- type = types.int;
495495- default = 2000;
496496- description = ''
497497- Max qps allowed from whitelisted sources.
498498- 0 means unlimited. Set the rrl-whitelist option for specific
499499- queries to apply this limit instead of the default to them.
500500- '';
501501- };
502502-503503- slip = mkOption {
504504- type = types.nullOr types.int;
505505- default = null;
506506- description = ''
507507- Number of packets that get discarded before replying a SLIP response.
508508- 0 disables SLIP responses. 1 will make every response a SLIP response.
509509- '';
510510- };
511511-512512- ipv4PrefixLength = mkOption {
513513- type = types.nullOr types.int;
514514- default = null;
515515- description = ''
516516- IPv4 prefix length. Addresses are grouped by netblock.
517517- '';
518518- };
519519-520520- ipv6PrefixLength = mkOption {
521521- type = types.nullOr types.int;
522522- default = null;
523523- description = ''
524524- IPv6 prefix length. Addresses are grouped by netblock.
525525- '';
526526- };
527527- };
528528-529529-530530- remoteControl = {
531531- enable = mkEnableOption "remote control via nsd-control";
532532-533533- interfaces = mkOption {
534534- type = types.listOf types.str;
535535- default = [ "127.0.0.1" "::1" ];
536536- description = ''
537537- Which interfaces NSD should bind to for remote control.
538538- '';
539539- };
540540-541541- port = mkOption {
542542- type = types.int;
543543- default = 8952;
544544- description = ''
545545- Port number for remote control operations (uses TLS over TCP).
546546- '';
547547- };
548548-549549- serverKeyFile = mkOption {
550550- type = types.path;
551551- default = "/etc/nsd/nsd_server.key";
552552- description = ''
553553- Path to the server private key, which is used by the server
554554- but not by nsd-control. This file is generated by nsd-control-setup.
555555- '';
556556- };
557557-558558- serverCertFile = mkOption {
559559- type = types.path;
560560- default = "/etc/nsd/nsd_server.pem";
561561- description = ''
562562- Path to the server self signed certificate, which is used by the server
563563- but and by nsd-control. This file is generated by nsd-control-setup.
564564- '';
565565- };
566566-567567- controlKeyFile = mkOption {
568568- type = types.path;
569569- default = "/etc/nsd/nsd_control.key";
570570- description = ''
571571- Path to the client private key, which is used by nsd-control
572572- but not by the server. This file is generated by nsd-control-setup.
573573- '';
574574- };
575575-576576- controlCertFile = mkOption {
577577- type = types.path;
578578- default = "/etc/nsd/nsd_control.pem";
579579- description = ''
580580- Path to the client certificate signed with the server certificate.
581581- This file is used by nsd-control and generated by nsd-control-setup.
582582- '';
583583- };
584584- };
687687+ };
585688586689587587- keys = mkOption {
588588- type = types.attrsOf (types.submodule {
589589- options = {
590590- algorithm = mkOption {
591591- type = types.str;
592592- default = "hmac-sha256";
593593- description = ''
594594- Authentication algorithm for this key.
595595- '';
690690+ zones = mkOption {
691691+ type = types.attrsOf zoneOptions;
692692+ default = {};
693693+ example = literalExample ''
694694+ { "serverGroup1" = {
695695+ provideXFR = [ "10.1.2.3 NOKEY" ];
696696+ children = {
697697+ "example.com." = {
698698+ data = '''
699699+ $ORIGIN example.com.
700700+ $TTL 86400
701701+ @ IN SOA a.ns.example.com. admin.example.com. (
702702+ ...
703703+ ''';
704704+ };
705705+ "example.org." = {
706706+ data = '''
707707+ $ORIGIN example.org.
708708+ $TTL 86400
709709+ @ IN SOA a.ns.example.com. admin.example.com. (
710710+ ...
711711+ ''';
712712+ };
596713 };
714714+ };
597715598598- keyFile = mkOption {
599599- type = types.path;
600600- description = ''
601601- Path to the file which contains the actual base64 encoded
602602- key. The key will be copied into "${stateDir}/private" before
603603- NSD starts. The copied file is only accessibly by the NSD
604604- user.
605605- '';
606606- };
607607- };
608608- });
609609- default = {};
610610- example = {
611611- "tsig.example.org" = {
612612- algorithm = "hmac-md5";
613613- secret = "aaaaaabbbbbbccccccdddddd";
716716+ "example.net." = {
717717+ provideXFR = [ "10.3.2.1 NOKEY" ];
718718+ data = '''
719719+ ...
720720+ ''';
614721 };
615722 };
616616- description = ''
617617- Define your TSIG keys here.
618618- '';
619619- };
723723+ '';
724724+ description = ''
725725+ Define your zones here. Zones can cascade other zones and therefore
726726+ inherit settings from parent zones. Look at the definition of
727727+ children to learn about inheritance and child zones.
728728+ The given example will define 3 zones (example.(com|org|net).). Both
729729+ example.com. and example.org. inherit their configuration from
730730+ serverGroup1.
731731+ '';
732732+ };
620733621621- zones = mkOption {
622622- type = types.attrsOf zoneOptions;
623623- default = {};
624624- example = literalExample ''
625625- { "serverGroup1" = {
626626- provideXFR = [ "10.1.2.3 NOKEY" ];
627627- children = {
628628- "example.com." = {
629629- data = '''
630630- $ORIGIN example.com.
631631- $TTL 86400
632632- @ IN SOA a.ns.example.com. admin.example.com. (
633633- ...
634634- ''';
635635- };
636636- "example.org." = {
637637- data = '''
638638- $ORIGIN example.org.
639639- $TTL 86400
640640- @ IN SOA a.ns.example.com. admin.example.com. (
641641- ...
642642- ''';
643643- };
644644- };
645645- };
646646-647647- "example.net." = {
648648- provideXFR = [ "10.3.2.1 NOKEY" ];
649649- data = '''
650650- ...
651651- ''';
652652- };
653653- }
654654- '';
655655- description = ''
656656- Define your zones here. Zones can cascade other zones and therefore
657657- inherit settings from parent zones. Look at the definition of
658658- children to learn about inheritance and child zones.
659659- The given example will define 3 zones (example.(com|org|net).). Both
660660- example.com. and example.org. inherit their configuration from
661661- serverGroup1.
662662- '';
663663- };
664664-665665- };
666734 };
667735668736 config = mkIf cfg.enable {
669737670738 users.extraGroups = singleton {
671739 name = username;
672672- gid = config.ids.gids.nsd;
740740+ gid = config.ids.gids.nsd;
673741 };
674742675743 users.extraUsers = singleton {
676676- name = username;
744744+ name = username;
677745 description = "NSD service user";
678678- home = stateDir;
746746+ home = stateDir;
679747 createHome = true;
680680- uid = config.ids.uids.nsd;
681681- group = username;
748748+ uid = config.ids.uids.nsd;
749749+ group = username;
682750 };
683751684752 systemd.services.nsd = {
685753 description = "NSD authoritative only domain name service";
686686- wantedBy = [ "multi-user.target" ];
687687- after = [ "network.target" ];
754754+755755+ after = [ "keys.target" "network.target" ];
756756+ wantedBy = [ "multi-user.target" ];
757757+ wants = [ "keys.target" ];
688758689759 serviceConfig = {
690690- PIDFile = pidFile;
691691- Restart = "always";
692692- ExecStart = "${nsdPkg}/sbin/nsd -d -c ${configFile}";
760760+ ExecStart = "${nsdPkg}/sbin/nsd -d -c ${nsdEnv}/nsd.conf";
761761+ PIDFile = pidFile;
762762+ Restart = "always";
763763+ RestartSec = "4s";
764764+ StartLimitBurst = 4;
765765+ StartLimitInterval = "5min";
693766 };
694767695768 preStart = ''
696696- ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/private"
697697- ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/tmp"
698698- ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/var"
769769+ rm -Rf "${stateDir}/private/"
770770+ rm -Rf "${stateDir}/tmp/"
699771700700- ${pkgs.coreutils}/bin/touch "${stateDir}/don't touch anything in here"
772772+ mkdir -m 0700 -p "${stateDir}/private"
773773+ mkdir -m 0700 -p "${stateDir}/tmp"
774774+ mkdir -m 0700 -p "${stateDir}/var"
701775702702- ${pkgs.coreutils}/bin/rm -f "${stateDir}/private/"*
703703- ${pkgs.coreutils}/bin/rm -f "${stateDir}/tmp/"*
776776+ cat > "${stateDir}/don't touch anything in here" << EOF
777777+ Everything in this directory except NSD's state in var is
778778+ automatically generated and will be purged and redeployed
779779+ by the nsd.service pre-start script.
780780+ EOF
704781705705- ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/private"
706706- ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/tmp"
707707- ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/var"
782782+ chown ${username}:${username} -R "${stateDir}/private"
783783+ chown ${username}:${username} -R "${stateDir}/tmp"
784784+ chown ${username}:${username} -R "${stateDir}/var"
708785709709- ${pkgs.coreutils}/bin/rm -rf "${stateDir}/zones"
710710- ${pkgs.coreutils}/bin/cp -r "${zoneFiles}" "${stateDir}/zones"
786786+ rm -rf "${stateDir}/zones"
787787+ cp -rL "${nsdEnv}/zones" "${stateDir}/zones"
711788712789 ${copyKeys}
713790 '';