Unverified Commit 377ae8a7 authored by Michele Guerini Rocco's avatar Michele Guerini Rocco Committed by GitHub
Browse files

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

parents 4a6660ea 66db09eb
Loading
Loading
Loading
Loading
+74 −30
Original line number Diff line number Diff line
@@ -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 = [ ];
@@ -185,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 = "";
@@ -196,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.
@@ -263,11 +289,16 @@ in
        # dhcpcd.  So do a "systemctl restart" instead.
        stopIfChanged = false;

        path = [
        path =
          [
            dhcpcd
          pkgs.nettools
            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";

@@ -299,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"
@@ -313,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;
@@ -338,12 +369,15 @@ in
          RestrictNamespaces = true;
          RestrictRealtime = true;
          RestrictSUIDSGID = true;
          SystemCallFilter = [
          SystemCallFilter =
            [
              "@system-service"
              "~@aio"
              "~@keyring"
              "~@memlock"
              "~@mount"
            ]
            ++ lib.optionals (!cfg.allowSetuid) [
              "~@privileged"
              "~@resources"
            ];
@@ -371,17 +405,27 @@ in
      /run/current-system/systemd/bin/systemctl reload dhcpcd.service
    '';

    security.polkit.extraConfig = lib.mkIf config.services.resolved.enable ''
    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 == '${config.systemd.services.dhcpcd.serviceConfig.User}') {
                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;
            }
        });
      '')
    ];

  };

+23 −0
Original line number Diff line number Diff line
@@ -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;
+7 −1
Original line number Diff line number Diff line
@@ -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";

@@ -62,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; {