nixos/dhcpcd: fix hostname via DHCP (#385348)

authored by Michele Guerini Rocco and committed by GitHub 377ae8a7 4a6660ea

+104 -31
+74 -30
nixos/modules/services/networking/dhcpcd.nix
··· 69 hostname 70 71 # A list of options to request from the DHCP server. 72 - option domain_name_servers, domain_name, domain_search, host_name 73 option classless_static_routes, ntp_servers, interface_mtu 74 75 # A ServerID is required by RFC2131. ··· 112 ${lib.optionalString (config.networking.enableIPv6 && cfg.IPv6rs == false) '' 113 noipv6rs 114 ''} 115 116 ${cfg.extraConfig} 117 ''; ··· 137 type = lib.types.bool; 138 default = false; 139 description = '' 140 - Whenever to leave interfaces configured on dhcpcd daemon 141 shutdown. Set to true if you have your root or store mounted 142 over the network or this machine accepts SSH connections 143 through DHCP interfaces and clients should be notified when ··· 145 ''; 146 }; 147 148 networking.dhcpcd.denyInterfaces = lib.mkOption { 149 type = lib.types.listOf lib.types.str; 150 default = [ ]; ··· 185 ''; 186 }; 187 188 networking.dhcpcd.runHook = lib.mkOption { 189 type = lib.types.lines; 190 default = ""; ··· 196 ::: {.note} 197 To use sudo or similar tools in your script you may have to set: 198 199 - systemd.services.dhcpcd.serviceConfig.NoNewPrivileges = false; 200 201 In addition, as most of the filesystem is inaccessible to dhcpcd 202 by default, you may want to define some exceptions, e.g. ··· 263 # dhcpcd. So do a "systemctl restart" instead. 264 stopIfChanged = false; 265 266 - path = [ 267 - dhcpcd 268 - pkgs.nettools 269 - config.networking.resolvconf.package 270 - ]; 271 272 unitConfig.ConditionCapability = "CAP_NET_ADMIN"; 273 ··· 299 "CAP_NET_RAW" 300 "CAP_NET_BIND_SERVICE" 301 ]; 302 - CapabilityBoundingSet = [ 303 "CAP_NET_ADMIN" 304 "CAP_NET_RAW" 305 "CAP_NET_BIND_SERVICE" ··· 313 DeviceAllow = ""; 314 LockPersonality = true; 315 MemoryDenyWriteExecute = true; 316 - NoNewPrivileges = lib.mkDefault true; # may be disabled for sudo in runHook 317 PrivateDevices = true; 318 PrivateMounts = true; 319 PrivateTmp = true; ··· 338 RestrictNamespaces = true; 339 RestrictRealtime = true; 340 RestrictSUIDSGID = true; 341 - SystemCallFilter = [ 342 - "@system-service" 343 - "~@aio" 344 - "~@keyring" 345 - "~@memlock" 346 - "~@mount" 347 - "~@privileged" 348 - "~@resources" 349 - ]; 350 SystemCallArchitectures = "native"; 351 UMask = "0027"; 352 }; ··· 371 /run/current-system/systemd/bin/systemctl reload dhcpcd.service 372 ''; 373 374 - security.polkit.extraConfig = lib.mkIf config.services.resolved.enable '' 375 - polkit.addRule(function(action, subject) { 376 - if (action.id == 'org.freedesktop.resolve1.revert' || 377 - action.id == 'org.freedesktop.resolve1.set-dns-servers' || 378 - action.id == 'org.freedesktop.resolve1.set-domains') { 379 - if (subject.user == '${config.systemd.services.dhcpcd.serviceConfig.User}') { 380 - return polkit.Result.YES; 381 - } 382 - } 383 - }); 384 - ''; 385 386 }; 387
··· 69 hostname 70 71 # A list of options to request from the DHCP server. 72 + option domain_name_servers, domain_name, domain_search 73 option classless_static_routes, ntp_servers, interface_mtu 74 75 # A ServerID is required by RFC2131. ··· 112 ${lib.optionalString (config.networking.enableIPv6 && cfg.IPv6rs == false) '' 113 noipv6rs 114 ''} 115 + ${lib.optionalString cfg.setHostname "option host_name"} 116 117 ${cfg.extraConfig} 118 ''; ··· 138 type = lib.types.bool; 139 default = false; 140 description = '' 141 + Whether to leave interfaces configured on dhcpcd daemon 142 shutdown. Set to true if you have your root or store mounted 143 over the network or this machine accepts SSH connections 144 through DHCP interfaces and clients should be notified when ··· 146 ''; 147 }; 148 149 + networking.dhcpcd.setHostname = lib.mkOption { 150 + type = lib.types.bool; 151 + default = true; 152 + description = '' 153 + Whether to set the machine hostname based on the information 154 + received from the DHCP server. 155 + 156 + ::: {.note} 157 + The hostname will be changed only if the current one is 158 + the empty string, `localhost` or `nixos`. 159 + 160 + Polkit ([](#opt-security.polkit.enable)) is also required. 161 + ::: 162 + ''; 163 + }; 164 + 165 networking.dhcpcd.denyInterfaces = lib.mkOption { 166 type = lib.types.listOf lib.types.str; 167 default = [ ]; ··· 202 ''; 203 }; 204 205 + networking.dhcpcd.allowSetuid = lib.mkOption { 206 + type = lib.types.bool; 207 + default = false; 208 + description = '' 209 + Whether to relax the security sandbox to allow running setuid 210 + binaries (e.g. `sudo`) in the dhcpcd hooks. 211 + ''; 212 + }; 213 + 214 networking.dhcpcd.runHook = lib.mkOption { 215 type = lib.types.lines; 216 default = ""; ··· 222 ::: {.note} 223 To use sudo or similar tools in your script you may have to set: 224 225 + networking.dhcpcd.allowSetuid = true; 226 227 In addition, as most of the filesystem is inaccessible to dhcpcd 228 by default, you may want to define some exceptions, e.g. ··· 289 # dhcpcd. So do a "systemctl restart" instead. 290 stopIfChanged = false; 291 292 + path = 293 + [ 294 + dhcpcd 295 + config.networking.resolvconf.package 296 + ] 297 + ++ lib.optional cfg.setHostname ( 298 + pkgs.writeShellScriptBin "hostname" '' 299 + ${lib.getExe' pkgs.systemd "hostnamectl"} set-hostname --transient $1 300 + '' 301 + ); 302 303 unitConfig.ConditionCapability = "CAP_NET_ADMIN"; 304 ··· 330 "CAP_NET_RAW" 331 "CAP_NET_BIND_SERVICE" 332 ]; 333 + CapabilityBoundingSet = lib.optionals (!cfg.allowSetuid) [ 334 "CAP_NET_ADMIN" 335 "CAP_NET_RAW" 336 "CAP_NET_BIND_SERVICE" ··· 344 DeviceAllow = ""; 345 LockPersonality = true; 346 MemoryDenyWriteExecute = true; 347 + NoNewPrivileges = lib.mkDefault (!cfg.allowSetuid); # may be disabled for sudo in runHook 348 PrivateDevices = true; 349 PrivateMounts = true; 350 PrivateTmp = true; ··· 369 RestrictNamespaces = true; 370 RestrictRealtime = true; 371 RestrictSUIDSGID = true; 372 + SystemCallFilter = 373 + [ 374 + "@system-service" 375 + "~@aio" 376 + "~@keyring" 377 + "~@memlock" 378 + "~@mount" 379 + ] 380 + ++ lib.optionals (!cfg.allowSetuid) [ 381 + "~@privileged" 382 + "~@resources" 383 + ]; 384 SystemCallArchitectures = "native"; 385 UMask = "0027"; 386 }; ··· 405 /run/current-system/systemd/bin/systemctl reload dhcpcd.service 406 ''; 407 408 + security.polkit.extraConfig = lib.mkMerge [ 409 + (lib.mkIf config.services.resolved.enable '' 410 + polkit.addRule(function(action, subject) { 411 + if (action.id == 'org.freedesktop.resolve1.revert' || 412 + action.id == 'org.freedesktop.resolve1.set-dns-servers' || 413 + action.id == 'org.freedesktop.resolve1.set-domains') { 414 + if (subject.user == 'dhcpcd') { 415 + return polkit.Result.YES; 416 + } 417 + } 418 + }); 419 + '') 420 + (lib.mkIf cfg.setHostname '' 421 + polkit.addRule(function(action, subject) { 422 + if (action.id == 'org.freedesktop.hostname1.set-hostname' && 423 + subject.user == 'dhcpcd') { 424 + return polkit.Result.YES; 425 + } 426 + }); 427 + '') 428 + ]; 429 430 }; 431
+23
nixos/tests/networking/networkd-and-scripted.nix
··· 178 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::2") 179 ''; 180 }; 181 dhcpOneIf = { 182 name = "OneInterfaceDHCP"; 183 nodes.router = router;
··· 178 router.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::2") 179 ''; 180 }; 181 + dhcpHostname = { 182 + name = "hostnameDHCP"; 183 + nodes.router = router; 184 + nodes.client = clientConfig { 185 + # use the name given by the DHCP server 186 + system.name = "client"; 187 + networking.hostName = lib.mkForce ""; 188 + security.polkit.enable = true; 189 + virtualisation.interfaces.enp1s0.vlan = 1; 190 + networking.interfaces.enp1s0.useDHCP = true; 191 + }; 192 + testScript = '' 193 + router.start() 194 + router.systemctl("start network-online.target") 195 + router.wait_for_unit("network-online.target") 196 + 197 + client.start() 198 + client.wait_for_unit("network.target") 199 + 200 + with subtest("Wait until we have received the hostname"): 201 + client.wait_until_succeeds("hostname | grep -q 'client1'") 202 + ''; 203 + }; 204 dhcpOneIf = { 205 name = "OneInterfaceDHCP"; 206 nodes.router = router;
+7 -1
pkgs/by-name/dh/dhcpcd/package.nix
··· 44 "--localstatedir=/var" 45 "--disable-privsep" 46 "--dbdir=/var/lib/dhcpcd" 47 (lib.enableFeature enablePrivSep "privsep") 48 ] ++ lib.optional enablePrivSep "--privsepuser=dhcpcd"; 49 ··· 62 ) "[ -e ${placeholder "out"}/lib/dhcpcd/dev/udev.so ]"; 63 64 passthru.tests = { 65 - inherit (nixosTests.networking.scripted) macvlan dhcpSimple dhcpOneIf; 66 }; 67 68 meta = with lib; {
··· 44 "--localstatedir=/var" 45 "--disable-privsep" 46 "--dbdir=/var/lib/dhcpcd" 47 + "--with-default-hostname=nixos" 48 (lib.enableFeature enablePrivSep "privsep") 49 ] ++ lib.optional enablePrivSep "--privsepuser=dhcpcd"; 50 ··· 63 ) "[ -e ${placeholder "out"}/lib/dhcpcd/dev/udev.so ]"; 64 65 passthru.tests = { 66 + inherit (nixosTests.networking.scripted) 67 + macvlan 68 + dhcpSimple 69 + dhcpHostname 70 + dhcpOneIf 71 + ; 72 }; 73 74 meta = with lib; {