diff --git a/nixos/doc/manual/release-notes/rl-unstable.xml b/nixos/doc/manual/release-notes/rl-unstable.xml
index ddbd80a8a00d..5c2938794b95 100644
--- a/nixos/doc/manual/release-notes/rl-unstable.xml
+++ b/nixos/doc/manual/release-notes/rl-unstable.xml
@@ -226,6 +226,27 @@ programs.ibus.plugins = with pkgs; [ ibus-anthy mozc ];
was removed. Please review the currently available options.
+
+
+ The option no
+ longer interpret the dollar sign ($) as a shell variable, as such it
+ should not be escaped anymore. Thus the following zone data:
+
+
+\$ORIGIN example.com.
+\$TTL 1800
+@ IN SOA ns1.vpn.nbp.name. admin.example.com. (
+
+
+ Should modified to look like the actual file expected by nsd:
+
+
+$ORIGIN example.com.
+$TTL 1800
+@ IN SOA ns1.vpn.nbp.name. admin.example.com. (
+
+
+
diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix
index 10566310041e..b3f2730e672f 100644
--- a/nixos/modules/services/networking/nsd.nix
+++ b/nixos/modules/services/networking/nsd.nix
@@ -7,92 +7,118 @@ let
username = "nsd";
stateDir = "/var/lib/nsd";
- pidFile = stateDir + "/var/nsd.pid";
+ pidFile = stateDir + "/var/nsd.pid";
+ # build nsd with the options needed for the given config
nsdPkg = pkgs.nsd.override {
bind8Stats = cfg.bind8Stats;
- ipv6 = cfg.ipv6;
- ratelimit = cfg.ratelimit.enable;
+ ipv6 = cfg.ipv6;
+ ratelimit = cfg.ratelimit.enable;
rootServer = cfg.rootServer;
- zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0;
+ zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0;
};
- zoneFiles = pkgs.stdenv.mkDerivation {
- preferLocalBuild = true;
+
+ nsdEnv = pkgs.buildEnv {
name = "nsd-env";
- buildCommand = concatStringsSep "\n"
- [ "mkdir -p $out"
- (concatStrings (mapAttrsToList (zoneName: zoneOptions: ''
- cat > "$out/${zoneName}" <<_EOF_
- ${zoneOptions.data}
- _EOF_
- '') zoneConfigs))
- ];
+
+ paths = [ configFile ]
+ ++ mapAttrsToList (name: zone: writeZoneData name zone.data) zoneConfigs;
+
+ postBuild = ''
+ echo "checking zone files"
+ cd $out/zones
+
+ for zoneFile in *; do
+ ${nsdPkg}/sbin/nsd-checkzone "$zoneFile" "$zoneFile" || {
+ if grep -q \\\\\\$ "$zoneFile"; then
+ echo zone "$zoneFile" contains escaped dollar signes \\\$
+ echo Escaping them is not needed any more. Please make shure \
+ to unescape them where they prefix a variable name
+ fi
+
+ exit 1
+ }
+ done
+
+ echo "checking configuration file"
+ ${nsdPkg}/sbin/nsd-checkconf $out/nsd.conf
+ '';
};
- configFile = pkgs.writeText "nsd.conf" ''
+ writeZoneData = name: text: pkgs.writeTextFile {
+ inherit name text;
+ destination = "/zones/${name}";
+ };
+
+
+ # options are ordered alphanumerically by the nixos option name
+ configFile = pkgs.writeTextDir "nsd.conf" ''
server:
- username: ${username}
chroot: "${stateDir}"
+ username: ${username}
# The directory for zonefile: files. The daemon chdirs here.
zonesdir: "${stateDir}"
# the list of dynamically added zones.
- zonelistfile: "${stateDir}/var/zone.list"
database: "${stateDir}/var/nsd.db"
pidfile: "${pidFile}"
xfrdfile: "${stateDir}/var/xfrd.state"
xfrdir: "${stateDir}/tmp"
+ zonelistfile: "${stateDir}/var/zone.list"
# interfaces
${forEach " ip-address: " cfg.interfaces}
- server-count: ${toString cfg.serverCount}
- ip-transparent: ${yesOrNo cfg.ipTransparent}
- do-ip4: ${yesOrNo cfg.ipv4}
- do-ip6: ${yesOrNo cfg.ipv6}
- port: ${toString cfg.port}
- verbosity: ${toString cfg.verbosity}
hide-version: ${yesOrNo cfg.hideVersion}
identity: "${cfg.identity}"
+ ip-transparent: ${yesOrNo cfg.ipTransparent}
+ do-ip4: ${yesOrNo cfg.ipv4}
+ ipv4-edns-size: ${toString cfg.ipv4EDNSSize}
+ do-ip6: ${yesOrNo cfg.ipv6}
+ ipv6-edns-size: ${toString cfg.ipv6EDNSSize}
+ log-time-ascii: ${yesOrNo cfg.logTimeAscii}
${maybeString "nsid: " cfg.nsid}
+ port: ${toString cfg.port}
+ reuseport: ${yesOrNo cfg.reuseport}
+ round-robin: ${yesOrNo cfg.roundRobin}
+ server-count: ${toString cfg.serverCount}
+ ${if cfg.statistics == null then "" else "statistics: ${toString cfg.statistics}"}
tcp-count: ${toString cfg.tcpCount}
tcp-query-count: ${toString cfg.tcpQueryCount}
tcp-timeout: ${toString cfg.tcpTimeout}
- ipv4-edns-size: ${toString cfg.ipv4EDNSSize}
- ipv6-edns-size: ${toString cfg.ipv6EDNSSize}
- ${if cfg.statistics == null then "" else "statistics: ${toString cfg.statistics}"}
+ verbosity: ${toString cfg.verbosity}
+ ${maybeString "version: " cfg.version}
xfrd-reload-timeout: ${toString cfg.xfrdReloadTimeout}
zonefiles-check: ${yesOrNo cfg.zonefilesCheck}
- rrl-size: ${toString cfg.ratelimit.size}
- rrl-ratelimit: ${toString cfg.ratelimit.ratelimit}
- rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit}
- ${maybeString "rrl-slip: " cfg.ratelimit.slip}
${maybeString "rrl-ipv4-prefix-length: " cfg.ratelimit.ipv4PrefixLength}
${maybeString "rrl-ipv6-prefix-length: " cfg.ratelimit.ipv6PrefixLength}
+ rrl-ratelimit: ${toString cfg.ratelimit.ratelimit}
+ ${maybeString "rrl-slip: " cfg.ratelimit.slip}
+ rrl-size: ${toString cfg.ratelimit.size}
+ rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit}
${keyConfigFile}
remote-control:
control-enable: ${yesOrNo cfg.remoteControl.enable}
- ${forEach " control-interface: " cfg.remoteControl.interfaces}
- control-port: ${toString cfg.port}
- server-key-file: "${cfg.remoteControl.serverKeyFile}"
- server-cert-file: "${cfg.remoteControl.serverCertFile}"
control-key-file: "${cfg.remoteControl.controlKeyFile}"
control-cert-file: "${cfg.remoteControl.controlCertFile}"
+ ${forEach " control-interface: " cfg.remoteControl.interfaces}
+ control-port: ${toString cfg.remoteControl.port}
+ server-key-file: "${cfg.remoteControl.serverKeyFile}"
+ server-cert-file: "${cfg.remoteControl.serverCertFile}"
- # zone files reside in "${zoneFiles}" linked to "${stateDir}/zones"
${concatStrings (mapAttrsToList zoneConfigFile zoneConfigs)}
${cfg.extraConfig}
'';
- yesOrNo = b: if b then "yes" else "no";
+ yesOrNo = b: if b then "yes" else "no";
maybeString = pre: s: if s == null then "" else ''${pre} "${s}"'';
- forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
+ forEach = pre: l: concatMapStrings (x: pre + x + "\n") l;
keyConfigFile = concatStrings (mapAttrsToList (keyName: keyOptions: ''
@@ -106,22 +132,23 @@ let
secret=$(cat "${keyOptions.keyFile}")
dest="${stateDir}/private/${keyName}"
echo " secret: \"$secret\"" > "$dest"
- ${pkgs.coreutils}/bin/chown ${username}:${username} "$dest"
- ${pkgs.coreutils}/bin/chmod 0400 "$dest"
+ chown ${username}:${username} "$dest"
+ chmod 0400 "$dest"
'') cfg.keys);
+ # options are ordered alphanumerically by the nixos option name
zoneConfigFile = name: zone: ''
zone:
name: "${name}"
zonefile: "${stateDir}/zones/${name}"
- ${maybeString "zonestats: " zone.zoneStats}
${maybeString "outgoing-interface: " zone.outgoingInterface}
${forEach " rrl-whitelist: " zone.rrlWhitelist}
+ ${maybeString "zonestats: " zone.zoneStats}
+ allow-axfr-fallback: ${yesOrNo zone.allowAXFRFallback}
${forEach " allow-notify: " zone.allowNotify}
${forEach " request-xfr: " zone.requestXFR}
- allow-axfr-fallback: ${yesOrNo zone.allowAXFRFallback}
${forEach " notify: " zone.notify}
notify-retry: ${toString zone.notifyRetry}
@@ -142,7 +169,7 @@ let
);
# fighting infinite recursion
- zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true;
+ zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true;
zoneOptions1 = zoneOptionsRaw // childConfig zoneOptions2 false;
zoneOptions2 = zoneOptionsRaw // childConfig zoneOptions3 false;
zoneOptions3 = zoneOptionsRaw // childConfig zoneOptions4 false;
@@ -152,26 +179,25 @@ let
childConfig = x: v: { options.children = { type = types.attrsOf x; visible = v; }; };
+ # options are ordered alphanumerically
zoneOptionsRaw = types.submodule {
options = {
- children = mkOption {
- default = {};
+
+ allowAXFRFallback = mkOption {
+ type = types.bool;
+ default = true;
description = ''
- Children zones inherit all options of their parents. Attributes
- defined in a child will overwrite the ones of its parent. Only
- leaf zones will be actually served. This way it's possible to
- define maybe zones which share most attributes without
- duplicating everything. This mechanism replaces nsd's patterns
- in a save and functional way.
+ If NSD as secondary server should be allowed to AXFR if the primary
+ server does not allow IXFR.
'';
};
allowNotify = mkOption {
- type = types.listOf types.str;
- default = [ ];
- example = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name"
- "10.0.3.4&255.255.0.0 BLOCKED"
- ];
+ type = types.listOf types.str;
+ default = [ ];
+ example = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name"
+ "10.0.3.4&255.255.0.0 BLOCKED"
+ ];
description = ''
Listed primary servers are allowed to notify this secondary server.
[AXFR|UDP] <ip-address> <key-name | NOKEY>
+ Children zones inherit all options of their parents. Attributes
+ defined in a child will overwrite the ones of its parent. Only
+ leaf zones will be actually served. This way it's possible to
+ define maybe zones which share most attributes without
+ duplicating everything. This mechanism replaces nsd's patterns
+ in a save and functional way.
'';
};
- allowAXFRFallback = mkOption {
- type = types.bool;
- default = true;
+ data = mkOption {
+ type = types.str;
+ default = "";
+ example = "";
description = ''
- If NSD as secondary server should be allowed to AXFR if the primary
- server does not allow IXFR.
+ The actual zone data. This is the content of your zone file.
+ Use imports or pkgs.lib.readFile if you don't want this data in your config file.
'';
};
notify = mkOption {
- type = types.listOf types.str;
- default = [];
- example = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ];
+ type = types.listOf types.str;
+ default = [];
+ example = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ];
description = ''
This primary server will notify all given secondary servers about
zone changes.
@@ -231,27 +261,17 @@ let
};
notifyRetry = mkOption {
- type = types.int;
- default = 5;
+ type = types.int;
+ default = 5;
description = ''
Specifies the number of retries for failed notifies. Set this along with notify.
'';
};
- provideXFR = mkOption {
- type = types.listOf types.str;
- default = [];
- example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ];
- description = ''
- Allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED
- address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40
- '';
- };
-
outgoingInterface = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "2000::1@1234";
+ type = types.nullOr types.str;
+ default = null;
+ example = "2000::1@1234";
description = ''
This address will be used for zone-transfere requests if configured
as a secondary server or notifications in case of a primary server.
@@ -260,9 +280,28 @@ let
'';
};
+ provideXFR = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ];
+ description = ''
+ Allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED
+ address range 192.0.2.0/24, 1.2.3.4&255.255.0.0, 3.0.2.20-3.0.2.40
+ '';
+ };
+
+ requestXFR = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [];
+ description = ''
+ Format: [AXFR|UDP] <ip-address> <key-name | NOKEY>
+ '';
+ };
+
rrlWhitelist = mkOption {
- type = types.listOf types.str;
- default = [];
+ type = types.listOf types.str;
+ default = [];
description = ''
Whitelists the given rrl-types.
The RRL classification types are: nxdomain, error, referral, any,
@@ -270,20 +309,10 @@ let
'';
};
- data = mkOption {
- type = types.str;
- default = "";
- example = "";
- description = ''
- The actual zone data. This is the content of your zone file.
- Use imports or pkgs.lib.readFile if you don't want this data in your config file.
- '';
- };
-
zoneStats = mkOption {
- type = types.nullOr types.str;
- default = null;
- example = "%s";
+ type = types.nullOr types.str;
+ default = null;
+ example = "%s";
description = ''
When set to something distinct to null NSD is able to collect
statistics per zone. All statistics of this zone(s) will be added
@@ -292,422 +321,470 @@ let
and stats_noreset.
'';
};
+
};
};
in
{
- options = {
- services.nsd = {
+ # options are ordered alphanumerically
+ options.services.nsd = {
- enable = mkEnableOption "NSD authoritative DNS server";
- bind8Stats = mkEnableOption "BIND8 like statistics";
+ enable = mkEnableOption "NSD authoritative DNS server";
- rootServer = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Wheter if this server will be a root server (a DNS root server, you
- usually don't want that).
- '';
- };
+ bind8Stats = mkEnableOption "BIND8 like statistics";
- interfaces = mkOption {
- type = types.listOf types.str;
- default = [ "127.0.0.0" "::1" ];
- description = ''
- What addresses the server should listen to.
- '';
- };
+ extraConfig = mkOption {
+ type = types.str;
+ default = "";
+ description = ''
+ Extra nsd config.
+ '';
+ };
- serverCount = mkOption {
- type = types.int;
- default = 1;
- description = ''
- Number of NSD servers to fork. Put the number of CPUs to use here.
- '';
- };
+ hideVersion = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Wheter NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries.
+ '';
+ };
- ipTransparent = mkOption {
- type = types.bool;
- default = false;
- description = ''
- Allow binding to non local addresses.
- '';
- };
+ identity = mkOption {
+ type = types.str;
+ default = "unidentified server";
+ description = ''
+ Identify the server (CH TXT ID.SERVER entry).
+ '';
+ };
- ipv4 = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Wheter to listen on IPv4 connections.
- '';
- };
+ interfaces = mkOption {
+ type = types.listOf types.str;
+ default = [ "127.0.0.0" "::1" ];
+ description = ''
+ What addresses the server should listen to.
+ '';
+ };
- ipv6 = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Wheter to listen on IPv6 connections.
- '';
- };
+ ipTransparent = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Allow binding to non local addresses.
+ '';
+ };
- port = mkOption {
- type = types.int;
- default = 53;
- description = ''
- Port the service should bind do.
- '';
- };
+ ipv4 = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Wheter to listen on IPv4 connections.
+ '';
+ };
- verbosity = mkOption {
- type = types.int;
- default = 0;
- description = ''
- Verbosity level.
- '';
- };
+ ipv4EDNSSize = mkOption {
+ type = types.int;
+ default = 4096;
+ description = ''
+ Preferred EDNS buffer size for IPv4.
+ '';
+ };
- hideVersion = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Wheter NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries.
- '';
- };
+ ipv6 = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Wheter to listen on IPv6 connections.
+ '';
+ };
- identity = mkOption {
- type = types.str;
- default = "unidentified server";
- description = ''
- Identify the server (CH TXT ID.SERVER entry).
- '';
- };
+ ipv6EDNSSize = mkOption {
+ type = types.int;
+ default = 4096;
+ description = ''
+ Preferred EDNS buffer size for IPv6.
+ '';
+ };
- nsid = mkOption {
- type = types.nullOr types.str;
- default = null;
- description = ''
- NSID identity (hex string, or "ascii_somestring").
- '';
- };
+ logTimeAscii = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Log time in ascii, if false then in unix epoch seconds.
+ '';
+ };
- tcpCount = mkOption {
- type = types.int;
- default = 100;
- description = ''
- Maximum number of concurrent TCP connections per server.
- '';
- };
+ nsid = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ NSID identity (hex string, or "ascii_somestring").
+ '';
+ };
- tcpQueryCount = mkOption {
- type = types.int;
- default = 0;
- description = ''
- Maximum number of queries served on a single TCP connection.
- 0 means no maximum.
- '';
- };
+ port = mkOption {
+ type = types.int;
+ default = 53;
+ description = ''
+ Port the service should bind do.
+ '';
+ };
- tcpTimeout = mkOption {
- type = types.int;
- default = 120;
- description = ''
- TCP timeout in seconds.
- '';
- };
+ reuseport = mkOption {
+ type = types.bool;
+ default = pkgs.stdenv.isLinux;
+ description = ''
+ Wheter to enable SO_REUSEPORT on all used sockets. This lets multiple
+ processes bind to the same port. This speeds up operation especially
+ if the server count is greater than one and makes fast restarts less
+ prone to fail
+ '';
+ };
- ipv4EDNSSize = mkOption {
- type = types.int;
- default = 4096;
- description = ''
- Preferred EDNS buffer size for IPv4.
- '';
- };
+ rootServer = mkOption {
+ type = types.bool;
+ default = false;
+ description = ''
+ Wheter if this server will be a root server (a DNS root server, you
+ usually don't want that).
+ '';
+ };
- ipv6EDNSSize = mkOption {
- type = types.int;
- default = 4096;
- description = ''
- Preferred EDNS buffer size for IPv6.
- '';
- };
+ roundRobin = mkEnableOption "round robin rotation of records";
- statistics = mkOption {
- type = types.nullOr types.int;
- default = null;
- description = ''
- Statistics are produced every number of seconds. Prints to log.
- If null no statistics are logged.
- '';
- };
+ serverCount = mkOption {
+ type = types.int;
+ default = 1;
+ description = ''
+ Number of NSD servers to fork. Put the number of CPUs to use here.
+ '';
+ };
- xfrdReloadTimeout = mkOption {
- type = types.int;
- default = 1;
- description = ''
- Number of seconds between reloads triggered by xfrd.
- '';
- };
+ statistics = mkOption {
+ type = types.nullOr types.int;
+ default = null;
+ description = ''
+ Statistics are produced every number of seconds. Prints to log.
+ If null no statistics are logged.
+ '';
+ };
- zonefilesCheck = mkOption {
- type = types.bool;
- default = true;
- description = ''
- Wheter to check mtime of all zone files on start and sighup.
- '';
- };
+ tcpCount = mkOption {
+ type = types.int;
+ default = 100;
+ description = ''
+ Maximum number of concurrent TCP connections per server.
+ '';
+ };
+
+ tcpQueryCount = mkOption {
+ type = types.int;
+ default = 0;
+ description = ''
+ Maximum number of queries served on a single TCP connection.
+ 0 means no maximum.
+ '';
+ };
+
+ tcpTimeout = mkOption {
+ type = types.int;
+ default = 120;
+ description = ''
+ TCP timeout in seconds.
+ '';
+ };
+
+ verbosity = mkOption {
+ type = types.int;
+ default = 0;
+ description = ''
+ Verbosity level.
+ '';
+ };
+
+ version = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = ''
+ The version string replied for CH TXT version.server and version.bind
+ queries. Will use the compiled package version on null.
+ See hideVersion for enabling/disabling this responses.
+ '';
+ };
+
+ xfrdReloadTimeout = mkOption {
+ type = types.int;
+ default = 1;
+ description = ''
+ Number of seconds between reloads triggered by xfrd.
+ '';
+ };
+
+ zonefilesCheck = mkOption {
+ type = types.bool;
+ default = true;
+ description = ''
+ Wheter to check mtime of all zone files on start and sighup.
+ '';
+ };
- extraConfig = mkOption {
- type = types.str;
- default = "";
- description = ''
- Extra nsd config.
- '';
- };
+ keys = mkOption {
+ type = types.attrsOf (types.submodule {
+ options = {
-
- ratelimit = {
- enable = mkEnableOption "ratelimit capabilities";
-
- size = mkOption {
- type = types.int;
- default = 1000000;
- description = ''
- Size of the hashtable. More buckets use more memory but lower
- the chance of hash hash collisions.
- '';
- };
-
- ratelimit = mkOption {
- type = types.int;
- default = 200;
- description = ''
- Max qps allowed from any query source.
- 0 means unlimited. With an verbosity of 2 blocked and
- unblocked subnets will be logged.
- '';
- };
-
- whitelistRatelimit = mkOption {
- type = types.int;
- default = 2000;
- description = ''
- Max qps allowed from whitelisted sources.
- 0 means unlimited. Set the rrl-whitelist option for specific
- queries to apply this limit instead of the default to them.
- '';
- };
-
- slip = mkOption {
- type = types.nullOr types.int;
- default = null;
- description = ''
- Number of packets that get discarded before replying a SLIP response.
- 0 disables SLIP responses. 1 will make every response a SLIP response.
- '';
- };
-
- ipv4PrefixLength = mkOption {
- type = types.nullOr types.int;
- default = null;
- description = ''
- IPv4 prefix length. Addresses are grouped by netblock.
- '';
- };
-
- ipv6PrefixLength = mkOption {
- type = types.nullOr types.int;
- default = null;
- description = ''
- IPv6 prefix length. Addresses are grouped by netblock.
- '';
- };
- };
-
-
- remoteControl = {
- enable = mkEnableOption "remote control via nsd-control";
-
- interfaces = mkOption {
- type = types.listOf types.str;
- default = [ "127.0.0.1" "::1" ];
- description = ''
- Which interfaces NSD should bind to for remote control.
- '';
- };
-
- port = mkOption {
- type = types.int;
- default = 8952;
- description = ''
- Port number for remote control operations (uses TLS over TCP).
- '';
- };
-
- serverKeyFile = mkOption {
- type = types.path;
- default = "/etc/nsd/nsd_server.key";
- description = ''
- Path to the server private key, which is used by the server
- but not by nsd-control. This file is generated by nsd-control-setup.
- '';
- };
-
- serverCertFile = mkOption {
- type = types.path;
- default = "/etc/nsd/nsd_server.pem";
- description = ''
- Path to the server self signed certificate, which is used by the server
- but and by nsd-control. This file is generated by nsd-control-setup.
- '';
- };
-
- controlKeyFile = mkOption {
- type = types.path;
- default = "/etc/nsd/nsd_control.key";
- description = ''
- Path to the client private key, which is used by nsd-control
- but not by the server. This file is generated by nsd-control-setup.
- '';
- };
-
- controlCertFile = mkOption {
- type = types.path;
- default = "/etc/nsd/nsd_control.pem";
- description = ''
- Path to the client certificate signed with the server certificate.
- This file is used by nsd-control and generated by nsd-control-setup.
- '';
- };
- };
-
-
- keys = mkOption {
- type = types.attrsOf (types.submodule {
- options = {
- algorithm = mkOption {
- type = types.str;
- default = "hmac-sha256";
- description = ''
- Authentication algorithm for this key.
- '';
- };
-
- keyFile = mkOption {
- type = types.path;
- description = ''
- Path to the file which contains the actual base64 encoded
- key. The key will be copied into "${stateDir}/private" before
- NSD starts. The copied file is only accessibly by the NSD
- user.
- '';
- };
+ algorithm = mkOption {
+ type = types.str;
+ default = "hmac-sha256";
+ description = ''
+ Authentication algorithm for this key.
+ '';
};
- });
- default = {};
- example = {
- "tsig.example.org" = {
+
+ keyFile = mkOption {
+ type = types.path;
+ description = ''
+ Path to the file which contains the actual base64 encoded
+ key. The key will be copied into "${stateDir}/private" before
+ NSD starts. The copied file is only accessibly by the NSD
+ user.
+ '';
+ };
+
+ };
+ });
+ default = {};
+ example = literalExample ''
+ { "tsig.example.org" = {
algorithm = "hmac-md5";
- secret = "aaaaaabbbbbbccccccdddddd";
+ keyFile = "/path/to/my/key";
};
};
+ '';
+ description = ''
+ Define your TSIG keys here.
+ '';
+ };
+
+
+ ratelimit = {
+
+ enable = mkEnableOption "ratelimit capabilities";
+
+ ipv4PrefixLength = mkOption {
+ type = types.nullOr types.int;
+ default = null;
description = ''
- Define your TSIG keys here.
+ IPv4 prefix length. Addresses are grouped by netblock.
'';
};
- zones = mkOption {
- type = types.attrsOf zoneOptions;
- default = {};
- example = literalExample ''
- { "serverGroup1" = {
- provideXFR = [ "10.1.2.3 NOKEY" ];
- children = {
- "example.com." = {
- data = '''
- $ORIGIN example.com.
- $TTL 86400
- @ IN SOA a.ns.example.com. admin.example.com. (
- ...
- ''';
- };
- "example.org." = {
- data = '''
- $ORIGIN example.org.
- $TTL 86400
- @ IN SOA a.ns.example.com. admin.example.com. (
- ...
- ''';
- };
- };
- };
-
- "example.net." = {
- provideXFR = [ "10.3.2.1 NOKEY" ];
- data = '''
- ...
- ''';
- };
- }
- '';
+ ipv6PrefixLength = mkOption {
+ type = types.nullOr types.int;
+ default = null;
description = ''
- Define your zones here. Zones can cascade other zones and therefore
- inherit settings from parent zones. Look at the definition of
- children to learn about inheritance and child zones.
- The given example will define 3 zones (example.(com|org|net).). Both
- example.com. and example.org. inherit their configuration from
- serverGroup1.
+ IPv6 prefix length. Addresses are grouped by netblock.
+ '';
+ };
+
+ ratelimit = mkOption {
+ type = types.int;
+ default = 200;
+ description = ''
+ Max qps allowed from any query source.
+ 0 means unlimited. With an verbosity of 2 blocked and
+ unblocked subnets will be logged.
+ '';
+ };
+
+ slip = mkOption {
+ type = types.nullOr types.int;
+ default = null;
+ description = ''
+ Number of packets that get discarded before replying a SLIP response.
+ 0 disables SLIP responses. 1 will make every response a SLIP response.
+ '';
+ };
+
+ size = mkOption {
+ type = types.int;
+ default = 1000000;
+ description = ''
+ Size of the hashtable. More buckets use more memory but lower
+ the chance of hash hash collisions.
+ '';
+ };
+
+ whitelistRatelimit = mkOption {
+ type = types.int;
+ default = 2000;
+ description = ''
+ Max qps allowed from whitelisted sources.
+ 0 means unlimited. Set the rrl-whitelist option for specific
+ queries to apply this limit instead of the default to them.
'';
};
};
+
+
+ remoteControl = {
+
+ enable = mkEnableOption "remote control via nsd-control";
+
+ controlCertFile = mkOption {
+ type = types.path;
+ default = "/etc/nsd/nsd_control.pem";
+ description = ''
+ Path to the client certificate signed with the server certificate.
+ This file is used by nsd-control and generated by nsd-control-setup.
+ '';
+ };
+
+ controlKeyFile = mkOption {
+ type = types.path;
+ default = "/etc/nsd/nsd_control.key";
+ description = ''
+ Path to the client private key, which is used by nsd-control
+ but not by the server. This file is generated by nsd-control-setup.
+ '';
+ };
+
+ interfaces = mkOption {
+ type = types.listOf types.str;
+ default = [ "127.0.0.1" "::1" ];
+ description = ''
+ Which interfaces NSD should bind to for remote control.
+ '';
+ };
+
+ port = mkOption {
+ type = types.int;
+ default = 8952;
+ description = ''
+ Port number for remote control operations (uses TLS over TCP).
+ '';
+ };
+
+ serverCertFile = mkOption {
+ type = types.path;
+ default = "/etc/nsd/nsd_server.pem";
+ description = ''
+ Path to the server self signed certificate, which is used by the server
+ but and by nsd-control. This file is generated by nsd-control-setup.
+ '';
+ };
+
+ serverKeyFile = mkOption {
+ type = types.path;
+ default = "/etc/nsd/nsd_server.key";
+ description = ''
+ Path to the server private key, which is used by the server
+ but not by nsd-control. This file is generated by nsd-control-setup.
+ '';
+ };
+
+ };
+
+
+ zones = mkOption {
+ type = types.attrsOf zoneOptions;
+ default = {};
+ example = literalExample ''
+ { "serverGroup1" = {
+ provideXFR = [ "10.1.2.3 NOKEY" ];
+ children = {
+ "example.com." = {
+ data = '''
+ $ORIGIN example.com.
+ $TTL 86400
+ @ IN SOA a.ns.example.com. admin.example.com. (
+ ...
+ ''';
+ };
+ "example.org." = {
+ data = '''
+ $ORIGIN example.org.
+ $TTL 86400
+ @ IN SOA a.ns.example.com. admin.example.com. (
+ ...
+ ''';
+ };
+ };
+ };
+
+ "example.net." = {
+ provideXFR = [ "10.3.2.1 NOKEY" ];
+ data = '''
+ ...
+ ''';
+ };
+ };
+ '';
+ description = ''
+ Define your zones here. Zones can cascade other zones and therefore
+ inherit settings from parent zones. Look at the definition of
+ children to learn about inheritance and child zones.
+ The given example will define 3 zones (example.(com|org|net).). Both
+ example.com. and example.org. inherit their configuration from
+ serverGroup1.
+ '';
+ };
+
};
config = mkIf cfg.enable {
users.extraGroups = singleton {
name = username;
- gid = config.ids.gids.nsd;
+ gid = config.ids.gids.nsd;
};
users.extraUsers = singleton {
- name = username;
+ name = username;
description = "NSD service user";
- home = stateDir;
+ home = stateDir;
createHome = true;
- uid = config.ids.uids.nsd;
- group = username;
+ uid = config.ids.uids.nsd;
+ group = username;
};
systemd.services.nsd = {
description = "NSD authoritative only domain name service";
- wantedBy = [ "multi-user.target" ];
- after = [ "network.target" ];
+
+ after = [ "keys.target" "network.target" ];
+ wantedBy = [ "multi-user.target" ];
+ wants = [ "keys.target" ];
serviceConfig = {
- PIDFile = pidFile;
- Restart = "always";
- ExecStart = "${nsdPkg}/sbin/nsd -d -c ${configFile}";
+ ExecStart = "${nsdPkg}/sbin/nsd -d -c ${nsdEnv}/nsd.conf";
+ PIDFile = pidFile;
+ Restart = "always";
+ RestartSec = "4s";
+ StartLimitBurst = 4;
+ StartLimitInterval = "5min";
};
preStart = ''
- ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/private"
- ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/tmp"
- ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/var"
+ rm -Rf "${stateDir}/private/"
+ rm -Rf "${stateDir}/tmp/"
- ${pkgs.coreutils}/bin/touch "${stateDir}/don't touch anything in here"
+ mkdir -m 0700 -p "${stateDir}/private"
+ mkdir -m 0700 -p "${stateDir}/tmp"
+ mkdir -m 0700 -p "${stateDir}/var"
- ${pkgs.coreutils}/bin/rm -f "${stateDir}/private/"*
- ${pkgs.coreutils}/bin/rm -f "${stateDir}/tmp/"*
+ cat > "${stateDir}/don't touch anything in here" << EOF
+ Everything in this directory except NSD's state in var is
+ automatically generated and will be purged and redeployed
+ by the nsd.service pre-start script.
+ EOF
- ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/private"
- ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/tmp"
- ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/var"
+ chown ${username}:${username} -R "${stateDir}/private"
+ chown ${username}:${username} -R "${stateDir}/tmp"
+ chown ${username}:${username} -R "${stateDir}/var"
- ${pkgs.coreutils}/bin/rm -rf "${stateDir}/zones"
- ${pkgs.coreutils}/bin/cp -r "${zoneFiles}" "${stateDir}/zones"
+ rm -rf "${stateDir}/zones"
+ cp -rL "${nsdEnv}/zones" "${stateDir}/zones"
${copyKeys}
'';
diff --git a/pkgs/servers/dns/nsd/default.nix b/pkgs/servers/dns/nsd/default.nix
index 2bd755d03246..d11ef186c319 100644
--- a/pkgs/servers/dns/nsd/default.nix
+++ b/pkgs/servers/dns/nsd/default.nix
@@ -13,11 +13,11 @@
}:
stdenv.mkDerivation rec {
- name = "nsd-4.1.6";
+ name = "nsd-4.1.7";
src = fetchurl {
url = "http://www.nlnetlabs.nl/downloads/nsd/${name}.tar.gz";
- sha256 = "0pvpsxhil60m21h3pqlzs0l5m8qd3l6j8fkjyfg8plwmbh2j5xl8";
+ sha256 = "12hskfgfbkvcgpa1xxkqd8lnc6xvln1amn97x6avfnj9kfrbxa3v";
};
buildInputs = [ libevent openssl ];
@@ -41,7 +41,6 @@ stdenv.mkDerivation rec {
homepage = http://www.nlnetlabs.nl;
description = "Authoritative only, high performance, simple and open source name server";
license = licenses.bsd3;
-
platforms = platforms.unix;
maintainers = [ maintainers.hrdinka ];
};