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