1{ config, lib, pkgs, ... }: 2 3with pkgs; 4with lib; 5 6let 7 cfg = config.networking.networkmanager; 8 9 # /var/lib/misc is for dnsmasq.leases. 10 stateDirs = "/var/lib/NetworkManager /var/lib/dhclient /var/lib/misc"; 11 12 configFile = writeText "NetworkManager.conf" '' 13 [main] 14 plugins=keyfile 15 16 [keyfile] 17 ${optionalString (config.networking.hostName != "") 18 ''hostname=${config.networking.hostName}''} 19 ${optionalString (cfg.unmanaged != []) 20 ''unmanaged-devices=${lib.concatStringsSep ";" cfg.unmanaged}''} 21 22 [logging] 23 level=WARN 24 ''; 25 26 /* 27 [network-manager] 28 Identity=unix-group:networkmanager 29 Action=org.freedesktop.NetworkManager.* 30 ResultAny=yes 31 ResultInactive=no 32 ResultActive=yes 33 34 [modem-manager] 35 Identity=unix-group:networkmanager 36 Action=org.freedesktop.ModemManager* 37 ResultAny=yes 38 ResultInactive=no 39 ResultActive=yes 40 */ 41 polkitConf = '' 42 polkit.addRule(function(action, subject) { 43 if ( 44 subject.isInGroup("networkmanager") 45 && (action.id.indexOf("org.freedesktop.NetworkManager.") == 0 46 || action.id.indexOf("org.freedesktop.ModemManager") == 0 47 )) 48 { return polkit.Result.YES; } 49 }); 50 ''; 51 52 ipUpScript = writeScript "01nixos-ip-up" '' 53 #!/bin/sh 54 if test "$2" = "up"; then 55 ${config.systemd.package}/bin/systemctl start ip-up.target 56 ${config.systemd.package}/bin/systemctl start network-online.target 57 fi 58 ''; 59 60 ns = xs: writeText "nameservers" ( 61 concatStrings (map (s: "nameserver ${s}\n") xs) 62 ); 63 64 overrideNameserversScript = writeScript "02overridedns" '' 65 #!/bin/sh 66 tmp=`${coreutils}/bin/mktemp` 67 ${gnused}/bin/sed '/nameserver /d' /etc/resolv.conf > $tmp 68 ${gnugrep}/bin/grep 'nameserver ' /etc/resolv.conf | \ 69 ${gnugrep}/bin/grep -vf ${ns (cfg.appendNameservers ++ cfg.insertNameservers)} > $tmp.ns 70 ${optionalString (cfg.appendNameservers != []) "${coreutils}/bin/cat $tmp $tmp.ns ${ns cfg.appendNameservers} > /etc/resolv.conf"} 71 ${optionalString (cfg.insertNameservers != []) "${coreutils}/bin/cat $tmp ${ns cfg.insertNameservers} $tmp.ns > /etc/resolv.conf"} 72 ${coreutils}/bin/rm -f $tmp $tmp.ns 73 ''; 74 75 dispatcherTypesSubdirMap = { 76 "basic" = ""; 77 "pre-up" = "pre-up.d/"; 78 "pre-down" = "pre-down.d/"; 79 }; 80 81in { 82 83 ###### interface 84 85 options = { 86 87 networking.networkmanager = { 88 89 enable = mkOption { 90 type = types.bool; 91 default = false; 92 description = '' 93 Whether to use NetworkManager to obtain an IP address and other 94 configuration for all network interfaces that are not manually 95 configured. If enabled, a group <literal>networkmanager</literal> 96 will be created. Add all users that should have permission 97 to change network settings to this group. 98 ''; 99 }; 100 101 unmanaged = mkOption { 102 type = types.listOf types.string; 103 default = []; 104 description = '' 105 List of interfaces that will not be managed by NetworkManager. 106 Interface name can be specified here, but if you need more fidelity 107 see "Device List Format" in NetworkManager.conf man page. 108 ''; 109 }; 110 111 # Ugly hack for using the correct gnome3 packageSet 112 basePackages = mkOption { 113 type = types.attrsOf types.package; 114 default = { inherit networkmanager modemmanager wpa_supplicant 115 networkmanager_openvpn networkmanager_vpnc 116 networkmanager_openconnect 117 networkmanager_pptp networkmanager_l2tp; }; 118 internal = true; 119 }; 120 121 packages = mkOption { 122 type = types.listOf types.path; 123 default = [ ]; 124 description = '' 125 Extra packages that provide NetworkManager plugins. 126 ''; 127 apply = list: (attrValues cfg.basePackages) ++ list; 128 }; 129 130 appendNameservers = mkOption { 131 type = types.listOf types.str; 132 default = []; 133 description = '' 134 A list of name servers that should be appended 135 to the ones configured in NetworkManager or received by DHCP. 136 ''; 137 }; 138 139 insertNameservers = mkOption { 140 type = types.listOf types.str; 141 default = []; 142 description = '' 143 A list of name servers that should be inserted before 144 the ones configured in NetworkManager or received by DHCP. 145 ''; 146 }; 147 148 dispatcherScripts = mkOption { 149 type = types.listOf (types.submodule { 150 options = { 151 source = mkOption { 152 type = types.str; 153 description = '' 154 A script source. 155 ''; 156 }; 157 158 type = mkOption { 159 type = types.enum (attrNames dispatcherTypesSubdirMap); 160 default = "basic"; 161 description = '' 162 Dispatcher hook type. Only basic hooks are currently available. 163 ''; 164 }; 165 }; 166 }); 167 default = []; 168 description = '' 169 A list of scripts which will be executed in response to network events. 170 ''; 171 }; 172 }; 173 }; 174 175 176 ###### implementation 177 178 config = mkIf cfg.enable { 179 180 assertions = [{ 181 assertion = config.networking.wireless.enable == false; 182 message = "You can not use networking.networkmanager with services.networking.wireless"; 183 }]; 184 185 boot.kernelModules = [ "ppp_mppe" ]; # Needed for most (all?) PPTP VPN connections. 186 187 environment.etc = with cfg.basePackages; [ 188 { source = ipUpScript; 189 target = "NetworkManager/dispatcher.d/01nixos-ip-up"; 190 } 191 { source = configFile; 192 target = "NetworkManager/NetworkManager.conf"; 193 } 194 { source = "${networkmanager_openvpn}/etc/NetworkManager/VPN/nm-openvpn-service.name"; 195 target = "NetworkManager/VPN/nm-openvpn-service.name"; 196 } 197 { source = "${networkmanager_vpnc}/etc/NetworkManager/VPN/nm-vpnc-service.name"; 198 target = "NetworkManager/VPN/nm-vpnc-service.name"; 199 } 200 { source = "${networkmanager_openconnect}/etc/NetworkManager/VPN/nm-openconnect-service.name"; 201 target = "NetworkManager/VPN/nm-openconnect-service.name"; 202 } 203 { source = "${networkmanager_pptp}/etc/NetworkManager/VPN/nm-pptp-service.name"; 204 target = "NetworkManager/VPN/nm-pptp-service.name"; 205 } 206 { source = "${networkmanager_l2tp}/etc/NetworkManager/VPN/nm-l2tp-service.name"; 207 target = "NetworkManager/VPN/nm-l2tp-service.name"; 208 } 209 ] ++ optional (cfg.appendNameservers == [] || cfg.insertNameservers == []) 210 { source = overrideNameserversScript; 211 target = "NetworkManager/dispatcher.d/02overridedns"; 212 } 213 ++ lib.imap (i: s: { 214 text = s.source; 215 target = "NetworkManager/dispatcher.d/${dispatcherTypesSubdirMap.${s.type}}03userscript${lib.fixedWidthNumber 4 i}"; 216 }) cfg.dispatcherScripts; 217 218 environment.systemPackages = cfg.packages; 219 220 users.extraGroups = [{ 221 name = "networkmanager"; 222 gid = config.ids.gids.networkmanager; 223 } 224 { 225 name = "nm-openvpn"; 226 gid = config.ids.gids.nm-openvpn; 227 }]; 228 users.extraUsers = [{ 229 name = "nm-openvpn"; 230 uid = config.ids.uids.nm-openvpn; 231 } 232 { 233 # to enable link-local connections 234 name = "avahi-autoipd"; 235 uid = config.ids.uids.avahi-autoipd; 236 }]; 237 238 systemd.packages = cfg.packages; 239 240 # Create an initialisation service that both starts 241 # NetworkManager when network.target is reached, 242 # and sets up necessary directories for NM. 243 systemd.services."networkmanager-init" = { 244 description = "NetworkManager initialisation"; 245 wantedBy = [ "network.target" ]; 246 wants = [ "network-manager.service" ]; 247 before = [ "network-manager.service" ]; 248 script = '' 249 mkdir -m 700 -p /etc/NetworkManager/system-connections 250 mkdir -m 755 -p ${stateDirs} 251 ''; 252 serviceConfig.Type = "oneshot"; 253 }; 254 255 # Turn off NixOS' network management 256 networking = { 257 useDHCP = false; 258 wireless.enable = false; 259 }; 260 261 powerManagement.resumeCommands = '' 262 ${config.systemd.package}/bin/systemctl restart network-manager 263 ''; 264 265 security.polkit.extraConfig = polkitConf; 266 267 services.dbus.packages = cfg.packages; 268 269 services.udev.packages = cfg.packages; 270 }; 271}