Merge pull request #12487 from hrdinka/refactor/nsd

Refactor NSD service and update to 4.1.7

+516 -419
+21
nixos/doc/manual/release-notes/rl-unstable.xml
··· 226 226 was removed. Please review the currently available options.</para> 227 227 </listitem> 228 228 229 + <listitem> 230 + <para> 231 + The option <option>services.nsd.zones.&lt;name&gt;.data</option> no 232 + longer interpret the dollar sign ($) as a shell variable, as such it 233 + should not be escaped anymore. Thus the following zone data: 234 + </para> 235 + <programlisting> 236 + \$ORIGIN example.com. 237 + \$TTL 1800 238 + @ IN SOA ns1.vpn.nbp.name. admin.example.com. ( 239 + </programlisting> 240 + <para> 241 + Should modified to look like the actual file expected by nsd: 242 + </para> 243 + <programlisting> 244 + $ORIGIN example.com. 245 + $TTL 1800 246 + @ IN SOA ns1.vpn.nbp.name. admin.example.com. ( 247 + </programlisting> 248 + </listitem> 249 + 229 250 </itemizedlist> 230 251 231 252
+493 -416
nixos/modules/services/networking/nsd.nix
··· 7 7 8 8 username = "nsd"; 9 9 stateDir = "/var/lib/nsd"; 10 - pidFile = stateDir + "/var/nsd.pid"; 10 + pidFile = stateDir + "/var/nsd.pid"; 11 11 12 + # build nsd with the options needed for the given config 12 13 nsdPkg = pkgs.nsd.override { 13 14 bind8Stats = cfg.bind8Stats; 14 - ipv6 = cfg.ipv6; 15 - ratelimit = cfg.ratelimit.enable; 15 + ipv6 = cfg.ipv6; 16 + ratelimit = cfg.ratelimit.enable; 16 17 rootServer = cfg.rootServer; 17 - zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0; 18 + zoneStats = length (collect (x: (x.zoneStats or null) != null) cfg.zones) > 0; 18 19 }; 19 20 20 - zoneFiles = pkgs.stdenv.mkDerivation { 21 - preferLocalBuild = true; 21 + 22 + nsdEnv = pkgs.buildEnv { 22 23 name = "nsd-env"; 23 - buildCommand = concatStringsSep "\n" 24 - [ "mkdir -p $out" 25 - (concatStrings (mapAttrsToList (zoneName: zoneOptions: '' 26 - cat > "$out/${zoneName}" <<_EOF_ 27 - ${zoneOptions.data} 28 - _EOF_ 29 - '') zoneConfigs)) 30 - ]; 24 + 25 + paths = [ configFile ] 26 + ++ mapAttrsToList (name: zone: writeZoneData name zone.data) zoneConfigs; 27 + 28 + postBuild = '' 29 + echo "checking zone files" 30 + cd $out/zones 31 + 32 + for zoneFile in *; do 33 + ${nsdPkg}/sbin/nsd-checkzone "$zoneFile" "$zoneFile" || { 34 + if grep -q \\\\\\$ "$zoneFile"; then 35 + echo zone "$zoneFile" contains escaped dollar signes \\\$ 36 + echo Escaping them is not needed any more. Please make shure \ 37 + to unescape them where they prefix a variable name 38 + fi 39 + 40 + exit 1 41 + } 42 + done 43 + 44 + echo "checking configuration file" 45 + ${nsdPkg}/sbin/nsd-checkconf $out/nsd.conf 46 + ''; 31 47 }; 32 48 33 - configFile = pkgs.writeText "nsd.conf" '' 49 + writeZoneData = name: text: pkgs.writeTextFile { 50 + inherit name text; 51 + destination = "/zones/${name}"; 52 + }; 53 + 54 + 55 + # options are ordered alphanumerically by the nixos option name 56 + configFile = pkgs.writeTextDir "nsd.conf" '' 34 57 server: 58 + chroot: "${stateDir}" 35 59 username: ${username} 36 - chroot: "${stateDir}" 37 60 38 61 # The directory for zonefile: files. The daemon chdirs here. 39 62 zonesdir: "${stateDir}" 40 63 41 64 # the list of dynamically added zones. 42 - zonelistfile: "${stateDir}/var/zone.list" 43 65 database: "${stateDir}/var/nsd.db" 44 66 pidfile: "${pidFile}" 45 67 xfrdfile: "${stateDir}/var/xfrd.state" 46 68 xfrdir: "${stateDir}/tmp" 69 + zonelistfile: "${stateDir}/var/zone.list" 47 70 48 71 # interfaces 49 72 ${forEach " ip-address: " cfg.interfaces} 50 73 51 - server-count: ${toString cfg.serverCount} 74 + hide-version: ${yesOrNo cfg.hideVersion} 75 + identity: "${cfg.identity}" 52 76 ip-transparent: ${yesOrNo cfg.ipTransparent} 53 77 do-ip4: ${yesOrNo cfg.ipv4} 78 + ipv4-edns-size: ${toString cfg.ipv4EDNSSize} 54 79 do-ip6: ${yesOrNo cfg.ipv6} 80 + ipv6-edns-size: ${toString cfg.ipv6EDNSSize} 81 + log-time-ascii: ${yesOrNo cfg.logTimeAscii} 82 + ${maybeString "nsid: " cfg.nsid} 55 83 port: ${toString cfg.port} 56 - verbosity: ${toString cfg.verbosity} 57 - hide-version: ${yesOrNo cfg.hideVersion} 58 - identity: "${cfg.identity}" 59 - ${maybeString "nsid: " cfg.nsid} 84 + reuseport: ${yesOrNo cfg.reuseport} 85 + round-robin: ${yesOrNo cfg.roundRobin} 86 + server-count: ${toString cfg.serverCount} 87 + ${if cfg.statistics == null then "" else "statistics: ${toString cfg.statistics}"} 60 88 tcp-count: ${toString cfg.tcpCount} 61 89 tcp-query-count: ${toString cfg.tcpQueryCount} 62 90 tcp-timeout: ${toString cfg.tcpTimeout} 63 - ipv4-edns-size: ${toString cfg.ipv4EDNSSize} 64 - ipv6-edns-size: ${toString cfg.ipv6EDNSSize} 65 - ${if cfg.statistics == null then "" else "statistics: ${toString cfg.statistics}"} 91 + verbosity: ${toString cfg.verbosity} 92 + ${maybeString "version: " cfg.version} 66 93 xfrd-reload-timeout: ${toString cfg.xfrdReloadTimeout} 67 94 zonefiles-check: ${yesOrNo cfg.zonefilesCheck} 68 95 69 - rrl-size: ${toString cfg.ratelimit.size} 70 - rrl-ratelimit: ${toString cfg.ratelimit.ratelimit} 71 - rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit} 72 - ${maybeString "rrl-slip: " cfg.ratelimit.slip} 73 96 ${maybeString "rrl-ipv4-prefix-length: " cfg.ratelimit.ipv4PrefixLength} 74 97 ${maybeString "rrl-ipv6-prefix-length: " cfg.ratelimit.ipv6PrefixLength} 98 + rrl-ratelimit: ${toString cfg.ratelimit.ratelimit} 99 + ${maybeString "rrl-slip: " cfg.ratelimit.slip} 100 + rrl-size: ${toString cfg.ratelimit.size} 101 + rrl-whitelist-ratelimit: ${toString cfg.ratelimit.whitelistRatelimit} 75 102 76 103 ${keyConfigFile} 77 104 78 105 remote-control: 79 106 control-enable: ${yesOrNo cfg.remoteControl.enable} 107 + control-key-file: "${cfg.remoteControl.controlKeyFile}" 108 + control-cert-file: "${cfg.remoteControl.controlCertFile}" 80 109 ${forEach " control-interface: " cfg.remoteControl.interfaces} 81 - control-port: ${toString cfg.port} 110 + control-port: ${toString cfg.remoteControl.port} 82 111 server-key-file: "${cfg.remoteControl.serverKeyFile}" 83 112 server-cert-file: "${cfg.remoteControl.serverCertFile}" 84 - control-key-file: "${cfg.remoteControl.controlKeyFile}" 85 - control-cert-file: "${cfg.remoteControl.controlCertFile}" 86 113 87 - # zone files reside in "${zoneFiles}" linked to "${stateDir}/zones" 88 114 ${concatStrings (mapAttrsToList zoneConfigFile zoneConfigs)} 89 115 90 116 ${cfg.extraConfig} 91 117 ''; 92 118 93 - yesOrNo = b: if b then "yes" else "no"; 119 + yesOrNo = b: if b then "yes" else "no"; 94 120 maybeString = pre: s: if s == null then "" else ''${pre} "${s}"''; 95 - forEach = pre: l: concatMapStrings (x: pre + x + "\n") l; 121 + forEach = pre: l: concatMapStrings (x: pre + x + "\n") l; 96 122 97 123 98 124 keyConfigFile = concatStrings (mapAttrsToList (keyName: keyOptions: '' ··· 106 132 secret=$(cat "${keyOptions.keyFile}") 107 133 dest="${stateDir}/private/${keyName}" 108 134 echo " secret: \"$secret\"" > "$dest" 109 - ${pkgs.coreutils}/bin/chown ${username}:${username} "$dest" 110 - ${pkgs.coreutils}/bin/chmod 0400 "$dest" 135 + chown ${username}:${username} "$dest" 136 + chmod 0400 "$dest" 111 137 '') cfg.keys); 112 138 113 139 140 + # options are ordered alphanumerically by the nixos option name 114 141 zoneConfigFile = name: zone: '' 115 142 zone: 116 143 name: "${name}" 117 144 zonefile: "${stateDir}/zones/${name}" 118 - ${maybeString "zonestats: " zone.zoneStats} 119 145 ${maybeString "outgoing-interface: " zone.outgoingInterface} 120 146 ${forEach " rrl-whitelist: " zone.rrlWhitelist} 147 + ${maybeString "zonestats: " zone.zoneStats} 121 148 149 + allow-axfr-fallback: ${yesOrNo zone.allowAXFRFallback} 122 150 ${forEach " allow-notify: " zone.allowNotify} 123 151 ${forEach " request-xfr: " zone.requestXFR} 124 - allow-axfr-fallback: ${yesOrNo zone.allowAXFRFallback} 125 152 126 153 ${forEach " notify: " zone.notify} 127 154 notify-retry: ${toString zone.notifyRetry} ··· 142 169 ); 143 170 144 171 # fighting infinite recursion 145 - zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true; 172 + zoneOptions = zoneOptionsRaw // childConfig zoneOptions1 true; 146 173 zoneOptions1 = zoneOptionsRaw // childConfig zoneOptions2 false; 147 174 zoneOptions2 = zoneOptionsRaw // childConfig zoneOptions3 false; 148 175 zoneOptions3 = zoneOptionsRaw // childConfig zoneOptions4 false; ··· 152 179 153 180 childConfig = x: v: { options.children = { type = types.attrsOf x; visible = v; }; }; 154 181 182 + # options are ordered alphanumerically 155 183 zoneOptionsRaw = types.submodule { 156 184 options = { 157 - children = mkOption { 158 - default = {}; 185 + 186 + allowAXFRFallback = mkOption { 187 + type = types.bool; 188 + default = true; 159 189 description = '' 160 - Children zones inherit all options of their parents. Attributes 161 - defined in a child will overwrite the ones of its parent. Only 162 - leaf zones will be actually served. This way it's possible to 163 - define maybe zones which share most attributes without 164 - duplicating everything. This mechanism replaces nsd's patterns 165 - in a save and functional way. 190 + If NSD as secondary server should be allowed to AXFR if the primary 191 + server does not allow IXFR. 166 192 ''; 167 193 }; 168 194 169 195 allowNotify = mkOption { 170 - type = types.listOf types.str; 171 - default = [ ]; 172 - example = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name" 173 - "10.0.3.4&255.255.0.0 BLOCKED" 174 - ]; 196 + type = types.listOf types.str; 197 + default = [ ]; 198 + example = [ "192.0.2.0/24 NOKEY" "10.0.0.1-10.0.0.5 my_tsig_key_name" 199 + "10.0.3.4&255.255.0.0 BLOCKED" 200 + ]; 175 201 description = '' 176 202 Listed primary servers are allowed to notify this secondary server. 177 203 <screen><![CDATA[ ··· 193 219 ''; 194 220 }; 195 221 196 - requestXFR = mkOption { 197 - type = types.listOf types.str; 198 - default = []; 199 - example = []; 222 + children = mkOption { 223 + default = {}; 200 224 description = '' 201 - Format: <code>[AXFR|UDP] &lt;ip-address&gt; &lt;key-name | NOKEY&gt;</code> 225 + Children zones inherit all options of their parents. Attributes 226 + defined in a child will overwrite the ones of its parent. Only 227 + leaf zones will be actually served. This way it's possible to 228 + define maybe zones which share most attributes without 229 + duplicating everything. This mechanism replaces nsd's patterns 230 + in a save and functional way. 202 231 ''; 203 232 }; 204 233 205 - allowAXFRFallback = mkOption { 206 - type = types.bool; 207 - default = true; 234 + data = mkOption { 235 + type = types.str; 236 + default = ""; 237 + example = ""; 208 238 description = '' 209 - If NSD as secondary server should be allowed to AXFR if the primary 210 - server does not allow IXFR. 239 + The actual zone data. This is the content of your zone file. 240 + Use imports or pkgs.lib.readFile if you don't want this data in your config file. 211 241 ''; 212 242 }; 213 243 214 244 notify = mkOption { 215 - type = types.listOf types.str; 216 - default = []; 217 - example = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ]; 245 + type = types.listOf types.str; 246 + default = []; 247 + example = [ "10.0.0.1@3721 my_key" "::5 NOKEY" ]; 218 248 description = '' 219 249 This primary server will notify all given secondary servers about 220 250 zone changes. ··· 231 261 }; 232 262 233 263 notifyRetry = mkOption { 234 - type = types.int; 235 - default = 5; 264 + type = types.int; 265 + default = 5; 236 266 description = '' 237 267 Specifies the number of retries for failed notifies. Set this along with notify. 238 268 ''; 239 269 }; 240 270 271 + outgoingInterface = mkOption { 272 + type = types.nullOr types.str; 273 + default = null; 274 + example = "2000::1@1234"; 275 + description = '' 276 + This address will be used for zone-transfere requests if configured 277 + as a secondary server or notifications in case of a primary server. 278 + Supply either a plain IPv4 or IPv6 address with an optional port 279 + number (ip@port). 280 + ''; 281 + }; 282 + 241 283 provideXFR = mkOption { 242 - type = types.listOf types.str; 243 - default = []; 244 - example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ]; 284 + type = types.listOf types.str; 285 + default = []; 286 + example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ]; 245 287 description = '' 246 288 Allow these IPs and TSIG to transfer zones, addr TSIG|NOKEY|BLOCKED 247 289 address range 192.0.2.0/24, 1.2.3.4&amp;255.255.0.0, 3.0.2.20-3.0.2.40 248 290 ''; 249 291 }; 250 292 251 - outgoingInterface = mkOption { 252 - type = types.nullOr types.str; 253 - default = null; 254 - example = "2000::1@1234"; 293 + requestXFR = mkOption { 294 + type = types.listOf types.str; 295 + default = []; 296 + example = []; 255 297 description = '' 256 - This address will be used for zone-transfere requests if configured 257 - as a secondary server or notifications in case of a primary server. 258 - Supply either a plain IPv4 or IPv6 address with an optional port 259 - number (ip@port). 298 + Format: <code>[AXFR|UDP] &lt;ip-address&gt; &lt;key-name | NOKEY&gt;</code> 260 299 ''; 261 300 }; 262 301 263 302 rrlWhitelist = mkOption { 264 - type = types.listOf types.str; 265 - default = []; 303 + type = types.listOf types.str; 304 + default = []; 266 305 description = '' 267 306 Whitelists the given rrl-types. 268 307 The RRL classification types are: nxdomain, error, referral, any, ··· 270 309 ''; 271 310 }; 272 311 273 - data = mkOption { 274 - type = types.str; 275 - default = ""; 276 - example = ""; 277 - description = '' 278 - The actual zone data. This is the content of your zone file. 279 - Use imports or pkgs.lib.readFile if you don't want this data in your config file. 280 - ''; 281 - }; 282 - 283 312 zoneStats = mkOption { 284 - type = types.nullOr types.str; 285 - default = null; 286 - example = "%s"; 313 + type = types.nullOr types.str; 314 + default = null; 315 + example = "%s"; 287 316 description = '' 288 317 When set to something distinct to null NSD is able to collect 289 318 statistics per zone. All statistics of this zone(s) will be added ··· 292 321 and stats_noreset. 293 322 ''; 294 323 }; 324 + 295 325 }; 296 326 }; 297 327 298 328 in 299 329 { 300 - options = { 301 - services.nsd = { 330 + # options are ordered alphanumerically 331 + options.services.nsd = { 332 + 333 + enable = mkEnableOption "NSD authoritative DNS server"; 334 + 335 + bind8Stats = mkEnableOption "BIND8 like statistics"; 336 + 337 + extraConfig = mkOption { 338 + type = types.str; 339 + default = ""; 340 + description = '' 341 + Extra nsd config. 342 + ''; 343 + }; 344 + 345 + hideVersion = mkOption { 346 + type = types.bool; 347 + default = true; 348 + description = '' 349 + Wheter NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries. 350 + ''; 351 + }; 352 + 353 + identity = mkOption { 354 + type = types.str; 355 + default = "unidentified server"; 356 + description = '' 357 + Identify the server (CH TXT ID.SERVER entry). 358 + ''; 359 + }; 360 + 361 + interfaces = mkOption { 362 + type = types.listOf types.str; 363 + default = [ "127.0.0.0" "::1" ]; 364 + description = '' 365 + What addresses the server should listen to. 366 + ''; 367 + }; 368 + 369 + ipTransparent = mkOption { 370 + type = types.bool; 371 + default = false; 372 + description = '' 373 + Allow binding to non local addresses. 374 + ''; 375 + }; 376 + 377 + ipv4 = mkOption { 378 + type = types.bool; 379 + default = true; 380 + description = '' 381 + Wheter to listen on IPv4 connections. 382 + ''; 383 + }; 384 + 385 + ipv4EDNSSize = mkOption { 386 + type = types.int; 387 + default = 4096; 388 + description = '' 389 + Preferred EDNS buffer size for IPv4. 390 + ''; 391 + }; 392 + 393 + ipv6 = mkOption { 394 + type = types.bool; 395 + default = true; 396 + description = '' 397 + Wheter to listen on IPv6 connections. 398 + ''; 399 + }; 400 + 401 + ipv6EDNSSize = mkOption { 402 + type = types.int; 403 + default = 4096; 404 + description = '' 405 + Preferred EDNS buffer size for IPv6. 406 + ''; 407 + }; 408 + 409 + logTimeAscii = mkOption { 410 + type = types.bool; 411 + default = true; 412 + description = '' 413 + Log time in ascii, if false then in unix epoch seconds. 414 + ''; 415 + }; 416 + 417 + nsid = mkOption { 418 + type = types.nullOr types.str; 419 + default = null; 420 + description = '' 421 + NSID identity (hex string, or "ascii_somestring"). 422 + ''; 423 + }; 424 + 425 + port = mkOption { 426 + type = types.int; 427 + default = 53; 428 + description = '' 429 + Port the service should bind do. 430 + ''; 431 + }; 432 + 433 + reuseport = mkOption { 434 + type = types.bool; 435 + default = pkgs.stdenv.isLinux; 436 + description = '' 437 + Wheter to enable SO_REUSEPORT on all used sockets. This lets multiple 438 + processes bind to the same port. This speeds up operation especially 439 + if the server count is greater than one and makes fast restarts less 440 + prone to fail 441 + ''; 442 + }; 443 + 444 + rootServer = mkOption { 445 + type = types.bool; 446 + default = false; 447 + description = '' 448 + Wheter if this server will be a root server (a DNS root server, you 449 + usually don't want that). 450 + ''; 451 + }; 452 + 453 + roundRobin = mkEnableOption "round robin rotation of records"; 454 + 455 + serverCount = mkOption { 456 + type = types.int; 457 + default = 1; 458 + description = '' 459 + Number of NSD servers to fork. Put the number of CPUs to use here. 460 + ''; 461 + }; 462 + 463 + statistics = mkOption { 464 + type = types.nullOr types.int; 465 + default = null; 466 + description = '' 467 + Statistics are produced every number of seconds. Prints to log. 468 + If null no statistics are logged. 469 + ''; 470 + }; 471 + 472 + tcpCount = mkOption { 473 + type = types.int; 474 + default = 100; 475 + description = '' 476 + Maximum number of concurrent TCP connections per server. 477 + ''; 478 + }; 479 + 480 + tcpQueryCount = mkOption { 481 + type = types.int; 482 + default = 0; 483 + description = '' 484 + Maximum number of queries served on a single TCP connection. 485 + 0 means no maximum. 486 + ''; 487 + }; 488 + 489 + tcpTimeout = mkOption { 490 + type = types.int; 491 + default = 120; 492 + description = '' 493 + TCP timeout in seconds. 494 + ''; 495 + }; 496 + 497 + verbosity = mkOption { 498 + type = types.int; 499 + default = 0; 500 + description = '' 501 + Verbosity level. 502 + ''; 503 + }; 504 + 505 + version = mkOption { 506 + type = types.nullOr types.str; 507 + default = null; 508 + description = '' 509 + The version string replied for CH TXT version.server and version.bind 510 + queries. Will use the compiled package version on null. 511 + See hideVersion for enabling/disabling this responses. 512 + ''; 513 + }; 302 514 303 - enable = mkEnableOption "NSD authoritative DNS server"; 304 - bind8Stats = mkEnableOption "BIND8 like statistics"; 515 + xfrdReloadTimeout = mkOption { 516 + type = types.int; 517 + default = 1; 518 + description = '' 519 + Number of seconds between reloads triggered by xfrd. 520 + ''; 521 + }; 305 522 306 - rootServer = mkOption { 307 - type = types.bool; 308 - default = false; 309 - description = '' 310 - Wheter if this server will be a root server (a DNS root server, you 311 - usually don't want that). 312 - ''; 313 - }; 523 + zonefilesCheck = mkOption { 524 + type = types.bool; 525 + default = true; 526 + description = '' 527 + Wheter to check mtime of all zone files on start and sighup. 528 + ''; 529 + }; 530 + 531 + 532 + keys = mkOption { 533 + type = types.attrsOf (types.submodule { 534 + options = { 535 + 536 + algorithm = mkOption { 537 + type = types.str; 538 + default = "hmac-sha256"; 539 + description = '' 540 + Authentication algorithm for this key. 541 + ''; 542 + }; 543 + 544 + keyFile = mkOption { 545 + type = types.path; 546 + description = '' 547 + Path to the file which contains the actual base64 encoded 548 + key. The key will be copied into "${stateDir}/private" before 549 + NSD starts. The copied file is only accessibly by the NSD 550 + user. 551 + ''; 552 + }; 553 + 554 + }; 555 + }); 556 + default = {}; 557 + example = literalExample '' 558 + { "tsig.example.org" = { 559 + algorithm = "hmac-md5"; 560 + keyFile = "/path/to/my/key"; 561 + }; 562 + }; 563 + ''; 564 + description = '' 565 + Define your TSIG keys here. 566 + ''; 567 + }; 314 568 315 - interfaces = mkOption { 316 - type = types.listOf types.str; 317 - default = [ "127.0.0.0" "::1" ]; 318 - description = '' 319 - What addresses the server should listen to. 320 - ''; 321 - }; 322 569 323 - serverCount = mkOption { 324 - type = types.int; 325 - default = 1; 326 - description = '' 327 - Number of NSD servers to fork. Put the number of CPUs to use here. 328 - ''; 329 - }; 570 + ratelimit = { 330 571 331 - ipTransparent = mkOption { 332 - type = types.bool; 333 - default = false; 334 - description = '' 335 - Allow binding to non local addresses. 336 - ''; 337 - }; 572 + enable = mkEnableOption "ratelimit capabilities"; 338 573 339 - ipv4 = mkOption { 340 - type = types.bool; 341 - default = true; 574 + ipv4PrefixLength = mkOption { 575 + type = types.nullOr types.int; 576 + default = null; 342 577 description = '' 343 - Wheter to listen on IPv4 connections. 578 + IPv4 prefix length. Addresses are grouped by netblock. 344 579 ''; 345 580 }; 346 581 347 - ipv6 = mkOption { 348 - type = types.bool; 349 - default = true; 582 + ipv6PrefixLength = mkOption { 583 + type = types.nullOr types.int; 584 + default = null; 350 585 description = '' 351 - Wheter to listen on IPv6 connections. 586 + IPv6 prefix length. Addresses are grouped by netblock. 352 587 ''; 353 588 }; 354 589 355 - port = mkOption { 356 - type = types.int; 357 - default = 53; 590 + ratelimit = mkOption { 591 + type = types.int; 592 + default = 200; 358 593 description = '' 359 - Port the service should bind do. 594 + Max qps allowed from any query source. 595 + 0 means unlimited. With an verbosity of 2 blocked and 596 + unblocked subnets will be logged. 360 597 ''; 361 598 }; 362 599 363 - verbosity = mkOption { 364 - type = types.int; 365 - default = 0; 600 + slip = mkOption { 601 + type = types.nullOr types.int; 602 + default = null; 366 603 description = '' 367 - Verbosity level. 604 + Number of packets that get discarded before replying a SLIP response. 605 + 0 disables SLIP responses. 1 will make every response a SLIP response. 368 606 ''; 369 607 }; 370 608 371 - hideVersion = mkOption { 372 - type = types.bool; 373 - default = true; 609 + size = mkOption { 610 + type = types.int; 611 + default = 1000000; 374 612 description = '' 375 - Wheter NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries. 613 + Size of the hashtable. More buckets use more memory but lower 614 + the chance of hash hash collisions. 376 615 ''; 377 616 }; 378 617 379 - identity = mkOption { 380 - type = types.str; 381 - default = "unidentified server"; 618 + whitelistRatelimit = mkOption { 619 + type = types.int; 620 + default = 2000; 382 621 description = '' 383 - Identify the server (CH TXT ID.SERVER entry). 622 + Max qps allowed from whitelisted sources. 623 + 0 means unlimited. Set the rrl-whitelist option for specific 624 + queries to apply this limit instead of the default to them. 384 625 ''; 385 626 }; 386 627 387 - nsid = mkOption { 388 - type = types.nullOr types.str; 389 - default = null; 390 - description = '' 391 - NSID identity (hex string, or "ascii_somestring"). 392 - ''; 393 - }; 628 + }; 394 629 395 - tcpCount = mkOption { 396 - type = types.int; 397 - default = 100; 398 - description = '' 399 - Maximum number of concurrent TCP connections per server. 400 - ''; 401 - }; 402 630 403 - tcpQueryCount = mkOption { 404 - type = types.int; 405 - default = 0; 406 - description = '' 407 - Maximum number of queries served on a single TCP connection. 408 - 0 means no maximum. 409 - ''; 410 - }; 631 + remoteControl = { 411 632 412 - tcpTimeout = mkOption { 413 - type = types.int; 414 - default = 120; 415 - description = '' 416 - TCP timeout in seconds. 417 - ''; 418 - }; 633 + enable = mkEnableOption "remote control via nsd-control"; 419 634 420 - ipv4EDNSSize = mkOption { 421 - type = types.int; 422 - default = 4096; 635 + controlCertFile = mkOption { 636 + type = types.path; 637 + default = "/etc/nsd/nsd_control.pem"; 423 638 description = '' 424 - Preferred EDNS buffer size for IPv4. 639 + Path to the client certificate signed with the server certificate. 640 + This file is used by nsd-control and generated by nsd-control-setup. 425 641 ''; 426 642 }; 427 643 428 - ipv6EDNSSize = mkOption { 429 - type = types.int; 430 - default = 4096; 644 + controlKeyFile = mkOption { 645 + type = types.path; 646 + default = "/etc/nsd/nsd_control.key"; 431 647 description = '' 432 - Preferred EDNS buffer size for IPv6. 648 + Path to the client private key, which is used by nsd-control 649 + but not by the server. This file is generated by nsd-control-setup. 433 650 ''; 434 651 }; 435 652 436 - statistics = mkOption { 437 - type = types.nullOr types.int; 438 - default = null; 653 + interfaces = mkOption { 654 + type = types.listOf types.str; 655 + default = [ "127.0.0.1" "::1" ]; 439 656 description = '' 440 - Statistics are produced every number of seconds. Prints to log. 441 - If null no statistics are logged. 657 + Which interfaces NSD should bind to for remote control. 442 658 ''; 443 659 }; 444 660 445 - xfrdReloadTimeout = mkOption { 446 - type = types.int; 447 - default = 1; 661 + port = mkOption { 662 + type = types.int; 663 + default = 8952; 448 664 description = '' 449 - Number of seconds between reloads triggered by xfrd. 665 + Port number for remote control operations (uses TLS over TCP). 450 666 ''; 451 667 }; 452 668 453 - zonefilesCheck = mkOption { 454 - type = types.bool; 455 - default = true; 669 + serverCertFile = mkOption { 670 + type = types.path; 671 + default = "/etc/nsd/nsd_server.pem"; 456 672 description = '' 457 - Wheter to check mtime of all zone files on start and sighup. 673 + Path to the server self signed certificate, which is used by the server 674 + but and by nsd-control. This file is generated by nsd-control-setup. 458 675 ''; 459 676 }; 460 677 461 - 462 - extraConfig = mkOption { 463 - type = types.str; 464 - default = ""; 678 + serverKeyFile = mkOption { 679 + type = types.path; 680 + default = "/etc/nsd/nsd_server.key"; 465 681 description = '' 466 - Extra nsd config. 682 + Path to the server private key, which is used by the server 683 + but not by nsd-control. This file is generated by nsd-control-setup. 467 684 ''; 468 685 }; 469 686 470 - 471 - ratelimit = { 472 - enable = mkEnableOption "ratelimit capabilities"; 473 - 474 - size = mkOption { 475 - type = types.int; 476 - default = 1000000; 477 - description = '' 478 - Size of the hashtable. More buckets use more memory but lower 479 - the chance of hash hash collisions. 480 - ''; 481 - }; 482 - 483 - ratelimit = mkOption { 484 - type = types.int; 485 - default = 200; 486 - description = '' 487 - Max qps allowed from any query source. 488 - 0 means unlimited. With an verbosity of 2 blocked and 489 - unblocked subnets will be logged. 490 - ''; 491 - }; 492 - 493 - whitelistRatelimit = mkOption { 494 - type = types.int; 495 - default = 2000; 496 - description = '' 497 - Max qps allowed from whitelisted sources. 498 - 0 means unlimited. Set the rrl-whitelist option for specific 499 - queries to apply this limit instead of the default to them. 500 - ''; 501 - }; 502 - 503 - slip = mkOption { 504 - type = types.nullOr types.int; 505 - default = null; 506 - description = '' 507 - Number of packets that get discarded before replying a SLIP response. 508 - 0 disables SLIP responses. 1 will make every response a SLIP response. 509 - ''; 510 - }; 511 - 512 - ipv4PrefixLength = mkOption { 513 - type = types.nullOr types.int; 514 - default = null; 515 - description = '' 516 - IPv4 prefix length. Addresses are grouped by netblock. 517 - ''; 518 - }; 519 - 520 - ipv6PrefixLength = mkOption { 521 - type = types.nullOr types.int; 522 - default = null; 523 - description = '' 524 - IPv6 prefix length. Addresses are grouped by netblock. 525 - ''; 526 - }; 527 - }; 528 - 529 - 530 - remoteControl = { 531 - enable = mkEnableOption "remote control via nsd-control"; 532 - 533 - interfaces = mkOption { 534 - type = types.listOf types.str; 535 - default = [ "127.0.0.1" "::1" ]; 536 - description = '' 537 - Which interfaces NSD should bind to for remote control. 538 - ''; 539 - }; 540 - 541 - port = mkOption { 542 - type = types.int; 543 - default = 8952; 544 - description = '' 545 - Port number for remote control operations (uses TLS over TCP). 546 - ''; 547 - }; 548 - 549 - serverKeyFile = mkOption { 550 - type = types.path; 551 - default = "/etc/nsd/nsd_server.key"; 552 - description = '' 553 - Path to the server private key, which is used by the server 554 - but not by nsd-control. This file is generated by nsd-control-setup. 555 - ''; 556 - }; 557 - 558 - serverCertFile = mkOption { 559 - type = types.path; 560 - default = "/etc/nsd/nsd_server.pem"; 561 - description = '' 562 - Path to the server self signed certificate, which is used by the server 563 - but and by nsd-control. This file is generated by nsd-control-setup. 564 - ''; 565 - }; 566 - 567 - controlKeyFile = mkOption { 568 - type = types.path; 569 - default = "/etc/nsd/nsd_control.key"; 570 - description = '' 571 - Path to the client private key, which is used by nsd-control 572 - but not by the server. This file is generated by nsd-control-setup. 573 - ''; 574 - }; 575 - 576 - controlCertFile = mkOption { 577 - type = types.path; 578 - default = "/etc/nsd/nsd_control.pem"; 579 - description = '' 580 - Path to the client certificate signed with the server certificate. 581 - This file is used by nsd-control and generated by nsd-control-setup. 582 - ''; 583 - }; 584 - }; 687 + }; 585 688 586 689 587 - keys = mkOption { 588 - type = types.attrsOf (types.submodule { 589 - options = { 590 - algorithm = mkOption { 591 - type = types.str; 592 - default = "hmac-sha256"; 593 - description = '' 594 - Authentication algorithm for this key. 595 - ''; 690 + zones = mkOption { 691 + type = types.attrsOf zoneOptions; 692 + default = {}; 693 + example = literalExample '' 694 + { "serverGroup1" = { 695 + provideXFR = [ "10.1.2.3 NOKEY" ]; 696 + children = { 697 + "example.com." = { 698 + data = ''' 699 + $ORIGIN example.com. 700 + $TTL 86400 701 + @ IN SOA a.ns.example.com. admin.example.com. ( 702 + ... 703 + '''; 704 + }; 705 + "example.org." = { 706 + data = ''' 707 + $ORIGIN example.org. 708 + $TTL 86400 709 + @ IN SOA a.ns.example.com. admin.example.com. ( 710 + ... 711 + '''; 712 + }; 596 713 }; 714 + }; 597 715 598 - keyFile = mkOption { 599 - type = types.path; 600 - description = '' 601 - Path to the file which contains the actual base64 encoded 602 - key. The key will be copied into "${stateDir}/private" before 603 - NSD starts. The copied file is only accessibly by the NSD 604 - user. 605 - ''; 606 - }; 607 - }; 608 - }); 609 - default = {}; 610 - example = { 611 - "tsig.example.org" = { 612 - algorithm = "hmac-md5"; 613 - secret = "aaaaaabbbbbbccccccdddddd"; 716 + "example.net." = { 717 + provideXFR = [ "10.3.2.1 NOKEY" ]; 718 + data = ''' 719 + ... 720 + '''; 614 721 }; 615 722 }; 616 - description = '' 617 - Define your TSIG keys here. 618 - ''; 619 - }; 723 + ''; 724 + description = '' 725 + Define your zones here. Zones can cascade other zones and therefore 726 + inherit settings from parent zones. Look at the definition of 727 + children to learn about inheritance and child zones. 728 + The given example will define 3 zones (example.(com|org|net).). Both 729 + example.com. and example.org. inherit their configuration from 730 + serverGroup1. 731 + ''; 732 + }; 620 733 621 - zones = mkOption { 622 - type = types.attrsOf zoneOptions; 623 - default = {}; 624 - example = literalExample '' 625 - { "serverGroup1" = { 626 - provideXFR = [ "10.1.2.3 NOKEY" ]; 627 - children = { 628 - "example.com." = { 629 - data = ''' 630 - $ORIGIN example.com. 631 - $TTL 86400 632 - @ IN SOA a.ns.example.com. admin.example.com. ( 633 - ... 634 - '''; 635 - }; 636 - "example.org." = { 637 - data = ''' 638 - $ORIGIN example.org. 639 - $TTL 86400 640 - @ IN SOA a.ns.example.com. admin.example.com. ( 641 - ... 642 - '''; 643 - }; 644 - }; 645 - }; 646 - 647 - "example.net." = { 648 - provideXFR = [ "10.3.2.1 NOKEY" ]; 649 - data = ''' 650 - ... 651 - '''; 652 - }; 653 - } 654 - ''; 655 - description = '' 656 - Define your zones here. Zones can cascade other zones and therefore 657 - inherit settings from parent zones. Look at the definition of 658 - children to learn about inheritance and child zones. 659 - The given example will define 3 zones (example.(com|org|net).). Both 660 - example.com. and example.org. inherit their configuration from 661 - serverGroup1. 662 - ''; 663 - }; 664 - 665 - }; 666 734 }; 667 735 668 736 config = mkIf cfg.enable { 669 737 670 738 users.extraGroups = singleton { 671 739 name = username; 672 - gid = config.ids.gids.nsd; 740 + gid = config.ids.gids.nsd; 673 741 }; 674 742 675 743 users.extraUsers = singleton { 676 - name = username; 744 + name = username; 677 745 description = "NSD service user"; 678 - home = stateDir; 746 + home = stateDir; 679 747 createHome = true; 680 - uid = config.ids.uids.nsd; 681 - group = username; 748 + uid = config.ids.uids.nsd; 749 + group = username; 682 750 }; 683 751 684 752 systemd.services.nsd = { 685 753 description = "NSD authoritative only domain name service"; 686 - wantedBy = [ "multi-user.target" ]; 687 - after = [ "network.target" ]; 754 + 755 + after = [ "keys.target" "network.target" ]; 756 + wantedBy = [ "multi-user.target" ]; 757 + wants = [ "keys.target" ]; 688 758 689 759 serviceConfig = { 690 - PIDFile = pidFile; 691 - Restart = "always"; 692 - ExecStart = "${nsdPkg}/sbin/nsd -d -c ${configFile}"; 760 + ExecStart = "${nsdPkg}/sbin/nsd -d -c ${nsdEnv}/nsd.conf"; 761 + PIDFile = pidFile; 762 + Restart = "always"; 763 + RestartSec = "4s"; 764 + StartLimitBurst = 4; 765 + StartLimitInterval = "5min"; 693 766 }; 694 767 695 768 preStart = '' 696 - ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/private" 697 - ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/tmp" 698 - ${pkgs.coreutils}/bin/mkdir -m 0700 -p "${stateDir}/var" 769 + rm -Rf "${stateDir}/private/" 770 + rm -Rf "${stateDir}/tmp/" 699 771 700 - ${pkgs.coreutils}/bin/touch "${stateDir}/don't touch anything in here" 772 + mkdir -m 0700 -p "${stateDir}/private" 773 + mkdir -m 0700 -p "${stateDir}/tmp" 774 + mkdir -m 0700 -p "${stateDir}/var" 701 775 702 - ${pkgs.coreutils}/bin/rm -f "${stateDir}/private/"* 703 - ${pkgs.coreutils}/bin/rm -f "${stateDir}/tmp/"* 776 + cat > "${stateDir}/don't touch anything in here" << EOF 777 + Everything in this directory except NSD's state in var is 778 + automatically generated and will be purged and redeployed 779 + by the nsd.service pre-start script. 780 + EOF 704 781 705 - ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/private" 706 - ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/tmp" 707 - ${pkgs.coreutils}/bin/chown nsd:nsd -R "${stateDir}/var" 782 + chown ${username}:${username} -R "${stateDir}/private" 783 + chown ${username}:${username} -R "${stateDir}/tmp" 784 + chown ${username}:${username} -R "${stateDir}/var" 708 785 709 - ${pkgs.coreutils}/bin/rm -rf "${stateDir}/zones" 710 - ${pkgs.coreutils}/bin/cp -r "${zoneFiles}" "${stateDir}/zones" 786 + rm -rf "${stateDir}/zones" 787 + cp -rL "${nsdEnv}/zones" "${stateDir}/zones" 711 788 712 789 ${copyKeys} 713 790 '';
+2 -3
pkgs/servers/dns/nsd/default.nix
··· 13 13 }: 14 14 15 15 stdenv.mkDerivation rec { 16 - name = "nsd-4.1.6"; 16 + name = "nsd-4.1.7"; 17 17 18 18 src = fetchurl { 19 19 url = "http://www.nlnetlabs.nl/downloads/nsd/${name}.tar.gz"; 20 - sha256 = "0pvpsxhil60m21h3pqlzs0l5m8qd3l6j8fkjyfg8plwmbh2j5xl8"; 20 + sha256 = "12hskfgfbkvcgpa1xxkqd8lnc6xvln1amn97x6avfnj9kfrbxa3v"; 21 21 }; 22 22 23 23 buildInputs = [ libevent openssl ]; ··· 41 41 homepage = http://www.nlnetlabs.nl; 42 42 description = "Authoritative only, high performance, simple and open source name server"; 43 43 license = licenses.bsd3; 44 - 45 44 platforms = platforms.unix; 46 45 maintainers = [ maintainers.hrdinka ]; 47 46 };