From c73c174392a7ed7cc60b5005f35c610491124417 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Wed, 26 Feb 2025 15:50:24 +0100 Subject: [PATCH 1/4] dhcpcd: use nixos as a default hostname This is effectively the default since bf5d64a1. --- pkgs/by-name/dh/dhcpcd/package.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/by-name/dh/dhcpcd/package.nix b/pkgs/by-name/dh/dhcpcd/package.nix index 7394fea8f83f..3c47105a9a1f 100644 --- a/pkgs/by-name/dh/dhcpcd/package.nix +++ b/pkgs/by-name/dh/dhcpcd/package.nix @@ -44,6 +44,7 @@ stdenv.mkDerivation rec { "--localstatedir=/var" "--disable-privsep" "--dbdir=/var/lib/dhcpcd" + "--with-default-hostname=nixos" (lib.enableFeature enablePrivSep "privsep") ] ++ lib.optional enablePrivSep "--privsepuser=dhcpcd"; From bf1cf6bffc1d59bd8db1bde95047881326538e2e Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Wed, 26 Feb 2025 16:00:53 +0100 Subject: [PATCH 2/4] nixos/dhcpcd: fix hostname via DHCP --- nixos/modules/services/networking/dhcpcd.nix | 67 ++++++++++++++------ 1 file changed, 49 insertions(+), 18 deletions(-) diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index 308ae1278a1b..bfade11ebacd 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -69,7 +69,7 @@ let hostname # A list of options to request from the DHCP server. - option domain_name_servers, domain_name, domain_search, host_name + option domain_name_servers, domain_name, domain_search option classless_static_routes, ntp_servers, interface_mtu # A ServerID is required by RFC2131. @@ -112,6 +112,7 @@ let ${lib.optionalString (config.networking.enableIPv6 && cfg.IPv6rs == false) '' noipv6rs ''} + ${lib.optionalString cfg.setHostname "option host_name"} ${cfg.extraConfig} ''; @@ -137,7 +138,7 @@ in type = lib.types.bool; default = false; description = '' - Whenever to leave interfaces configured on dhcpcd daemon + Whether to leave interfaces configured on dhcpcd daemon shutdown. Set to true if you have your root or store mounted over the network or this machine accepts SSH connections through DHCP interfaces and clients should be notified when @@ -145,6 +146,22 @@ in ''; }; + networking.dhcpcd.setHostname = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Whether to set the machine hostname based on the information + received from the DHCP server. + + ::: {.note} + The hostname will be changed only if the current one is + the empty string, `localhost` or `nixos`. + + Polkit ([](#opt-security.polkit.enable)) is also required. + ::: + ''; + }; + networking.dhcpcd.denyInterfaces = lib.mkOption { type = lib.types.listOf lib.types.str; default = [ ]; @@ -263,11 +280,15 @@ in # dhcpcd. So do a "systemctl restart" instead. stopIfChanged = false; - path = [ - dhcpcd - pkgs.nettools - config.networking.resolvconf.package - ]; + path = + [ + dhcpcd + config.networking.resolvconf.package + ] ++ lib.optional cfg.setHostname ( + pkgs.writeShellScriptBin "hostname" '' + ${lib.getExe' pkgs.systemd "hostnamectl"} set-hostname --transient $1 + '' + ); unitConfig.ConditionCapability = "CAP_NET_ADMIN"; @@ -371,17 +392,27 @@ in /run/current-system/systemd/bin/systemctl reload dhcpcd.service ''; - security.polkit.extraConfig = lib.mkIf config.services.resolved.enable '' - polkit.addRule(function(action, subject) { - if (action.id == 'org.freedesktop.resolve1.revert' || - action.id == 'org.freedesktop.resolve1.set-dns-servers' || - action.id == 'org.freedesktop.resolve1.set-domains') { - if (subject.user == '${config.systemd.services.dhcpcd.serviceConfig.User}') { - return polkit.Result.YES; - } - } - }); - ''; + security.polkit.extraConfig = lib.mkMerge [ + (lib.mkIf config.services.resolved.enable '' + polkit.addRule(function(action, subject) { + if (action.id == 'org.freedesktop.resolve1.revert' || + action.id == 'org.freedesktop.resolve1.set-dns-servers' || + action.id == 'org.freedesktop.resolve1.set-domains') { + if (subject.user == 'dhcpcd') { + return polkit.Result.YES; + } + } + }); + '') + (lib.mkIf cfg.setHostname '' + polkit.addRule(function(action, subject) { + if (action.id == 'org.freedesktop.hostname1.set-hostname' && + subject.user == 'dhcpcd') { + return polkit.Result.YES; + } + }); + '') + ]; }; From 54a6949722e1e290cf934f246a40d88d60835987 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Wed, 26 Feb 2025 16:02:20 +0100 Subject: [PATCH 3/4] nixos/tests/networking: test hostname via DHCP --- nixos/modules/services/networking/dhcpcd.nix | 3 ++- .../networking/networkd-and-scripted.nix | 23 +++++++++++++++++++ pkgs/by-name/dh/dhcpcd/package.nix | 7 +++++- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index bfade11ebacd..32ddc2757bff 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -284,7 +284,8 @@ in [ dhcpcd config.networking.resolvconf.package - ] ++ lib.optional cfg.setHostname ( + ] + ++ lib.optional cfg.setHostname ( pkgs.writeShellScriptBin "hostname" '' ${lib.getExe' pkgs.systemd "hostnamectl"} set-hostname --transient $1 '' diff --git a/nixos/tests/networking/networkd-and-scripted.nix b/nixos/tests/networking/networkd-and-scripted.nix index f2211738db2b..312981317735 100644 --- a/nixos/tests/networking/networkd-and-scripted.nix +++ b/nixos/tests/networking/networkd-and-scripted.nix @@ -178,6 +178,29 @@ let router.wait_until_succeeds("ping -c 1 fd00:1234:5678:2::2") ''; }; + dhcpHostname = { + name = "hostnameDHCP"; + nodes.router = router; + nodes.client = clientConfig { + # use the name given by the DHCP server + system.name = "client"; + networking.hostName = lib.mkForce ""; + security.polkit.enable = true; + virtualisation.interfaces.enp1s0.vlan = 1; + networking.interfaces.enp1s0.useDHCP = true; + }; + testScript = '' + router.start() + router.systemctl("start network-online.target") + router.wait_for_unit("network-online.target") + + client.start() + client.wait_for_unit("network.target") + + with subtest("Wait until we have received the hostname"): + client.wait_until_succeeds("hostname | grep -q 'client1'") + ''; + }; dhcpOneIf = { name = "OneInterfaceDHCP"; nodes.router = router; diff --git a/pkgs/by-name/dh/dhcpcd/package.nix b/pkgs/by-name/dh/dhcpcd/package.nix index 3c47105a9a1f..b6b814248050 100644 --- a/pkgs/by-name/dh/dhcpcd/package.nix +++ b/pkgs/by-name/dh/dhcpcd/package.nix @@ -63,7 +63,12 @@ stdenv.mkDerivation rec { ) "[ -e ${placeholder "out"}/lib/dhcpcd/dev/udev.so ]"; passthru.tests = { - inherit (nixosTests.networking.scripted) macvlan dhcpSimple dhcpOneIf; + inherit (nixosTests.networking.scripted) + macvlan + dhcpSimple + dhcpHostname + dhcpOneIf + ; }; meta = with lib; { From 66db09eb6225dbc3b013a70513ce8ae82d32edf6 Mon Sep 17 00:00:00 2001 From: rnhmjoj Date: Wed, 26 Feb 2025 19:33:54 +0100 Subject: [PATCH 4/4] nixos/dhcpcd: add option to allow setuid binaries The promise in the networking.dhcpcd.runHook description was broken by further restrictions added in 21bb7ea9. --- nixos/modules/services/networking/dhcpcd.nix | 36 +++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/nixos/modules/services/networking/dhcpcd.nix b/nixos/modules/services/networking/dhcpcd.nix index 32ddc2757bff..6aecbec7bd4a 100644 --- a/nixos/modules/services/networking/dhcpcd.nix +++ b/nixos/modules/services/networking/dhcpcd.nix @@ -202,6 +202,15 @@ in ''; }; + networking.dhcpcd.allowSetuid = lib.mkOption { + type = lib.types.bool; + default = false; + description = '' + Whether to relax the security sandbox to allow running setuid + binaries (e.g. `sudo`) in the dhcpcd hooks. + ''; + }; + networking.dhcpcd.runHook = lib.mkOption { type = lib.types.lines; default = ""; @@ -213,7 +222,7 @@ in ::: {.note} To use sudo or similar tools in your script you may have to set: - systemd.services.dhcpcd.serviceConfig.NoNewPrivileges = false; + networking.dhcpcd.allowSetuid = true; In addition, as most of the filesystem is inaccessible to dhcpcd by default, you may want to define some exceptions, e.g. @@ -321,7 +330,7 @@ in "CAP_NET_RAW" "CAP_NET_BIND_SERVICE" ]; - CapabilityBoundingSet = [ + CapabilityBoundingSet = lib.optionals (!cfg.allowSetuid) [ "CAP_NET_ADMIN" "CAP_NET_RAW" "CAP_NET_BIND_SERVICE" @@ -335,7 +344,7 @@ in DeviceAllow = ""; LockPersonality = true; MemoryDenyWriteExecute = true; - NoNewPrivileges = lib.mkDefault true; # may be disabled for sudo in runHook + NoNewPrivileges = lib.mkDefault (!cfg.allowSetuid); # may be disabled for sudo in runHook PrivateDevices = true; PrivateMounts = true; PrivateTmp = true; @@ -360,15 +369,18 @@ in RestrictNamespaces = true; RestrictRealtime = true; RestrictSUIDSGID = true; - SystemCallFilter = [ - "@system-service" - "~@aio" - "~@keyring" - "~@memlock" - "~@mount" - "~@privileged" - "~@resources" - ]; + SystemCallFilter = + [ + "@system-service" + "~@aio" + "~@keyring" + "~@memlock" + "~@mount" + ] + ++ lib.optionals (!cfg.allowSetuid) [ + "~@privileged" + "~@resources" + ]; SystemCallArchitectures = "native"; UMask = "0027"; };