summary refs log tree commit diff
path: root/nixos/modules/services/networking/dhclient.nix
diff options
context:
space:
mode:
Diffstat (limited to 'nixos/modules/services/networking/dhclient.nix')
-rw-r--r--nixos/modules/services/networking/dhclient.nix111
1 files changed, 111 insertions, 0 deletions
diff --git a/nixos/modules/services/networking/dhclient.nix b/nixos/modules/services/networking/dhclient.nix
new file mode 100644
index 00000000000..1e343443899
--- /dev/null
+++ b/nixos/modules/services/networking/dhclient.nix
@@ -0,0 +1,111 @@
+{ config, pkgs, ... }:
+
+with pkgs.lib;
+
+let
+
+  inherit (pkgs) nettools dhcp lib;
+
+  # Don't start dhclient on explicitly configured interfaces or on
+  # interfaces that are part of a bridge.
+  ignoredInterfaces =
+    map (i: i.name) (lib.filter (i: i ? ipAddress && i.ipAddress != "" ) config.networking.interfaces)
+    ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges));
+
+  stateDir = "/var/lib/dhcp"; # Don't use /var/state/dhcp; not FHS-compliant.
+
+  dhclientExitHooks = pkgs.writeText "dhclient-exit-hooks"
+    ''
+      #echo "$reason" >> /tmp/dhcp-exit
+      #echo "$exit_status" >> /tmp/dhcp-exit
+
+      if test "$reason" = BOUND -o "$reason" = REBOOT; then
+          # Restart ntpd.  (The "ip-up" event below will trigger the
+          # restart.)  We need to restart it to make sure that it will
+          # actually do something: if ntpd cannot resolve the server
+          # hostnames in its config file, then it will never do
+          # anything ever again ("couldn't resolve ..., giving up on
+          # it"), so we silently lose time synchronisation.
+          ${config.system.build.upstart}/sbin/initctl stop ntpd
+
+          ${config.system.build.upstart}/sbin/initctl emit -n ip-up
+      fi
+
+      if test "$reason" = EXPIRE -o "$reason" = RELEASE; then
+          ${config.system.build.upstart}/sbin/initctl emit -n ip-down
+      fi
+    '';
+
+in
+
+{
+
+  ###### implementation
+
+  config = mkIf config.networking.useDHCP {
+
+    # dhclient barfs if /proc/net/if_inet6 doesn't exist.
+    boot.kernelModules = [ "ipv6" ];
+
+    jobs.dhclient =
+      { startOn = "started network-interfaces";
+        stopOn = "stopping network-interfaces";
+
+        path = [ dhcp ];
+
+        script =
+          ''
+            # Determine the interface on which to start dhclient.
+            interfaces=
+
+            for i in $(cd /sys/class/net && ls -d *); do
+                # Only run dhclient on interfaces of type ARPHRD_ETHER
+                # (1), i.e. Ethernet.  Ignore peth* devices; on Xen,
+                # they're renamed physical Ethernet cards used for
+                # bridging.  Likewise for vif* and tap* (Xen) and
+                # virbr* and vnet* (libvirt).
+                if [ "$(cat /sys/class/net/$i/type)" = 1 ]; then
+                    if ! for j in ${toString ignoredInterfaces}; do echo $j; done | grep -F -x -q "$i" &&
+                       ! echo "$i" | grep -x -q "peth.*\|vif.*\|tap.*\|virbr.*\|vnet.*";
+		    then
+                        echo "Running dhclient on $i"
+                        interfaces="$interfaces $i"
+                    fi
+                fi
+            done
+
+            if test -z "$interfaces"; then
+                echo 'No interfaces on which to start dhclient!'
+                exit 1
+            fi
+
+            mkdir -m 755 -p ${stateDir}
+
+            exec dhclient -d $interfaces -e "PATH=$PATH" -lf ${stateDir}/dhclient.leases -sf ${dhcp}/sbin/dhclient-script
+          '';
+      };
+
+    environment.systemPackages = [dhcp];
+
+    environment.etc =
+      [ # Dhclient hooks for emitting ip-up/ip-down events.
+        { source = dhclientExitHooks;
+          target = "dhclient-exit-hooks";
+        }
+      ];
+
+    powerManagement.resumeCommands =
+      ''
+        ${config.system.build.upstart}/sbin/restart dhclient
+      '';
+
+    networking.interfaceMonitor.commands =
+      ''
+        if [ "$status" = up ]; then
+          ${config.system.build.upstart}/sbin/restart dhclient
+        fi
+      '';
+
+  };
+
+}