diff --git a/nixos/modules/system/boot/networkd.nix b/nixos/modules/system/boot/networkd.nix index dba90620719c..bc6c9166b956 100644 --- a/nixos/modules/system/boot/networkd.nix +++ b/nixos/modules/system/boot/networkd.nix @@ -1884,6 +1884,11 @@ let networkdOptions = { networkConfig = mkOption { default = { }; + defaultText = lib.literalExpression '' + { + IPv6PrivacyExtensions = true; + } + ''; example = { SpeedMeter = true; ManageForeignRoutingPolicyRules = false; @@ -3127,7 +3132,10 @@ let }; config = { - networkConfig = optionalAttrs (config.routeTables != { }) { + networkConfig = { + IPv6PrivacyExtensions = lib.mkOptionDefault true; + } + // optionalAttrs (config.routeTables != { }) { RouteTable = mapAttrsToList (name: number: "${name}:${toString number}") config.routeTables; }; }; diff --git a/nixos/modules/tasks/network-interfaces.nix b/nixos/modules/tasks/network-interfaces.nix index d056cd45655b..6f4ef6492026 100644 --- a/nixos/modules/tasks/network-interfaces.nix +++ b/nixos/modules/tasks/network-interfaces.nix @@ -1813,146 +1813,147 @@ in virtualisation.vswitch = mkIf (cfg.vswitches != { }) { enable = true; }; - services.udev.packages = [ - (pkgs.writeTextFile rec { - name = "ipv6-privacy-extensions.rules"; - destination = "/etc/udev/rules.d/98-${name}"; - 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 ${sysctl-value} > /proc/sys/net/ipv6/conf/$name/use_tempaddr'" - ''; - }) - (pkgs.writeTextFile rec { - name = "ipv6-privacy-extensions.rules"; - destination = "/etc/udev/rules.d/99-${name}"; - text = concatMapStrings ( - i: - let - opt = i.tempAddress; - val = tempaddrValues.${opt}.sysctl; - msg = tempaddrValues.${opt}.description; - in - '' - # override to ${msg} for ${i.name} - ACTION=="add", SUBSYSTEM=="net", NAME=="${i.name}", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${ - replaceStrings [ "." ] [ "/" ] i.name - }.use_tempaddr=${val}" - '' - ) (filter (i: i.tempAddress != cfg.tempAddresses) interfaces); - }) - ] - ++ lib.optional (cfg.wlanInterfaces != { }) ( - pkgs.writeTextFile { - name = "99-zzz-40-wlanInterfaces.rules"; - destination = "/etc/udev/rules.d/99-zzz-40-wlanInterfaces.rules"; - text = - let - # Collect all interfaces that are defined for a device - # as device:interface key:value pairs. - wlanDeviceInterfaces = - let - allDevices = unique (mapAttrsToList (_: v: v.device) cfg.wlanInterfaces); - interfacesOfDevice = d: filterAttrs (_: v: v.device == d) cfg.wlanInterfaces; - in - genAttrs allDevices (d: interfacesOfDevice d); - - # Convert device:interface key:value pairs into a list, and if it exists, - # place the interface which is named after the device at the beginning. - wlanListDeviceFirst = - device: interfaces: - if hasAttr device interfaces then - mapAttrsToList (n: v: v // { _iName = n; }) (filterAttrs (n: _: n == device) interfaces) - ++ mapAttrsToList (n: v: v // { _iName = n; }) (filterAttrs (n: _: n != device) interfaces) - else - mapAttrsToList (n: v: v // { _iName = n; }) interfaces; - - # Udev script to execute for the default WLAN interface with the persistend udev name. - # The script creates the required, new WLAN interfaces interfaces and configures the - # existing, default interface. - curInterfaceScript = - device: current: new: - pkgs.writeScript "udev-run-script-wlan-interfaces-${device}.sh" '' - #!${pkgs.runtimeShell} - # Change the wireless phy device to a predictable name. - ${pkgs.iw}/bin/iw phy `${pkgs.coreutils}/bin/cat /sys/class/net/$INTERFACE/phy80211/name` set name ${device} - - # Add new WLAN interfaces - ${flip concatMapStrings new (i: '' - ${pkgs.iw}/bin/iw phy ${device} interface add ${i._iName} type managed - '')} - - # Configure the current interface - ${pkgs.iw}/bin/iw dev ${device} set type ${current.type} - ${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.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. - newInterfaceScript = - new: - pkgs.writeScript "udev-run-script-wlan-interfaces-${new._iName}.sh" '' - #!${pkgs.runtimeShell} - # Configure the new interface - ${pkgs.iw}/bin/iw dev ${new._iName} set type ${new.type} - ${optionalString ( - new.type == "mesh" && new.meshID != null - ) "${pkgs.iw}/bin/iw dev ${new._iName} set meshid ${new.meshID}"} - ${optionalString ( - new.type == "monitor" && new.flags != null - ) "${pkgs.iw}/bin/iw dev ${new._iName} set monitor ${new.flags}"} - ${optionalString ( - new.type == "managed" && new.fourAddr != null - ) "${pkgs.iw}/bin/iw dev ${new._iName} set 4addr ${if new.fourAddr then "on" else "off"}"} - ${optionalString ( - new.mac != null - ) "${pkgs.iproute2}/bin/ip link set dev ${new._iName} 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"''; - in - flip (concatMapStringsSep "\n") (attrNames wlanDeviceInterfaces) ( - device: + services.udev.packages = + lib.optionals (!config.systemd.network.enable) [ + (pkgs.writeTextFile rec { + name = "ipv6-privacy-extensions.rules"; + destination = "/etc/udev/rules.d/98-${name}"; + text = let - interfaces = wlanListDeviceFirst device wlanDeviceInterfaces.${device}; - curInterface = elemAt interfaces 0; - newInterfaces = drop 1 interfaces; + sysctl-value = tempaddrValues.${cfg.tempAddresses}.sysctl; in '' - # It is important to have that rule first as overwriting the NAME attribute also prevents the - # next rules from matching. - ${flip (concatMapStringsSep "\n") (wlanListDeviceFirst device wlanDeviceInterfaces.${device}) ( - interface: - ''ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", ENV{INTERFACE}=="${interface._iName}", ${systemdAttrs interface._iName}, RUN+="${newInterfaceScript interface}"'' - )} - - # Add the required, new WLAN interfaces to the default WLAN interface with the - # persistent, default name as assigned by udev. - ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", NAME=="${device}", ${systemdAttrs curInterface._iName}, RUN+="${ - curInterfaceScript device curInterface newInterfaces - }" - # Generate the same systemd events for both 'add' and 'move' udev events. - ACTION=="move", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", NAME=="${device}", ${systemdAttrs curInterface._iName} + # enable and prefer IPv6 privacy addresses by default + ACTION=="add", SUBSYSTEM=="net", RUN+="${pkgs.bash}/bin/sh -c 'echo ${sysctl-value} > /proc/sys/net/ipv6/conf/$name/use_tempaddr'" + ''; + }) + (pkgs.writeTextFile rec { + name = "ipv6-privacy-extensions.rules"; + destination = "/etc/udev/rules.d/99-${name}"; + text = concatMapStrings ( + i: + let + opt = i.tempAddress; + val = tempaddrValues.${opt}.sysctl; + msg = tempaddrValues.${opt}.description; + in '' - ); - } - ); + # override to ${msg} for ${i.name} + ACTION=="add", SUBSYSTEM=="net", NAME=="${i.name}", RUN+="${pkgs.procps}/bin/sysctl net.ipv6.conf.${ + replaceStrings [ "." ] [ "/" ] i.name + }.use_tempaddr=${val}" + '' + ) (filter (i: i.tempAddress != cfg.tempAddresses) interfaces); + }) + ] + ++ lib.optional (cfg.wlanInterfaces != { }) ( + pkgs.writeTextFile { + name = "99-zzz-40-wlanInterfaces.rules"; + destination = "/etc/udev/rules.d/99-zzz-40-wlanInterfaces.rules"; + text = + let + # Collect all interfaces that are defined for a device + # as device:interface key:value pairs. + wlanDeviceInterfaces = + let + allDevices = unique (mapAttrsToList (_: v: v.device) cfg.wlanInterfaces); + interfacesOfDevice = d: filterAttrs (_: v: v.device == d) cfg.wlanInterfaces; + in + genAttrs allDevices (d: interfacesOfDevice d); + + # Convert device:interface key:value pairs into a list, and if it exists, + # place the interface which is named after the device at the beginning. + wlanListDeviceFirst = + device: interfaces: + if hasAttr device interfaces then + mapAttrsToList (n: v: v // { _iName = n; }) (filterAttrs (n: _: n == device) interfaces) + ++ mapAttrsToList (n: v: v // { _iName = n; }) (filterAttrs (n: _: n != device) interfaces) + else + mapAttrsToList (n: v: v // { _iName = n; }) interfaces; + + # Udev script to execute for the default WLAN interface with the persistend udev name. + # The script creates the required, new WLAN interfaces interfaces and configures the + # existing, default interface. + curInterfaceScript = + device: current: new: + pkgs.writeScript "udev-run-script-wlan-interfaces-${device}.sh" '' + #!${pkgs.runtimeShell} + # Change the wireless phy device to a predictable name. + ${pkgs.iw}/bin/iw phy `${pkgs.coreutils}/bin/cat /sys/class/net/$INTERFACE/phy80211/name` set name ${device} + + # Add new WLAN interfaces + ${flip concatMapStrings new (i: '' + ${pkgs.iw}/bin/iw phy ${device} interface add ${i._iName} type managed + '')} + + # Configure the current interface + ${pkgs.iw}/bin/iw dev ${device} set type ${current.type} + ${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.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. + newInterfaceScript = + new: + pkgs.writeScript "udev-run-script-wlan-interfaces-${new._iName}.sh" '' + #!${pkgs.runtimeShell} + # Configure the new interface + ${pkgs.iw}/bin/iw dev ${new._iName} set type ${new.type} + ${optionalString ( + new.type == "mesh" && new.meshID != null + ) "${pkgs.iw}/bin/iw dev ${new._iName} set meshid ${new.meshID}"} + ${optionalString ( + new.type == "monitor" && new.flags != null + ) "${pkgs.iw}/bin/iw dev ${new._iName} set monitor ${new.flags}"} + ${optionalString ( + new.type == "managed" && new.fourAddr != null + ) "${pkgs.iw}/bin/iw dev ${new._iName} set 4addr ${if new.fourAddr then "on" else "off"}"} + ${optionalString ( + new.mac != null + ) "${pkgs.iproute2}/bin/ip link set dev ${new._iName} 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"''; + in + flip (concatMapStringsSep "\n") (attrNames wlanDeviceInterfaces) ( + device: + let + interfaces = wlanListDeviceFirst device wlanDeviceInterfaces.${device}; + curInterface = elemAt interfaces 0; + newInterfaces = drop 1 interfaces; + in + '' + # It is important to have that rule first as overwriting the NAME attribute also prevents the + # next rules from matching. + ${flip (concatMapStringsSep "\n") (wlanListDeviceFirst device wlanDeviceInterfaces.${device}) ( + interface: + ''ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", ENV{INTERFACE}=="${interface._iName}", ${systemdAttrs interface._iName}, RUN+="${newInterfaceScript interface}"'' + )} + + # Add the required, new WLAN interfaces to the default WLAN interface with the + # persistent, default name as assigned by udev. + ACTION=="add", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", NAME=="${device}", ${systemdAttrs curInterface._iName}, RUN+="${ + curInterfaceScript device curInterface newInterfaces + }" + # Generate the same systemd events for both 'add' and 'move' udev events. + ACTION=="move", SUBSYSTEM=="net", ENV{DEVTYPE}=="wlan", NAME=="${device}", ${systemdAttrs curInterface._iName} + '' + ); + } + ); }; }