at 18.09-beta 5.1 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg4 = config.services.dhcpd4; 8 cfg6 = config.services.dhcpd6; 9 10 writeConfig = cfg: pkgs.writeText "dhcpd.conf" 11 '' 12 default-lease-time 600; 13 max-lease-time 7200; 14 authoritative; 15 ddns-update-style interim; 16 log-facility local1; # see dhcpd.nix 17 18 ${cfg.extraConfig} 19 20 ${lib.concatMapStrings 21 (machine: '' 22 host ${machine.hostName} { 23 hardware ethernet ${machine.ethernetAddress}; 24 fixed-address ${machine.ipAddress}; 25 } 26 '') 27 cfg.machines 28 } 29 ''; 30 31 dhcpdService = postfix: cfg: optionalAttrs cfg.enable { 32 "dhcpd${postfix}" = { 33 description = "DHCPv${postfix} server"; 34 wantedBy = [ "multi-user.target" ]; 35 after = [ "network.target" ]; 36 37 preStart = '' 38 mkdir -m 755 -p ${cfg.stateDir} 39 chown dhcpd:nogroup ${cfg.stateDir} 40 touch ${cfg.stateDir}/dhcpd.leases 41 ''; 42 43 serviceConfig = 44 let 45 configFile = if cfg.configFile != null then cfg.configFile else writeConfig cfg; 46 args = [ "@${pkgs.dhcp}/sbin/dhcpd" "dhcpd${postfix}" "-${postfix}" 47 "-pf" "/run/dhcpd${postfix}/dhcpd.pid" 48 "-cf" "${configFile}" 49 "-lf" "${cfg.stateDir}/dhcpd.leases" 50 "-user" "dhcpd" "-group" "nogroup" 51 ] ++ cfg.extraFlags 52 ++ cfg.interfaces; 53 54 in { 55 ExecStart = concatMapStringsSep " " escapeShellArg args; 56 Type = "forking"; 57 Restart = "always"; 58 RuntimeDirectory = [ "dhcpd${postfix}" ]; 59 PIDFile = "/run/dhcpd${postfix}/dhcpd.pid"; 60 }; 61 }; 62 }; 63 64 machineOpts = { ... }: { 65 66 options = { 67 68 hostName = mkOption { 69 type = types.str; 70 example = "foo"; 71 description = '' 72 Hostname which is assigned statically to the machine. 73 ''; 74 }; 75 76 ethernetAddress = mkOption { 77 type = types.str; 78 example = "00:16:76:9a:32:1d"; 79 description = '' 80 MAC address of the machine. 81 ''; 82 }; 83 84 ipAddress = mkOption { 85 type = types.str; 86 example = "192.168.1.10"; 87 description = '' 88 IP address of the machine. 89 ''; 90 }; 91 92 }; 93 }; 94 95 dhcpConfig = postfix: { 96 97 enable = mkOption { 98 type = types.bool; 99 default = false; 100 description = '' 101 Whether to enable the DHCPv${postfix} server. 102 ''; 103 }; 104 105 stateDir = mkOption { 106 type = types.path; 107 # We use /var/lib/dhcp for DHCPv4 to save backwards compatibility. 108 default = "/var/lib/dhcp${if postfix == "4" then "" else postfix}"; 109 description = '' 110 State directory for the DHCP server. 111 ''; 112 }; 113 114 extraConfig = mkOption { 115 type = types.lines; 116 default = ""; 117 example = '' 118 option subnet-mask 255.255.255.0; 119 option broadcast-address 192.168.1.255; 120 option routers 192.168.1.5; 121 option domain-name-servers 130.161.158.4, 130.161.33.17, 130.161.180.1; 122 option domain-name "example.org"; 123 subnet 192.168.1.0 netmask 255.255.255.0 { 124 range 192.168.1.100 192.168.1.200; 125 } 126 ''; 127 description = '' 128 Extra text to be appended to the DHCP server configuration 129 file. Currently, you almost certainly need to specify something 130 there, such as the options specifying the subnet mask, DNS servers, 131 etc. 132 ''; 133 }; 134 135 extraFlags = mkOption { 136 type = types.listOf types.str; 137 default = []; 138 description = '' 139 Additional command line flags to be passed to the dhcpd daemon. 140 ''; 141 }; 142 143 configFile = mkOption { 144 type = types.nullOr types.path; 145 default = null; 146 description = '' 147 The path of the DHCP server configuration file. If no file 148 is specified, a file is generated using the other options. 149 ''; 150 }; 151 152 interfaces = mkOption { 153 type = types.listOf types.str; 154 default = ["eth0"]; 155 description = '' 156 The interfaces on which the DHCP server should listen. 157 ''; 158 }; 159 160 machines = mkOption { 161 type = with types; listOf (submodule machineOpts); 162 default = []; 163 example = [ 164 { hostName = "foo"; 165 ethernetAddress = "00:16:76:9a:32:1d"; 166 ipAddress = "192.168.1.10"; 167 } 168 { hostName = "bar"; 169 ethernetAddress = "00:19:d1:1d:c4:9a"; 170 ipAddress = "192.168.1.11"; 171 } 172 ]; 173 description = '' 174 A list mapping Ethernet addresses to IPv${postfix} addresses for the 175 DHCP server. 176 ''; 177 }; 178 179 }; 180 181in 182 183{ 184 185 ###### interface 186 187 options = { 188 189 services.dhcpd4 = dhcpConfig "4"; 190 services.dhcpd6 = dhcpConfig "6"; 191 192 }; 193 194 195 ###### implementation 196 197 config = mkIf (cfg4.enable || cfg6.enable) { 198 199 users = { 200 users.dhcpd = { 201 uid = config.ids.uids.dhcpd; 202 description = "DHCP daemon user"; 203 }; 204 }; 205 206 systemd.services = dhcpdService "4" cfg4 // dhcpdService "6" cfg6; 207 208 }; 209 210}