at 21.11-pre 16 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 cfg = config.networking.networkmanager; 7 8 basePackages = with pkgs; [ 9 crda 10 modemmanager 11 networkmanager 12 networkmanager-fortisslvpn 13 networkmanager-iodine 14 networkmanager-l2tp 15 networkmanager-openconnect 16 networkmanager-openvpn 17 networkmanager-vpnc 18 networkmanager-sstp 19 ] ++ optional (!delegateWireless && !enableIwd) wpa_supplicant; 20 21 delegateWireless = config.networking.wireless.enable == true && cfg.unmanaged != []; 22 23 enableIwd = cfg.wifi.backend == "iwd"; 24 25 configFile = pkgs.writeText "NetworkManager.conf" '' 26 [main] 27 plugins=keyfile 28 dhcp=${cfg.dhcp} 29 dns=${cfg.dns} 30 # If resolvconf is disabled that means that resolv.conf is managed by some other module. 31 rc-manager=${if config.networking.resolvconf.enable then "resolvconf" else "unmanaged"} 32 33 [keyfile] 34 ${optionalString (cfg.unmanaged != []) 35 ''unmanaged-devices=${lib.concatStringsSep ";" cfg.unmanaged}''} 36 37 [logging] 38 level=${cfg.logLevel} 39 audit=${lib.boolToString config.security.audit.enable} 40 41 [connection] 42 ipv6.ip6-privacy=2 43 ethernet.cloned-mac-address=${cfg.ethernet.macAddress} 44 wifi.cloned-mac-address=${cfg.wifi.macAddress} 45 ${optionalString (cfg.wifi.powersave != null) 46 ''wifi.powersave=${if cfg.wifi.powersave then "3" else "2"}''} 47 48 [device] 49 wifi.scan-rand-mac-address=${if cfg.wifi.scanRandMacAddress then "yes" else "no"} 50 wifi.backend=${cfg.wifi.backend} 51 52 ${cfg.extraConfig} 53 ''; 54 55 /* 56 [network-manager] 57 Identity=unix-group:networkmanager 58 Action=org.freedesktop.NetworkManager.* 59 ResultAny=yes 60 ResultInactive=no 61 ResultActive=yes 62 63 [modem-manager] 64 Identity=unix-group:networkmanager 65 Action=org.freedesktop.ModemManager* 66 ResultAny=yes 67 ResultInactive=no 68 ResultActive=yes 69 */ 70 polkitConf = '' 71 polkit.addRule(function(action, subject) { 72 if ( 73 subject.isInGroup("networkmanager") 74 && (action.id.indexOf("org.freedesktop.NetworkManager.") == 0 75 || action.id.indexOf("org.freedesktop.ModemManager") == 0 76 )) 77 { return polkit.Result.YES; } 78 }); 79 ''; 80 81 ns = xs: pkgs.writeText "nameservers" ( 82 concatStrings (map (s: "nameserver ${s}\n") xs) 83 ); 84 85 overrideNameserversScript = pkgs.writeScript "02overridedns" '' 86 #!/bin/sh 87 PATH=${with pkgs; makeBinPath [ gnused gnugrep coreutils ]} 88 tmp=$(mktemp) 89 sed '/nameserver /d' /etc/resolv.conf > $tmp 90 grep 'nameserver ' /etc/resolv.conf | \ 91 grep -vf ${ns (cfg.appendNameservers ++ cfg.insertNameservers)} > $tmp.ns 92 cat $tmp ${ns cfg.insertNameservers} $tmp.ns ${ns cfg.appendNameservers} > /etc/resolv.conf 93 rm -f $tmp $tmp.ns 94 ''; 95 96 dispatcherTypesSubdirMap = { 97 basic = ""; 98 pre-up = "pre-up.d/"; 99 pre-down = "pre-down.d/"; 100 }; 101 102 macAddressOpt = mkOption { 103 type = types.either types.str (types.enum ["permanent" "preserve" "random" "stable"]); 104 default = "preserve"; 105 example = "00:11:22:33:44:55"; 106 description = '' 107 Set the MAC address of the interface. 108 <variablelist> 109 <varlistentry> 110 <term>"XX:XX:XX:XX:XX:XX"</term> 111 <listitem><para>MAC address of the interface</para></listitem> 112 </varlistentry> 113 <varlistentry> 114 <term><literal>"permanent"</literal></term> 115 <listitem><para>Use the permanent MAC address of the device</para></listitem> 116 </varlistentry> 117 <varlistentry> 118 <term><literal>"preserve"</literal></term> 119 <listitem><para>Dont change the MAC address of the device upon activation</para></listitem> 120 </varlistentry> 121 <varlistentry> 122 <term><literal>"random"</literal></term> 123 <listitem><para>Generate a randomized value upon each connect</para></listitem> 124 </varlistentry> 125 <varlistentry> 126 <term><literal>"stable"</literal></term> 127 <listitem><para>Generate a stable, hashed MAC address</para></listitem> 128 </varlistentry> 129 </variablelist> 130 ''; 131 }; 132 133in { 134 135 meta = { 136 maintainers = teams.freedesktop.members; 137 }; 138 139 ###### interface 140 141 options = { 142 143 networking.networkmanager = { 144 145 enable = mkOption { 146 type = types.bool; 147 default = false; 148 description = '' 149 Whether to use NetworkManager to obtain an IP address and other 150 configuration for all network interfaces that are not manually 151 configured. If enabled, a group <literal>networkmanager</literal> 152 will be created. Add all users that should have permission 153 to change network settings to this group. 154 ''; 155 }; 156 157 extraConfig = mkOption { 158 type = types.lines; 159 default = ""; 160 description = '' 161 Configuration appended to the generated NetworkManager.conf. 162 Refer to 163 <link xlink:href="https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html"> 164 https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html 165 </link> 166 or 167 <citerefentry> 168 <refentrytitle>NetworkManager.conf</refentrytitle> 169 <manvolnum>5</manvolnum> 170 </citerefentry> 171 for more information. 172 ''; 173 }; 174 175 unmanaged = mkOption { 176 type = types.listOf types.str; 177 default = []; 178 description = '' 179 List of interfaces that will not be managed by NetworkManager. 180 Interface name can be specified here, but if you need more fidelity, 181 refer to 182 <link xlink:href="https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html#device-spec"> 183 https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html#device-spec 184 </link> 185 or the "Device List Format" Appendix of 186 <citerefentry> 187 <refentrytitle>NetworkManager.conf</refentrytitle> 188 <manvolnum>5</manvolnum> 189 </citerefentry>. 190 ''; 191 }; 192 193 packages = mkOption { 194 type = types.listOf types.package; 195 default = [ ]; 196 description = '' 197 Extra packages that provide NetworkManager plugins. 198 ''; 199 apply = list: basePackages ++ list; 200 }; 201 202 dhcp = mkOption { 203 type = types.enum [ "dhclient" "dhcpcd" "internal" ]; 204 default = "internal"; 205 description = '' 206 Which program (or internal library) should be used for DHCP. 207 ''; 208 }; 209 210 logLevel = mkOption { 211 type = types.enum [ "OFF" "ERR" "WARN" "INFO" "DEBUG" "TRACE" ]; 212 default = "WARN"; 213 description = '' 214 Set the default logging verbosity level. 215 ''; 216 }; 217 218 appendNameservers = mkOption { 219 type = types.listOf types.str; 220 default = []; 221 description = '' 222 A list of name servers that should be appended 223 to the ones configured in NetworkManager or received by DHCP. 224 ''; 225 }; 226 227 insertNameservers = mkOption { 228 type = types.listOf types.str; 229 default = []; 230 description = '' 231 A list of name servers that should be inserted before 232 the ones configured in NetworkManager or received by DHCP. 233 ''; 234 }; 235 236 ethernet.macAddress = macAddressOpt; 237 238 wifi = { 239 macAddress = macAddressOpt; 240 241 backend = mkOption { 242 type = types.enum [ "wpa_supplicant" "iwd" ]; 243 default = "wpa_supplicant"; 244 description = '' 245 Specify the Wi-Fi backend used for the device. 246 Currently supported are <option>wpa_supplicant</option> or <option>iwd</option> (experimental). 247 ''; 248 }; 249 250 powersave = mkOption { 251 type = types.nullOr types.bool; 252 default = null; 253 description = '' 254 Whether to enable Wi-Fi power saving. 255 ''; 256 }; 257 258 scanRandMacAddress = mkOption { 259 type = types.bool; 260 default = true; 261 description = '' 262 Whether to enable MAC address randomization of a Wi-Fi device 263 during scanning. 264 ''; 265 }; 266 }; 267 268 dns = mkOption { 269 type = types.enum [ "default" "dnsmasq" "unbound" "systemd-resolved" "none" ]; 270 default = "default"; 271 description = '' 272 Set the DNS (<literal>resolv.conf</literal>) processing mode. 273 </para> 274 <para> 275 A description of these modes can be found in the main section of 276 <link xlink:href="https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html"> 277 https://developer.gnome.org/NetworkManager/stable/NetworkManager.conf.html 278 </link> 279 or in 280 <citerefentry> 281 <refentrytitle>NetworkManager.conf</refentrytitle> 282 <manvolnum>5</manvolnum> 283 </citerefentry>. 284 ''; 285 }; 286 287 dispatcherScripts = mkOption { 288 type = types.listOf (types.submodule { 289 options = { 290 source = mkOption { 291 type = types.path; 292 description = '' 293 Path to the hook script. 294 ''; 295 }; 296 297 type = mkOption { 298 type = types.enum (attrNames dispatcherTypesSubdirMap); 299 default = "basic"; 300 description = '' 301 Dispatcher hook type. Look up the hooks described at 302 <link xlink:href="https://developer.gnome.org/NetworkManager/stable/NetworkManager.html">https://developer.gnome.org/NetworkManager/stable/NetworkManager.html</link> 303 and choose the type depending on the output folder. 304 You should then filter the event type (e.g., "up"/"down") from within your script. 305 ''; 306 }; 307 }; 308 }); 309 default = []; 310 example = literalExample '' 311 [ { 312 source = pkgs.writeText "upHook" ''' 313 314 if [ "$2" != "up" ]; then 315 logger "exit: event $2 != up" 316 exit 317 fi 318 319 # coreutils and iproute are in PATH too 320 logger "Device $DEVICE_IFACE coming up" 321 '''; 322 type = "basic"; 323 } ]''; 324 description = '' 325 A list of scripts which will be executed in response to network events. 326 ''; 327 }; 328 329 enableStrongSwan = mkOption { 330 type = types.bool; 331 default = false; 332 description = '' 333 Enable the StrongSwan plugin. 334 </para><para> 335 If you enable this option the 336 <literal>networkmanager_strongswan</literal> plugin will be added to 337 the <option>networking.networkmanager.packages</option> option 338 so you don't need to to that yourself. 339 ''; 340 }; 341 }; 342 }; 343 344 imports = [ 345 (mkRenamedOptionModule [ "networking" "networkmanager" "useDnsmasq" ] [ "networking" "networkmanager" "dns" ]) 346 (mkRemovedOptionModule ["networking" "networkmanager" "dynamicHosts"] '' 347 This option was removed because allowing (multiple) regular users to 348 override host entries affecting the whole system opens up a huge attack 349 vector. There seem to be very rare cases where this might be useful. 350 Consider setting system-wide host entries using networking.hosts, provide 351 them via the DNS server in your network, or use environment.etc 352 to add a file into /etc/NetworkManager/dnsmasq.d reconfiguring hostsdir. 353 '') 354 ]; 355 356 357 ###### implementation 358 359 config = mkIf cfg.enable { 360 361 assertions = [ 362 { assertion = config.networking.wireless.enable == true -> cfg.unmanaged != []; 363 message = '' 364 You can not use networking.networkmanager with networking.wireless. 365 Except if you mark some interfaces as <literal>unmanaged</literal> by NetworkManager. 366 ''; 367 } 368 ]; 369 370 environment.etc = with pkgs; { 371 "NetworkManager/NetworkManager.conf".source = configFile; 372 373 "NetworkManager/VPN/nm-openvpn-service.name".source = 374 "${networkmanager-openvpn}/lib/NetworkManager/VPN/nm-openvpn-service.name"; 375 376 "NetworkManager/VPN/nm-vpnc-service.name".source = 377 "${networkmanager-vpnc}/lib/NetworkManager/VPN/nm-vpnc-service.name"; 378 379 "NetworkManager/VPN/nm-openconnect-service.name".source = 380 "${networkmanager-openconnect}/lib/NetworkManager/VPN/nm-openconnect-service.name"; 381 382 "NetworkManager/VPN/nm-fortisslvpn-service.name".source = 383 "${networkmanager-fortisslvpn}/lib/NetworkManager/VPN/nm-fortisslvpn-service.name"; 384 385 "NetworkManager/VPN/nm-l2tp-service.name".source = 386 "${networkmanager-l2tp}/lib/NetworkManager/VPN/nm-l2tp-service.name"; 387 388 "NetworkManager/VPN/nm-iodine-service.name".source = 389 "${networkmanager-iodine}/lib/NetworkManager/VPN/nm-iodine-service.name"; 390 391 "NetworkManager/VPN/nm-sstp-service.name".source = 392 "${networkmanager-sstp}/lib/NetworkManager/VPN/nm-sstp-service.name"; 393 } 394 // optionalAttrs (cfg.appendNameservers != [] || cfg.insertNameservers != []) 395 { 396 "NetworkManager/dispatcher.d/02overridedns".source = overrideNameserversScript; 397 } 398 // optionalAttrs cfg.enableStrongSwan 399 { 400 "NetworkManager/VPN/nm-strongswan-service.name".source = 401 "${pkgs.networkmanager_strongswan}/lib/NetworkManager/VPN/nm-strongswan-service.name"; 402 } 403 // listToAttrs (lib.imap1 (i: s: 404 { 405 name = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}"; 406 value = { mode = "0544"; inherit (s) source; }; 407 }) cfg.dispatcherScripts); 408 409 environment.systemPackages = cfg.packages; 410 411 users.groups = { 412 networkmanager.gid = config.ids.gids.networkmanager; 413 nm-openvpn.gid = config.ids.gids.nm-openvpn; 414 }; 415 416 users.users = { 417 nm-openvpn = { 418 uid = config.ids.uids.nm-openvpn; 419 extraGroups = [ "networkmanager" ]; 420 }; 421 nm-iodine = { 422 isSystemUser = true; 423 group = "networkmanager"; 424 }; 425 }; 426 427 systemd.packages = cfg.packages; 428 429 systemd.tmpfiles.rules = [ 430 "d /etc/NetworkManager/system-connections 0700 root root -" 431 "d /etc/ipsec.d 0700 root root -" 432 "d /var/lib/NetworkManager-fortisslvpn 0700 root root -" 433 434 "d /var/lib/dhclient 0755 root root -" 435 "d /var/lib/misc 0755 root root -" # for dnsmasq.leases 436 ]; 437 438 systemd.services.NetworkManager = { 439 wantedBy = [ "network.target" ]; 440 restartTriggers = [ configFile ]; 441 442 aliases = [ "dbus-org.freedesktop.NetworkManager.service" ]; 443 444 serviceConfig = { 445 StateDirectory = "NetworkManager"; 446 StateDirectoryMode = 755; # not sure if this really needs to be 755 447 }; 448 }; 449 450 systemd.services.NetworkManager-wait-online = { 451 wantedBy = [ "network-online.target" ]; 452 }; 453 454 systemd.services.ModemManager.aliases = [ "dbus-org.freedesktop.ModemManager1.service" ]; 455 456 # override unit as recommended by upstream - see https://github.com/NixOS/nixpkgs/issues/88089 457 # TODO: keep an eye on modem-manager releases as this will eventually be added to the upstream unit 458 systemd.services.ModemManager.serviceConfig.ExecStart = [ 459 "" 460 "${pkgs.modemmanager}/sbin/ModemManager --filter-policy=STRICT" 461 ]; 462 463 systemd.services.NetworkManager-dispatcher = { 464 wantedBy = [ "network.target" ]; 465 restartTriggers = [ configFile overrideNameserversScript ]; 466 467 # useful binaries for user-specified hooks 468 path = [ pkgs.iproute2 pkgs.util-linux pkgs.coreutils ]; 469 aliases = [ "dbus-org.freedesktop.nm-dispatcher.service" ]; 470 }; 471 472 # Turn off NixOS' network management when networking is managed entirely by NetworkManager 473 networking = mkMerge [ 474 (mkIf (!delegateWireless) { 475 useDHCP = false; 476 }) 477 478 (mkIf cfg.enableStrongSwan { 479 networkmanager.packages = [ pkgs.networkmanager_strongswan ]; 480 }) 481 482 (mkIf enableIwd { 483 wireless.iwd.enable = true; 484 }) 485 ]; 486 487 boot.kernelModules = [ "ctr" ]; 488 489 security.polkit.extraConfig = polkitConf; 490 491 services.dbus.packages = cfg.packages 492 ++ optional cfg.enableStrongSwan pkgs.strongswanNM 493 ++ optional (cfg.dns == "dnsmasq") pkgs.dnsmasq; 494 495 services.udev.packages = cfg.packages; 496 }; 497}