at 17.09-beta 6.8 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 dhcpcd = if !config.boot.isContainer then pkgs.dhcpcd else pkgs.dhcpcd.override { udev = null; }; 8 9 cfg = config.networking.dhcpcd; 10 11 interfaces = attrValues config.networking.interfaces; 12 13 enableDHCP = config.networking.dhcpcd.enable && 14 (config.networking.useDHCP || any (i: i.useDHCP == true) interfaces); 15 16 # Don't start dhcpcd on explicitly configured interfaces or on 17 # interfaces that are part of a bridge, bond or sit device. 18 ignoredInterfaces = 19 map (i: i.name) (filter (i: if i.useDHCP != null then !i.useDHCP else i.ip4 != [ ] || i.ipAddress != null) interfaces) 20 ++ mapAttrsToList (i: _: i) config.networking.sits 21 ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bridges)) 22 ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.vswitches)) 23 ++ concatLists (attrValues (mapAttrs (n: v: v.interfaces) config.networking.bonds)) 24 ++ config.networking.dhcpcd.denyInterfaces; 25 26 arrayAppendOrNull = a1: a2: if a1 == null && a2 == null then null 27 else if a1 == null then a2 else if a2 == null then a1 28 else a1 ++ a2; 29 30 # If dhcp is disabled but explicit interfaces are enabled, 31 # we need to provide dhcp just for those interfaces. 32 allowInterfaces = arrayAppendOrNull cfg.allowInterfaces 33 (if !config.networking.useDHCP && enableDHCP then 34 map (i: i.name) (filter (i: i.useDHCP == true) interfaces) else null); 35 36 # Config file adapted from the one that ships with dhcpcd. 37 dhcpcdConf = pkgs.writeText "dhcpcd.conf" 38 '' 39 # Inform the DHCP server of our hostname for DDNS. 40 hostname 41 42 # A list of options to request from the DHCP server. 43 option domain_name_servers, domain_name, domain_search, host_name 44 option classless_static_routes, ntp_servers, interface_mtu 45 46 # A ServerID is required by RFC2131. 47 # Commented out because of many non-compliant DHCP servers in the wild :( 48 #require dhcp_server_identifier 49 50 # A hook script is provided to lookup the hostname if not set by 51 # the DHCP server, but it should not be run by default. 52 nohook lookup-hostname 53 54 # Ignore peth* devices; on Xen, they're renamed physical 55 # Ethernet cards used for bridging. Likewise for vif* and tap* 56 # (Xen) and virbr* and vnet* (libvirt). 57 denyinterfaces ${toString ignoredInterfaces} lo peth* vif* tap* tun* virbr* vnet* vboxnet* sit* 58 59 # Use the list of allowed interfaces if specified 60 ${optionalString (allowInterfaces != null) "allowinterfaces ${toString allowInterfaces}"} 61 62 ${cfg.extraConfig} 63 ''; 64 65 exitHook = pkgs.writeText "dhcpcd.exit-hook" 66 '' 67 if [ "$reason" = BOUND -o "$reason" = REBOOT ]; then 68 # Restart ntpd. We need to restart it to make sure that it 69 # will actually do something: if ntpd cannot resolve the 70 # server hostnames in its config file, then it will never do 71 # anything ever again ("couldn't resolve ..., giving up on 72 # it"), so we silently lose time synchronisation. This also 73 # applies to openntpd. 74 ${config.systemd.package}/bin/systemctl try-reload-or-restart ntpd.service openntpd.service || true 75 fi 76 77 ${cfg.runHook} 78 ''; 79 80in 81 82{ 83 84 ###### interface 85 86 options = { 87 88 networking.dhcpcd.enable = mkOption { 89 type = types.bool; 90 default = true; 91 description = '' 92 Whether to enable dhcpcd for device configuration. This is mainly to 93 explicitly disable dhcpcd (for example when using networkd). 94 ''; 95 }; 96 97 networking.dhcpcd.persistent = mkOption { 98 type = types.bool; 99 default = false; 100 description = '' 101 Whenever to leave interfaces configured on dhcpcd daemon 102 shutdown. Set to true if you have your root or store mounted 103 over the network or this machine accepts SSH connections 104 through DHCP interfaces and clients should be notified when 105 it shuts down. 106 ''; 107 }; 108 109 networking.dhcpcd.denyInterfaces = mkOption { 110 type = types.listOf types.str; 111 default = []; 112 description = '' 113 Disable the DHCP client for any interface whose name matches 114 any of the shell glob patterns in this list. The purpose of 115 this option is to blacklist virtual interfaces such as those 116 created by Xen, libvirt, LXC, etc. 117 ''; 118 }; 119 120 networking.dhcpcd.allowInterfaces = mkOption { 121 type = types.nullOr (types.listOf types.str); 122 default = null; 123 description = '' 124 Enable the DHCP client for any interface whose name matches 125 any of the shell glob patterns in this list. Any interface not 126 explicitly matched by this pattern will be denied. This pattern only 127 applies when non-null. 128 ''; 129 }; 130 131 networking.dhcpcd.extraConfig = mkOption { 132 type = types.lines; 133 default = ""; 134 description = '' 135 Literal string to append to the config file generated for dhcpcd. 136 ''; 137 }; 138 139 networking.dhcpcd.runHook = mkOption { 140 type = types.lines; 141 default = ""; 142 example = "if [[ $reason =~ BOUND ]]; then echo $interface: Routers are $new_routers - were $old_routers; fi"; 143 description = '' 144 Shell code that will be run after all other hooks. See 145 `man dhcpcd-run-hooks` for details on what is possible. 146 ''; 147 }; 148 149 }; 150 151 152 ###### implementation 153 154 config = mkIf enableDHCP { 155 156 systemd.services.dhcpcd = 157 { description = "DHCP Client"; 158 159 wantedBy = [ "network-online.target" ]; 160 after = [ "network.target" ]; 161 wants = [ "network.target" ]; 162 163 # Stopping dhcpcd during a reconfiguration is undesirable 164 # because it brings down the network interfaces configured by 165 # dhcpcd. So do a "systemctl restart" instead. 166 stopIfChanged = false; 167 168 path = [ dhcpcd pkgs.nettools pkgs.openresolv ]; 169 170 unitConfig.ConditionCapability = "CAP_NET_ADMIN"; 171 172 serviceConfig = 173 { Type = "forking"; 174 PIDFile = "/run/dhcpcd.pid"; 175 ExecStart = "@${dhcpcd}/sbin/dhcpcd dhcpcd -w --quiet ${optionalString cfg.persistent "--persistent"} --config ${dhcpcdConf}"; 176 ExecReload = "${dhcpcd}/sbin/dhcpcd --rebind"; 177 Restart = "always"; 178 }; 179 }; 180 181 environment.systemPackages = [ dhcpcd ]; 182 183 environment.etc = 184 [ { source = exitHook; 185 target = "dhcpcd.exit-hook"; 186 } 187 ]; 188 189 powerManagement.resumeCommands = mkIf config.systemd.services.dhcpcd.enable 190 '' 191 # Tell dhcpcd to rebind its interfaces if it's running. 192 ${config.systemd.package}/bin/systemctl reload dhcpcd.service 193 ''; 194 195 }; 196 197}