diff options
Diffstat (limited to 'nixos/modules/services/networking')
18 files changed, 1012 insertions, 513 deletions
diff --git a/nixos/modules/services/networking/bird.nix b/nixos/modules/services/networking/bird.nix index e7e1db191529..e76cdac14ca8 100644 --- a/nixos/modules/services/networking/bird.nix +++ b/nixos/modules/services/networking/bird.nix @@ -30,7 +30,7 @@ in user = mkOption { type = types.string; - default = "ircd"; + default = "bird"; description = '' BIRD Internet Routing Daemon user. ''; @@ -38,7 +38,7 @@ in group = mkOption { type = types.string; - default = "ircd"; + default = "bird"; description = '' BIRD Internet Routing Daemon group. ''; diff --git a/nixos/modules/services/networking/consul.nix b/nixos/modules/services/networking/consul.nix index 58dad56014b0..2aa101f980da 100644 --- a/nixos/modules/services/networking/consul.nix +++ b/nixos/modules/services/networking/consul.nix @@ -33,6 +33,7 @@ in package = mkOption { type = types.package; default = pkgs.consul; + defaultText = "pkgs.consul"; description = '' The package used for the Consul agent and CLI. ''; diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix index e60520c742bd..c5dd1e71c189 100644 --- a/nixos/modules/services/networking/ddclient.nix +++ b/nixos/modules/services/networking/ddclient.nix @@ -127,7 +127,6 @@ in wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; - environment.SSL_CERT_FILE = "/etc/ssl/certs/ca-certificates.crt"; serviceConfig = { # Uncomment this if too many problems occur: # Type = "forking"; diff --git a/nixos/modules/services/networking/dnscrypt-proxy.nix b/nixos/modules/services/networking/dnscrypt-proxy.nix index 9340be28205a..016b6a12cd61 100644 --- a/nixos/modules/services/networking/dnscrypt-proxy.nix +++ b/nixos/modules/services/networking/dnscrypt-proxy.nix @@ -52,7 +52,10 @@ in default = "opendns"; type = types.nullOr types.string; description = '' - The name of the upstream DNSCrypt resolver to use. + The name of the upstream DNSCrypt resolver to use. See + <literal>${resolverListFile}</literal> for alternative resolvers + (e.g., if you are concerned about logging and/or server + location). ''; }; customResolver = mkOption { diff --git a/nixos/modules/services/networking/ejabberd.nix b/nixos/modules/services/networking/ejabberd.nix index 7af11f37a43c..8ffce23a4b10 100644 --- a/nixos/modules/services/networking/ejabberd.nix +++ b/nixos/modules/services/networking/ejabberd.nix @@ -32,6 +32,7 @@ in { package = mkOption { type = types.package; default = pkgs.ejabberd; + defaultText = "pkgs.ejabberd"; description = "ejabberd server package to use"; }; diff --git a/nixos/modules/services/networking/ifplugd.nix b/nixos/modules/services/networking/ifplugd.nix deleted file mode 100644 index 00b94fe2284e..000000000000 --- a/nixos/modules/services/networking/ifplugd.nix +++ /dev/null @@ -1,82 +0,0 @@ -{ config, lib, pkgs, ... }: - -with lib; - -let - - inherit (pkgs) ifplugd; - - cfg = config.networking.interfaceMonitor; - - # The ifplugd action script, which is called whenever the link - # status changes (i.e., a cable is plugged in or unplugged). - plugScript = pkgs.writeScript "ifplugd.action" - '' - #! ${pkgs.stdenv.shell} - iface="$1" - status="$2" - ${cfg.commands} - ''; - -in - -{ - - ###### interface - - options = { - - networking.interfaceMonitor.enable = mkOption { - type = types.bool; - default = false; - description = '' - If <literal>true</literal>, monitor Ethernet interfaces for - cables being plugged in or unplugged. When this occurs, the - commands specified in - <option>networking.interfaceMonitor.commands</option> are - executed. - ''; - }; - - networking.interfaceMonitor.beep = mkOption { - type = types.bool; - default = false; - description = '' - If <literal>true</literal>, beep when an Ethernet cable is - plugged in or unplugged. - ''; - }; - - networking.interfaceMonitor.commands = mkOption { - type = types.lines; - default = ""; - description = '' - Shell commands to be executed when the link status of an - interface changes. On invocation, the shell variable - <varname>iface</varname> contains the name of the interface, - while the variable <varname>status</varname> contains either - <literal>up</literal> or <literal>down</literal> to indicate - the new status. - ''; - }; - - }; - - - ###### implementation - - config = mkIf cfg.enable { - systemd.services.ifplugd = { - description = "Network interface connectivity monitor"; - after = [ "network-interfaces.target" ]; - wantedBy = [ "multi-user.target" ]; - script = '' - ${ifplugd}/sbin/ifplugd --no-daemon --no-startup --no-shutdown \ - ${if config.networking.interfaceMonitor.beep then "" else "--no-beep"} \ - --run ${plugScript} - ''; - }; - - environment.systemPackages = [ ifplugd ]; - }; -} diff --git a/nixos/modules/services/networking/kippo.nix b/nixos/modules/services/networking/kippo.nix index 7d70a3d05fa7..5f3efcd133a1 100644 --- a/nixos/modules/services/networking/kippo.nix +++ b/nixos/modules/services/networking/kippo.nix @@ -54,7 +54,7 @@ rec { }; config = mkIf cfg.enable { environment.systemPackages = with pkgs.pythonPackages; [ - python twisted pycrypto pyasn1 ]; + python twisted_11 pycrypto pyasn1 ]; environment.etc."kippo.cfg".text = '' # Automatically generated by NixOS. @@ -84,7 +84,7 @@ rec { description = "Kippo Web Server"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.pythonPackages.twisted}/lib/python2.7/site-packages/:."; + environment.PYTHONPATH = "${pkgs.kippo}/src/:${pkgs.pythonPackages.pycrypto}/lib/python2.7/site-packages/:${pkgs.pythonPackages.pyasn1}/lib/python2.7/site-packages/:${pkgs.pythonPackages.python}/lib/python2.7/site-packages/:${pkgs.pythonPackages.twisted_11}/lib/python2.7/site-packages/:."; preStart = '' if [ ! -d ${cfg.varPath}/ ] ; then mkdir -p ${cfg.logPath}/tty @@ -107,7 +107,7 @@ rec { fi ''; - serviceConfig.ExecStart = "${pkgs.pythonPackages.twisted}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n"; + serviceConfig.ExecStart = "${pkgs.pythonPackages.twisted_11}/bin/twistd -y ${pkgs.kippo}/src/kippo.tac --syslog --rundir=${cfg.varPath}/ --pidfile=${cfg.pidPath}/kippo.pid --prefix=kippo -n"; serviceConfig.PermissionsStartOnly = true; serviceConfig.User = "kippo"; serviceConfig.Group = "kippo"; diff --git a/nixos/modules/services/networking/libreswan.nix b/nixos/modules/services/networking/libreswan.nix new file mode 100644 index 000000000000..3866b216f8ef --- /dev/null +++ b/nixos/modules/services/networking/libreswan.nix @@ -0,0 +1,126 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + cfg = config.services.libreswan; + + libexec = "${pkgs.libreswan}/libexec/ipsec"; + ipsec = "${pkgs.libreswan}/sbin/ipsec"; + + trim = chars: str: let + nonchars = filter (x : !(elem x.value chars)) + (imap (i: v: {ind = (sub i 1); value = v;}) (stringToCharacters str)); + in + if length nonchars == 0 then "" + else substring (head nonchars).ind (add 1 (sub (last nonchars).ind (head nonchars).ind)) str; + indent = str: concatStrings (concatMap (s: [" " (trim [" " "\t"] s) "\n"]) (splitString "\n" str)); + configText = indent (toString cfg.configSetup); + connectionText = concatStrings (mapAttrsToList (n: v: + '' + conn ${n} + ${indent v} + + '') cfg.connections); + configFile = pkgs.writeText "ipsec.conf" + '' + config setup + ${configText} + + ${connectionText} + ''; + +in + +{ + + ###### interface + + options = { + + services.libreswan = { + + enable = mkEnableOption "libreswan ipsec service"; + + configSetup = mkOption { + type = types.lines; + default = '' + protostack=netkey + nat_traversal=yes + virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10 + ''; + example = '' + secretsfile=/root/ipsec.secrets + protostack=netkey + nat_traversal=yes + virtual_private=%v4:10.0.0.0/8,%v4:192.168.0.0/16,%v4:172.16.0.0/12,%v4:25.0.0.0/8,%v4:100.64.0.0/10,%v6:fd00::/8,%v6:fe80::/10 + ''; + description = "Options to go in the 'config setup' section of the libreswan ipsec configuration"; + }; + + connections = mkOption { + type = types.attrsOf types.lines; + default = {}; + example = { + myconnection = '' + auto=add + left=%defaultroute + leftid=@user + + right=my.vpn.com + + ikev2=no + ikelifetime=8h + ''; + }; + description = "A set of connections to define for the libreswan ipsec service"; + }; + }; + + }; + + + ###### implementation + + config = mkIf cfg.enable { + + environment.systemPackages = [ pkgs.libreswan pkgs.iproute ]; + + systemd.services.ipsec = { + description = "Internet Key Exchange (IKE) Protocol Daemon for IPsec"; + path = [ + "${pkgs.libreswan}" + "${pkgs.iproute}" + "${pkgs.procps}" + ]; + + wants = [ "network-online.target" ]; + after = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + + serviceConfig = { + Type = "simple"; + Restart = "always"; + EnvironmentFile = "${pkgs.libreswan}/etc/sysconfig/pluto"; + ExecStartPre = [ + "${libexec}/addconn --config ${configFile} --checkconfig" + "${libexec}/_stackmanager start" + "${ipsec} --checknss" + "${ipsec} --checknflog" + ]; + ExecStart = "${libexec}/pluto --config ${configFile} --nofork \$PLUTO_OPTIONS"; + ExecStop = "${libexec}/whack --shutdown"; + ExecStopPost = [ + "${pkgs.iproute}/bin/ip xfrm policy flush" + "${pkgs.iproute}/bin/ip xfrm state flush" + "${ipsec} --stopnflog" + ]; + ExecReload = "${libexec}/whack --listen"; + }; + + }; + + }; + +} diff --git a/nixos/modules/services/networking/networkmanager.nix b/nixos/modules/services/networking/networkmanager.nix index 01c05fb4a245..9912ad9ae3fc 100644 --- a/nixos/modules/services/networking/networkmanager.nix +++ b/nixos/modules/services/networking/networkmanager.nix @@ -21,6 +21,9 @@ let [logging] level=WARN + + [connection] + ipv6.ip6-privacy=2 ''; /* @@ -228,6 +231,11 @@ in { users.extraUsers = [{ name = "nm-openvpn"; uid = config.ids.uids.nm-openvpn; + } + { + # to enable link-local connections + name = "avahi-autoipd"; + uid = config.ids.uids.avahi-autoipd; }]; systemd.packages = cfg.packages; diff --git a/nixos/modules/services/networking/nntp-proxy.nix b/nixos/modules/services/networking/nntp-proxy.nix new file mode 100644 index 000000000000..cfa662c7311b --- /dev/null +++ b/nixos/modules/services/networking/nntp-proxy.nix @@ -0,0 +1,235 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + + inherit (pkgs) nntp-proxy; + + proxyUser = "nntp-proxy"; + + cfg = config.services.nntp-proxy; + + configBool = b: if b then "TRUE" else "FALSE"; + + confFile = pkgs.writeText "nntp-proxy.conf" '' + nntp_server: + { + # NNTP Server host and port address + server = "${cfg.upstreamServer}"; + port = ${toString cfg.upstreamPort}; + # NNTP username + username = "${cfg.upstreamUser}"; + # NNTP password in clear text + password = "${cfg.upstreamPassword}"; + # Maximum number of connections allowed by the NNTP + max_connections = ${toString cfg.upstreamMaxConnections}; + }; + + proxy: + { + # Local address and port to bind to + bind_ip = "${cfg.listenAddress}"; + bind_port = ${toString cfg.port}; + + # SSL key and cert file + ssl_key = "${cfg.sslKey}"; + ssl_cert = "${cfg.sslCert}"; + + # prohibit users from posting + prohibit_posting = ${configBool cfg.prohibitPosting}; + # Verbose levels: ERROR, WARNING, NOTICE, INFO, DEBUG + verbose = "${toUpper cfg.verbosity}"; + # Password is made with: 'mkpasswd -m sha-512 <password>' + users = (${concatStringsSep ",\n" (mapAttrsToList (username: userConfig: + '' + { + username = "${username}"; + password = "${userConfig.passwordHash}"; + max_connections = ${toString userConfig.maxConnections}; + } + '') cfg.users)}); + }; + ''; + +in + +{ + + ###### interface + + options = { + + services.nntp-proxy = { + enable = mkEnableOption "NNTP-Proxy"; + + upstreamServer = mkOption { + type = types.str; + default = ""; + example = "ssl-eu.astraweb.com"; + description = '' + Upstream server address + ''; + }; + + upstreamPort = mkOption { + type = types.int; + default = 563; + description = '' + Upstream server port + ''; + }; + + upstreamMaxConnections = mkOption { + type = types.int; + default = 20; + description = '' + Upstream server maximum allowed concurrent connections + ''; + }; + + upstreamUser = mkOption { + type = types.str; + default = ""; + description = '' + Upstream server username + ''; + }; + + upstreamPassword = mkOption { + type = types.str; + default = ""; + description = '' + Upstream server password + ''; + }; + + listenAddress = mkOption { + type = types.str; + default = "127.0.0.1"; + example = "[::]"; + description = '' + Proxy listen address (IPv6 literal addresses need to be enclosed in "[" and "]" characters) + ''; + }; + + port = mkOption { + type = types.int; + default = 5555; + description = '' + Proxy listen port + ''; + }; + + sslKey = mkOption { + type = types.str; + default = "key.pem"; + example = "/path/to/your/key.file"; + description = '' + Proxy ssl key path + ''; + }; + + sslCert = mkOption { + type = types.str; + default = "cert.pem"; + example = "/path/to/your/cert.file"; + description = '' + Proxy ssl certificate path + ''; + }; + + prohibitPosting = mkOption { + type = types.bool; + default = true; + description = '' + Whether to prohibit posting to the upstream server + ''; + }; + + verbosity = mkOption { + type = types.str; + default = "info"; + example = "error"; + description = '' + Verbosity level (error, warning, notice, info, debug) + ''; + }; + + users = mkOption { + type = types.attrsOf (types.submodule { + options = { + username = mkOption { + type = types.str; + default = null; + description = '' + Username + ''; + }; + + passwordHash = mkOption { + type = types.str; + default = null; + example = "$6$GtzE7FrpE$wwuVgFYU.TZH4Rz.Snjxk9XGua89IeVwPQ/fEUD8eujr40q5Y021yhn0aNcsQ2Ifw.BLclyzvzgegopgKcneL0"; + description = '' + SHA-512 password hash (can be generated by + <code>mkpasswd -m sha-512 <password></code>) + ''; + }; + + maxConnections = mkOption { + type = types.int; + default = 1; + description = '' + Maximum number of concurrent connections to the proxy for this user + ''; + }; + }; + }); + description = '' + NNTP-Proxy user configuration + ''; + + default = {}; + example = literalExample '' + "user1" = { + passwordHash = "$6$1l0t5Kn2Dk$appzivc./9l/kjq57eg5UCsBKlcfyCr0zNWYNerKoPsI1d7eAwiT0SVsOVx/CTgaBNT/u4fi2vN.iGlPfv1ek0"; + maxConnections = 5; + }; + "anotheruser" = { + passwordHash = "$6$6lwEsWB.TmsS$W7m1riUx4QrA8pKJz8hvff0dnF1NwtZXgdjmGqA1Dx2MDPj07tI9GNcb0SWlMglE.2/hBgynDdAd/XqqtRqVQ0"; + maxConnections = 7; + }; + ''; + }; + }; + + }; + + ###### implementation + + config = mkIf cfg.enable { + + users.extraUsers = singleton + { name = proxyUser; + uid = config.ids.uids.nntp-proxy; + description = "NNTP-Proxy daemon user"; + }; + + systemd.services.nntp-proxy = { + description = "NNTP proxy"; + after = [ "network.target" "nss-lookup.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { User="${proxyUser}"; }; + serviceConfig.ExecStart = "${nntp-proxy}/bin/nntp-proxy ${confFile}"; + preStart = '' + if [ ! \( -f ${cfg.sslCert} -a -f ${cfg.sslKey} \) ]; then + ${pkgs.openssl}/bin/openssl req -subj '/CN=AutoGeneratedCert/O=NixOS Service/C=US' \ + -new -newkey rsa:2048 -days 365 -nodes -x509 -keyout ${cfg.sslKey} -out ${cfg.sslCert}; + fi + ''; + }; + + }; + +} diff --git a/nixos/modules/services/networking/nsd.nix b/nixos/modules/services/networking/nsd.nix index e85f26811257..333a3378c4cc 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 + ''; + }; + + writeZoneData = name: text: pkgs.writeTextFile { + inherit name text; + destination = "/zones/${name}"; }; - configFile = pkgs.writeText "nsd.conf" '' + + # 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} + 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} - port: ${toString cfg.port} - verbosity: ${toString cfg.verbosity} - hide-version: ${yesOrNo cfg.hideVersion} - identity: "${cfg.identity}" + 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} + control-key-file: "${cfg.remoteControl.controlKeyFile}" + control-cert-file: "${cfg.remoteControl.controlCertFile}" ${forEach " control-interface: " cfg.remoteControl.interfaces} - control-port: ${toString cfg.port} + control-port: ${toString cfg.remoteControl.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}" - # 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. <screen><![CDATA[ @@ -193,28 +219,32 @@ let ''; }; - requestXFR = mkOption { - type = types.listOf types.str; - default = []; - example = []; + children = mkOption { + default = {}; description = '' - Format: <code>[AXFR|UDP] <ip-address> <key-name | NOKEY></code> + 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,38 +261,47 @@ 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. ''; }; + outgoingInterface = mkOption { + 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. + Supply either a plain IPv4 or IPv6 address with an optional port + number (ip@port). + ''; + }; + provideXFR = mkOption { - type = types.listOf types.str; - default = []; - example = [ "192.0.2.0/24 NOKEY" "192.0.2.0/24 my_tsig_key_name" ]; + 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"; + requestXFR = mkOption { + type = types.listOf types.str; + default = []; + example = []; description = '' - This address will be used for zone-transfere requests if configured - as a secondary server or notifications in case of a primary server. - Supply either a plain IPv4 or IPv6 address with an optional port - number (ip@port). + Format: <code>[AXFR|UDP] <ip-address> <key-name | NOKEY></code> ''; }; 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,419 +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 = '' + Whether 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 = '' + Whether 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. + ''; + }; + + ipv6 = mkOption { + type = types.bool; + default = true; + description = '' + Whether to listen on IPv6 connections. + ''; + }; + + ipv6EDNSSize = mkOption { + type = types.int; + default = 4096; + description = '' + Preferred EDNS buffer size for IPv6. + ''; + }; + + logTimeAscii = mkOption { + type = types.bool; + default = true; + description = '' + Log time in ascii, if false then in unix epoch seconds. + ''; + }; + + nsid = mkOption { + type = types.nullOr types.str; + default = null; + description = '' + NSID identity (hex string, or "ascii_somestring"). + ''; + }; + + port = mkOption { + type = types.int; + default = 53; + description = '' + Port the service should bind do. + ''; + }; + + reuseport = mkOption { + type = types.bool; + default = pkgs.stdenv.isLinux; + description = '' + Whether 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 + ''; + }; + + rootServer = mkOption { + type = types.bool; + default = false; + description = '' + Whether this server will be a root server (a DNS root server, you + usually don't want that). + ''; + }; + + roundRobin = mkEnableOption "round robin rotation of records"; + + serverCount = mkOption { + type = types.int; + default = 1; + description = '' + Number of NSD servers to fork. Put the number of CPUs to use here. + ''; + }; + + 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. + ''; + }; + + 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 = '' + Whether to check mtime of all zone files on start and sighup. + ''; + }; + + + 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. + ''; + }; + + }; + }); + default = {}; + example = literalExample '' + { "tsig.example.org" = { + algorithm = "hmac-md5"; + keyFile = "/path/to/my/key"; + }; + } + ''; + description = '' + Define your TSIG keys here. + ''; + }; + + + ratelimit = { + + enable = mkEnableOption "ratelimit capabilities"; - hideVersion = mkOption { - type = types.bool; - default = true; + ipv4PrefixLength = mkOption { + type = types.nullOr types.int; + default = null; description = '' - Wheter NSD should answer VERSION.BIND and VERSION.SERVER CHAOS class queries. + IPv4 prefix length. Addresses are grouped by netblock. ''; }; - identity = mkOption { - type = types.str; - default = "unidentified server"; + ipv6PrefixLength = mkOption { + type = types.nullOr types.int; + default = null; description = '' - Identify the server (CH TXT ID.SERVER entry). + IPv6 prefix length. Addresses are grouped by netblock. ''; }; - nsid = mkOption { - type = types.nullOr types.str; - default = null; + ratelimit = mkOption { + type = types.int; + default = 200; description = '' - NSID identity (hex string, or "ascii_somestring"). + Max qps allowed from any query source. + 0 means unlimited. With an verbosity of 2 blocked and + unblocked subnets will be logged. ''; }; - tcpCount = mkOption { - type = types.int; - default = 100; + slip = mkOption { + type = types.nullOr types.int; + default = null; description = '' - Maximum number of concurrent TCP connections per server. + Number of packets that get discarded before replying a SLIP response. + 0 disables SLIP responses. 1 will make every response a SLIP response. ''; }; - tcpQueryCount = mkOption { - type = types.int; - default = 0; + size = mkOption { + type = types.int; + default = 1000000; description = '' - Maximum number of queries served on a single TCP connection. - 0 means no maximum. + Size of the hashtable. More buckets use more memory but lower + the chance of hash hash collisions. ''; }; - tcpTimeout = mkOption { - type = types.int; - default = 120; + whitelistRatelimit = mkOption { + type = types.int; + default = 2000; description = '' - TCP timeout in seconds. + 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. ''; }; - ipv4EDNSSize = mkOption { - type = types.int; - default = 4096; + }; + + + remoteControl = { + + enable = mkEnableOption "remote control via nsd-control"; + + controlCertFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_control.pem"; description = '' - Preferred EDNS buffer size for IPv4. + Path to the client certificate signed with the server certificate. + This file is used by nsd-control and generated by nsd-control-setup. ''; }; - ipv6EDNSSize = mkOption { - type = types.int; - default = 4096; + controlKeyFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_control.key"; description = '' - Preferred EDNS buffer size for IPv6. + 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. ''; }; - statistics = mkOption { - type = types.nullOr types.int; - default = null; + interfaces = mkOption { + type = types.listOf types.str; + default = [ "127.0.0.1" "::1" ]; description = '' - Statistics are produced every number of seconds. Prints to log. - If null no statistics are logged. + Which interfaces NSD should bind to for remote control. ''; }; - xfrdReloadTimeout = mkOption { - type = types.int; - default = 1; + port = mkOption { + type = types.int; + default = 8952; description = '' - Number of seconds between reloads triggered by xfrd. + Port number for remote control operations (uses TLS over TCP). ''; }; - zonefilesCheck = mkOption { - type = types.bool; - default = true; + serverCertFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_server.pem"; description = '' - Wheter to check mtime of all zone files on start and sighup. + 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. ''; }; - - extraConfig = mkOption { - type = types.str; - default = ""; + serverKeyFile = mkOption { + type = types.path; + default = "/etc/nsd/nsd_server.key"; description = '' - Extra nsd config. + 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. ''; }; + }; - 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. - ''; - }; - }; - }); - default = {}; - example = { - "tsig.example.org" = { - algorithm = "hmac-md5"; - secret = "aaaaaabbbbbbccccccdddddd"; - }; - }; - description = '' - Define your TSIG keys here. - ''; - }; - zones = mkOption { - type = types.attrsOf zoneOptions; - default = {}; - example = { - "serverGroup1" = { + zones = mkOption { + type = types.attrsOf zoneOptions; + default = {}; + example = literalExample '' + { "serverGroup1" = { provideXFR = [ "10.1.2.3 NOKEY" ]; children = { "example.com." = { - data = '' + data = ''' $ORIGIN example.com. $TTL 86400 @ IN SOA a.ns.example.com. admin.example.com. ( ... - ''; + '''; }; "example.org." = { - data = '' + data = ''' $ORIGIN example.org. $TTL 86400 @ IN SOA a.ns.example.com. admin.example.com. ( ... - ''; + '''; }; }; }; "example.net." = { provideXFR = [ "10.3.2.1 NOKEY" ]; - data = ''...''; + 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. - ''; - }; - + } + ''; + 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/nixos/modules/services/networking/pdnsd.nix b/nixos/modules/services/networking/pdnsd.nix new file mode 100644 index 000000000000..f4467b818958 --- /dev/null +++ b/nixos/modules/services/networking/pdnsd.nix @@ -0,0 +1,93 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.services.pdnsd; + pdnsd = pkgs.pdnsd; + pdnsdUser = "pdnsd"; + pdnsdGroup = "pdnsd"; + pdnsdConf = pkgs.writeText "pdnsd.conf" + '' + global { + run_as=${pdnsdUser}; + cache_dir="${cfg.cacheDir}"; + ${cfg.globalConfig} + } + + server { + ${cfg.serverConfig} + } + ${cfg.extraConfig} + ''; +in + +{ options = + { services.pdnsd = + { enable = mkEnableOption "pdnsd"; + + cacheDir = mkOption { + type = types.str; + default = "/var/cache/pdnsd"; + description = "Directory holding the pdnsd cache"; + }; + + globalConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Global configuration that should be added to the global directory + of <literal>pdnsd.conf</literal>. + ''; + }; + + serverConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Server configuration that should be added to the server directory + of <literal>pdnsd.conf</literal>. + ''; + }; + + extraConfig = mkOption { + type = types.lines; + default = ""; + description = '' + Extra configuration directives that should be added to + <literal>pdnsd.conf</literal>. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + users.extraUsers = singleton { + name = pdnsdUser; + uid = config.ids.uids.pdnsd; + group = pdnsdGroup; + description = "pdnsd user"; + }; + + users.extraGroups = singleton { + name = pdnsdGroup; + gid = config.ids.gids.pdnsd; + }; + + systemd.services.pdnsd = + { wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + preStart = + '' + mkdir -p "${cfg.cacheDir}" + touch "${cfg.cacheDir}/pdnsd.cache" + chown -R ${pdnsdUser}:${pdnsdGroup} "${cfg.cacheDir}" + ''; + description = "pdnsd"; + serviceConfig = + { + ExecStart = "${pdnsd}/bin/pdnsd -c ${pdnsdConf}"; + }; + }; + }; +} diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index ba3efc8c0c2a..5971a5a250d3 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -263,7 +263,7 @@ in serviceConfig = { ExecStart = - "${cfgc.package}/sbin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + + "${cfgc.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + "-f ${pkgs.writeText "sshd_config" cfg.extraConfig}"; KillMode = "process"; } // (if cfg.startWhenNeeded then { @@ -304,7 +304,7 @@ in services.openssh.authorizedKeysFiles = [ ".ssh/authorized_keys" ".ssh/authorized_keys2" "/etc/ssh/authorized_keys.d/%u" ]; - services.openssh.extraConfig = + services.openssh.extraConfig = mkOrder 0 '' PidFile /run/sshd.pid diff --git a/nixos/modules/services/networking/syncthing.nix b/nixos/modules/services/networking/syncthing.nix index f5d5e1d25561..67b90516b996 100644 --- a/nixos/modules/services/networking/syncthing.nix +++ b/nixos/modules/services/networking/syncthing.nix @@ -33,6 +33,17 @@ in ''; }; + all_proxy = mkOption { + type = types.string; + default = ""; + example = "socks5://address.com:1234"; + description = '' + Overwrites all_proxy environment variable for the syncthing process to + the given value. This is normaly used to let relay client connect + through SOCKS5 proxy server. + ''; + }; + dataDir = mkOption { default = "/var/lib/syncthing"; description = '' @@ -51,7 +62,6 @@ in }; - }; }; @@ -66,8 +76,13 @@ in description = "Syncthing service"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - environment.STNORESTART = "yes"; # do not self-restart - environment.STNOUPGRADE = "yes"; + environment = { + STNORESTART = "yes"; # do not self-restart + STNOUPGRADE = "yes"; + } // + (config.networking.proxy.envVars) // + (if cfg.all_proxy != "" then { all_proxy = cfg.all_proxy; } else {}); + serviceConfig = { User = "${cfg.user}"; PermissionsStartOnly = true; diff --git a/nixos/modules/services/networking/tlsdated.nix b/nixos/modules/services/networking/tlsdated.nix index ff7d0178a81a..757cce287607 100644 --- a/nixos/modules/services/networking/tlsdated.nix +++ b/nixos/modules/services/networking/tlsdated.nix @@ -26,6 +26,7 @@ in extraOptions = mkOption { type = types.string; + default = ""; description = '' Additional command line arguments to pass to tlsdated. ''; diff --git a/nixos/modules/services/networking/unbound.nix b/nixos/modules/services/networking/unbound.nix index 73b10c1d5611..89762fe52488 100644 --- a/nixos/modules/services/networking/unbound.nix +++ b/nixos/modules/services/networking/unbound.nix @@ -16,6 +16,11 @@ let "forward-zone:\n name: .\n" + concatMapStrings (x: " forward-addr: ${x}\n") cfg.forwardAddresses; + rootTrustAnchorFile = "${stateDir}/root.key"; + + trustAnchor = optionalString cfg.enableRootTrustAnchor + "auto-trust-anchor-file: ${rootTrustAnchorFile}"; + confFile = pkgs.writeText "unbound.conf" '' server: directory: "${stateDir}" @@ -24,6 +29,7 @@ let pidfile: "" ${interfaces} ${access} + ${trustAnchor} ${cfg.extraConfig} ${forward} ''; @@ -38,28 +44,39 @@ in services.unbound = { enable = mkOption { - default = false; - description = "Whether to enable the Unbound domain name server."; + default = false; + type = types.bool; + description = "Whether to enable the Unbound domain name server."; }; allowedAccess = mkOption { - default = ["127.0.0.0/24"]; - description = "What networks are allowed to use unbound as a resolver."; + default = ["127.0.0.0/24"]; + type = types.listOf types.str; + description = "What networks are allowed to use unbound as a resolver."; }; interfaces = mkOption { - default = [ "127.0.0.1" "::1" ]; - description = "What addresses the server should listen on."; + default = [ "127.0.0.1" "::1" ]; + type = types.listOf types.str; + description = "What addresses the server should listen on."; }; forwardAddresses = mkOption { - default = [ ]; - description = "What servers to forward queries to."; + default = [ ]; + type = types.listOf types.str; + description = "What servers to forward queries to."; + }; + + enableRootTrustAnchor = mkOption { + default = true; + type = types.bool; + description = "Use and update root trust anchor for DNSSEC validation."; }; extraConfig = mkOption { - default = ""; - description = "Extra lines of unbound config."; + default = ""; + type = types.str; + description = "Extra lines of unbound config."; }; }; @@ -88,14 +105,15 @@ in preStart = '' mkdir -m 0755 -p ${stateDir}/dev/ - cp ${confFile} ${stateDir}/unbound.conf - chown unbound ${stateDir} - touch ${stateDir}/dev/random + cp ${confFile} ${stateDir}/unbound.conf + ${pkgs.unbound}/bin/unbound-anchor -a ${rootTrustAnchorFile} + chown unbound ${stateDir} ${rootTrustAnchorFile} + touch ${stateDir}/dev/random ${pkgs.utillinux}/bin/mount --bind -n /dev/random ${stateDir}/dev/random ''; serviceConfig = { - ExecStart = "${pkgs.unbound}/sbin/unbound -d -c ${stateDir}/unbound.conf"; + ExecStart = "${pkgs.unbound}/bin/unbound -d -c ${stateDir}/unbound.conf"; ExecStopPost="${pkgs.utillinux}/bin/umount ${stateDir}/dev/random"; }; }; diff --git a/nixos/modules/services/networking/wpa_supplicant.nix b/nixos/modules/services/networking/wpa_supplicant.nix index 1558c5832892..a8f445a2c73c 100644 --- a/nixos/modules/services/networking/wpa_supplicant.nix +++ b/nixos/modules/services/networking/wpa_supplicant.nix @@ -78,10 +78,11 @@ in { ''; default = {}; example = literalExample '' - echelon = { - psk = "abcdefgh"; - }; - "free.wifi" = {}; + { echelon = { + psk = "abcdefgh"; + }; + "free.wifi" = {}; + } ''; }; @@ -127,6 +128,7 @@ in { in { description = "WPA Supplicant"; + after = [ "network-interfaces.target" ]; wantedBy = [ "network.target" ]; path = [ pkgs.wpa_supplicant ]; diff --git a/nixos/modules/services/networking/zerotierone.nix b/nixos/modules/services/networking/zerotierone.nix index 886ea18d9809..6237f95b127b 100644 --- a/nixos/modules/services/networking/zerotierone.nix +++ b/nixos/modules/services/networking/zerotierone.nix @@ -21,10 +21,9 @@ in chown -R root:root /var/lib/zerotier-one ''; serviceConfig = { - Type = "forking"; - User = "root"; - PIDFile = "/var/lib/zerotier-one/zerotier-one.pid"; - ExecStart = "${pkgs.zerotierone}/bin/zerotier-one -d"; + ExecStart = "${pkgs.zerotierone}/bin/zerotier-one"; + Restart = "always"; + KillMode = "process"; }; }; environment.systemPackages = [ pkgs.zerotierone ]; |