summary refs log tree commit diff
path: root/nixos/modules/tasks/network-interfaces.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/tasks/network-interfaces.nix')
-rw-r--r--nixos/modules/tasks/network-interfaces.nix161
1 files changed, 113 insertions, 48 deletions
diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix
index af98123d477..879f077332e 100644
--- a/nixos/modules/tasks/network-interfaces.nix
+++ b/nixos/modules/tasks/network-interfaces.nix
@@ -144,33 +144,20 @@ let
       };
 
       tempAddress = mkOption {
-        type = types.enum [ "default" "enabled" "disabled" ];
-        default = if cfg.enableIPv6 then "default" else "disabled";
-        defaultText = literalExample ''if cfg.enableIPv6 then "default" else "disabled"'';
+        type = types.enum (lib.attrNames tempaddrValues);
+        default = cfg.tempAddresses;
+        defaultText = literalExample ''config.networking.tempAddresses'';
         description = ''
           When IPv6 is enabled with SLAAC, this option controls the use of
-          temporary address (aka privacy extensions). This is used to reduce tracking.
-          The three possible values are:
-
-          <itemizedlist>
-           <listitem>
-            <para>
-             <literal>"default"</literal> to generate temporary addresses and use
-             them by default;
-            </para>
-           </listitem>
-           <listitem>
-            <para>
-             <literal>"enabled"</literal> to generate temporary addresses but keep
-             using the standard EUI-64 ones by default;
-            </para>
-           </listitem>
-           <listitem>
-            <para>
-             <literal>"disabled"</literal> to completely disable temporary addresses.
-            </para>
-           </listitem>
-          </itemizedlist>
+          temporary address (aka privacy extensions) on this
+          interface. This is used to reduce tracking.
+
+          See also the global option
+          <xref linkend="opt-networking.tempAddresses"/>, which
+          applies to all interfaces where this is not set.
+
+          Possible values are:
+          ${tempaddrDoc}
         '';
       };
 
@@ -366,6 +353,32 @@ let
 
   isHexString = s: all (c: elem c hexChars) (stringToCharacters (toLower s));
 
+  tempaddrValues = {
+    disabled = {
+      sysctl = "0";
+      description = "completely disable IPv6 temporary addresses";
+    };
+    enabled = {
+      sysctl = "1";
+      description = "generate IPv6 temporary addresses but still use EUI-64 addresses as source addresses";
+    };
+    default = {
+      sysctl = "2";
+      description = "generate IPv6 temporary addresses and use these as source addresses in routing";
+    };
+  };
+  tempaddrDoc = ''
+    <itemizedlist>
+     ${concatStringsSep "\n" (mapAttrsToList (name: { description, ... }: ''
+       <listitem>
+         <para>
+           <literal>"${name}"</literal> to ${description};
+         </para>
+       </listitem>
+     '') tempaddrValues)}
+    </itemizedlist>
+  '';
+
 in
 
 {
@@ -381,15 +394,38 @@ in
       # syntax). Note: We also allow underscores for compatibility/legacy
       # reasons (as undocumented feature):
       type = types.strMatching
-        "^$|^[[:alpha:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$";
+        "^$|^[[:alnum:]]([[:alnum:]_-]{0,61}[[:alnum:]])?$";
       description = ''
         The name of the machine. Leave it empty if you want to obtain it from a
         DHCP server (if using DHCP). The hostname must be a valid DNS label (see
-        RFC 1035 section 2.3.1: "Preferred name syntax") and as such must not
-        contain the domain part. This means that the hostname must start with a
-        letter, end with a letter or digit, and have as interior characters only
+        RFC 1035 section 2.3.1: "Preferred name syntax", RFC 1123 section 2.1:
+        "Host Names and Numbers") and as such must not contain the domain part.
+        This means that the hostname must start with a letter or digit,
+        end with a letter or digit, and have as interior characters only
         letters, digits, and hyphen. The maximum length is 63 characters.
         Additionally it is recommended to only use lower-case characters.
+        If (e.g. for legacy reasons) a FQDN is required as the Linux kernel
+        network node hostname (uname --nodename) the option
+        boot.kernel.sysctl."kernel.hostname" can be used as a workaround (but
+        the 64 character limit still applies).
+      '';
+    };
+
+    networking.fqdn = mkOption {
+      readOnly = true;
+      type = types.str;
+      default = if (cfg.hostName != "" && cfg.domain != null)
+        then "${cfg.hostName}.${cfg.domain}"
+        else throw ''
+          The FQDN is required but cannot be determined. Please make sure that
+          both networking.hostName and networking.domain are set properly.
+        '';
+      defaultText = literalExample ''''${networking.hostName}.''${networking.domain}'';
+      description = ''
+        The fully qualified domain name (FQDN) of this host. It is the result
+        of combining networking.hostName and networking.domain. Using this
+        option will result in an evaluation error if the hostname is empty or
+        no domain is specified.
       '';
     };
 
@@ -469,7 +505,7 @@ in
 
     networking.search = mkOption {
       default = [];
-      example = [ "example.com" "local.domain" ];
+      example = [ "example.com" "home.arpa" ];
       type = types.listOf types.str;
       description = ''
         The list of search paths used when resolving domain names.
@@ -478,7 +514,7 @@ in
 
     networking.domain = mkOption {
       default = null;
-      example = "home";
+      example = "home.arpa";
       type = types.nullOr types.str;
       description = ''
         The domain.  It can be left empty if it is auto-detected through DHCP.
@@ -519,7 +555,7 @@ in
         <option>networking.useDHCP</option> is true, then every
         interface not listed here will be configured using DHCP.
       '';
-      type = with types; loaOf (submodule interfaceOpts);
+      type = with types; attrsOf (submodule interfaceOpts);
     };
 
     networking.vswitches = mkOption {
@@ -544,7 +580,7 @@ in
           interfaces = mkOption {
             example = [ "eth0" "eth1" ];
             description = "The physical network interfaces connected by the vSwitch.";
-            type = with types; loaOf (submodule vswitchInterfaceOpts);
+            type = with types; attrsOf (submodule vswitchInterfaceOpts);
           };
 
           controllers = mkOption {
@@ -1016,6 +1052,21 @@ in
       '';
     };
 
+    networking.tempAddresses = mkOption {
+      default = if cfg.enableIPv6 then "default" else "disabled";
+      type = types.enum (lib.attrNames tempaddrValues);
+      description = ''
+        Whether to enable IPv6 Privacy Extensions for interfaces not
+        configured explicitly in
+        <xref linkend="opt-networking.interfaces._name_.tempAddress" />.
+
+        This sets the ipv6.conf.*.use_tempaddr sysctl for all
+        interfaces. Possible values are:
+
+        ${tempaddrDoc}
+      '';
+    };
+
   };
 
 
@@ -1057,7 +1108,6 @@ in
       ];
 
     boot.kernelModules = [ ]
-      ++ optional cfg.enableIPv6 "ipv6"
       ++ optional hasVirtuals "tun"
       ++ optional hasSits "sit"
       ++ optional hasBonds "bonding";
@@ -1076,7 +1126,7 @@ in
       // listToAttrs (forEach interfaces
         (i: let
           opt = i.tempAddress;
-          val = { disabled = 0; enabled = 1; default = 2; }.${opt};
+          val = tempaddrValues.${opt}.sysctl;
          in nameValuePair "net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr" val));
 
     # Capabilities won't work unless we have at-least a 4.3 Linux
@@ -1089,6 +1139,21 @@ in
     } else {
       ping.source = "${pkgs.iputils.out}/bin/ping";
     };
+    security.apparmor.policies."bin.ping".profile = lib.mkIf config.security.apparmor.policies."bin.ping".enable (lib.mkAfter ''
+      /run/wrappers/bin/ping {
+        include <abstractions/base>
+        include <nixos/security.wrappers>
+        rpx /run/wrappers/wrappers.*/ping,
+      }
+      /run/wrappers/wrappers.*/ping {
+        include <abstractions/base>
+        include <nixos/security.wrappers>
+        r /run/wrappers/wrappers.*/ping.real,
+        mrpx ${config.security.wrappers.ping.source},
+        capability net_raw,
+        capability setpcap,
+      }
+    '');
 
     # Set the host and domain names in the activation script.  Don't
     # clear it if it's not configured in the NixOS configuration,
@@ -1122,7 +1187,7 @@ in
 
     environment.systemPackages =
       [ pkgs.host
-        pkgs.iproute
+        pkgs.iproute2
         pkgs.iputils
         pkgs.nettools
       ]
@@ -1149,7 +1214,7 @@ in
         wantedBy = [ "network.target" ];
         after = [ "network-pre.target" ];
         unitConfig.ConditionCapability = "CAP_NET_ADMIN";
-        path = [ pkgs.iproute ];
+        path = [ pkgs.iproute2 ];
         serviceConfig.Type = "oneshot";
         serviceConfig.RemainAfterExit = true;
         script = ''
@@ -1166,9 +1231,11 @@ in
       (pkgs.writeTextFile rec {
         name = "ipv6-privacy-extensions.rules";
         destination = "/etc/udev/rules.d/98-${name}";
-        text = ''
+        text = let
+          sysctl-value = tempaddrValues.${cfg.tempAddresses}.sysctl;
+        in ''
           # enable and prefer IPv6 privacy addresses by default
-          ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.bash}/bin/sh -c 'echo 2 > /proc/sys/net/ipv6/conf/%k/use_tempaddr'"
+          ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.bash}/bin/sh -c 'echo ${sysctl-value} > /proc/sys/net/ipv6/conf/%k/use_tempaddr'"
         '';
       })
       (pkgs.writeTextFile rec {
@@ -1177,15 +1244,13 @@ in
         text = concatMapStrings (i:
           let
             opt = i.tempAddress;
-            val = if opt == "disabled" then 0 else 1;
-            msg = if opt == "disabled"
-                  then "completely disable IPv6 privacy addresses"
-                  else "enable IPv6 privacy addresses but prefer EUI-64 addresses";
+            val = tempaddrValues.${opt}.sysctl;
+            msg = tempaddrValues.${opt}.description;
           in
           ''
             # override to ${msg} for ${i.name}
-            ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr=${toString val}"
-          '') (filter (i: i.tempAddress != "default") interfaces);
+            ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${replaceChars ["."] ["/"] i.name}.use_tempaddr=${val}"
+          '') (filter (i: i.tempAddress != cfg.tempAddresses) interfaces);
       })
     ] ++ lib.optional (cfg.wlanInterfaces != {})
       (pkgs.writeTextFile {
@@ -1227,7 +1292,7 @@ in
               ${optionalString (current.type == "mesh" && current.meshID!=null) "${pkgs.iw}/bin/iw dev ${device} set meshid ${current.meshID}"}
               ${optionalString (current.type == "monitor" && current.flags!=null) "${pkgs.iw}/bin/iw dev ${device} set monitor ${current.flags}"}
               ${optionalString (current.type == "managed" && current.fourAddr!=null) "${pkgs.iw}/bin/iw dev ${device} set 4addr ${if current.fourAddr then "on" else "off"}"}
-              ${optionalString (current.mac != null) "${pkgs.iproute}/bin/ip link set dev ${device} address ${current.mac}"}
+              ${optionalString (current.mac != null) "${pkgs.iproute2}/bin/ip link set dev ${device} address ${current.mac}"}
             '';
 
             # Udev script to execute for a new WLAN interface. The script configures the new WLAN interface.
@@ -1238,11 +1303,11 @@ in
               ${optionalString (new.type == "mesh" && new.meshID!=null) "${pkgs.iw}/bin/iw dev ${device} set meshid ${new.meshID}"}
               ${optionalString (new.type == "monitor" && new.flags!=null) "${pkgs.iw}/bin/iw dev ${device} set monitor ${new.flags}"}
               ${optionalString (new.type == "managed" && new.fourAddr!=null) "${pkgs.iw}/bin/iw dev ${device} set 4addr ${if new.fourAddr then "on" else "off"}"}
-              ${optionalString (new.mac != null) "${pkgs.iproute}/bin/ip link set dev ${device} address ${new.mac}"}
+              ${optionalString (new.mac != null) "${pkgs.iproute2}/bin/ip link set dev ${device} address ${new.mac}"}
             '';
 
             # Udev attributes for systemd to name the device and to create a .device target.
-            systemdAttrs = n: ''NAME:="${n}", ENV{INTERFACE}:="${n}", ENV{SYSTEMD_ALIAS}:="/sys/subsystem/net/devices/${n}", TAG+="systemd"'';
+            systemdAttrs = n: ''NAME:="${n}", ENV{INTERFACE}="${n}", ENV{SYSTEMD_ALIAS}="/sys/subsystem/net/devices/${n}", TAG+="systemd"'';
           in
           flip (concatMapStringsSep "\n") (attrNames wlanDeviceInterfaces) (device:
             let