python3Packages.orjson: Disable failing tests on 32 bit
[NixPkgs.git] / nixos / modules / services / networking / dhcpd.nix
blob0bd5e4ef5535856cef1b4ee34f1a23158d182c19
1 { config, lib, pkgs, ... }:
3 with lib;
5 let
7   cfg4 = config.services.dhcpd4;
8   cfg6 = config.services.dhcpd6;
10   writeConfig = postfix: cfg: pkgs.writeText "dhcpd.conf"
11     ''
12       default-lease-time 600;
13       max-lease-time 7200;
14       ${optionalString (!cfg.authoritative) "not "}authoritative;
15       ddns-update-style interim;
16       log-facility local1; # see dhcpd.nix
18       ${cfg.extraConfig}
20       ${lib.concatMapStrings
21           (machine: ''
22             host ${machine.hostName} {
23               hardware ethernet ${machine.ethernetAddress};
24               fixed-address${
25                 optionalString (postfix == "6") postfix
26               } ${machine.ipAddress};
27             }
28           '')
29           cfg.machines
30       }
31     '';
33   dhcpdService = postfix: cfg:
34     let
35       configFile =
36         if cfg.configFile != null
37           then cfg.configFile
38           else writeConfig postfix cfg;
39       leaseFile = "/var/lib/dhcpd${postfix}/dhcpd.leases";
40       args = [
41         "@${pkgs.dhcp}/sbin/dhcpd" "dhcpd${postfix}" "-${postfix}"
42         "-pf" "/run/dhcpd${postfix}/dhcpd.pid"
43         "-cf" configFile
44         "-lf" leaseFile
45       ] ++ cfg.extraFlags
46         ++ cfg.interfaces;
47     in
48       optionalAttrs cfg.enable {
49         "dhcpd${postfix}" = {
50           description = "DHCPv${postfix} server";
51           wantedBy = [ "multi-user.target" ];
52           after = [ "network.target" ];
54           preStart = "touch ${leaseFile}";
55           serviceConfig = {
56             ExecStart = concatMapStringsSep " " escapeShellArg args;
57             Type = "forking";
58             Restart = "always";
59             DynamicUser = true;
60             User = "dhcpd";
61             Group = "dhcpd";
62             AmbientCapabilities = [
63               "CAP_NET_RAW"          # to send ICMP messages
64               "CAP_NET_BIND_SERVICE" # to bind on DHCP port (67)
65             ];
66             StateDirectory   = "dhcpd${postfix}";
67             RuntimeDirectory = "dhcpd${postfix}";
68             PIDFile = "/run/dhcpd${postfix}/dhcpd.pid";
69           };
70         };
71       };
73   machineOpts = { ... }: {
75     options = {
77       hostName = mkOption {
78         type = types.str;
79         example = "foo";
80         description = lib.mdDoc ''
81           Hostname which is assigned statically to the machine.
82         '';
83       };
85       ethernetAddress = mkOption {
86         type = types.str;
87         example = "00:16:76:9a:32:1d";
88         description = lib.mdDoc ''
89           MAC address of the machine.
90         '';
91       };
93       ipAddress = mkOption {
94         type = types.str;
95         example = "192.168.1.10";
96         description = lib.mdDoc ''
97           IP address of the machine.
98         '';
99       };
101     };
102   };
104   dhcpConfig = postfix: {
106     enable = mkOption {
107       type = types.bool;
108       default = false;
109       description = lib.mdDoc ''
110         Whether to enable the DHCPv${postfix} server.
111       '';
112     };
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 = lib.mdDoc ''
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     };
135     extraFlags = mkOption {
136       type = types.listOf types.str;
137       default = [];
138       description = lib.mdDoc ''
139         Additional command line flags to be passed to the dhcpd daemon.
140       '';
141     };
143     configFile = mkOption {
144       type = types.nullOr types.path;
145       default = null;
146       description = lib.mdDoc ''
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     };
152     interfaces = mkOption {
153       type = types.listOf types.str;
154       default = ["eth0"];
155       description = lib.mdDoc ''
156         The interfaces on which the DHCP server should listen.
157       '';
158     };
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 = lib.mdDoc ''
174         A list mapping Ethernet addresses to IPv${postfix} addresses for the
175         DHCP server.
176       '';
177     };
179     authoritative = mkOption {
180       type = types.bool;
181       default = true;
182       description = lib.mdDoc ''
183         Whether the DHCP server shall send DHCPNAK messages to misconfigured
184         clients. If this is not done, clients may be unable to get a correct
185         IP address after changing subnets until their old lease has expired.
186       '';
187     };
189   };
195   imports = [
196     (mkRenamedOptionModule [ "services" "dhcpd" ] [ "services" "dhcpd4" ])
197   ] ++ flip map [ "4" "6" ] (postfix:
198     mkRemovedOptionModule [ "services" "dhcpd${postfix}" "stateDir" ] ''
199       The DHCP server state directory is now managed with the systemd's DynamicUser mechanism.
200       This means the directory is named after the service (dhcpd${postfix}), created under
201       /var/lib/private/ and symlinked to /var/lib/.
202     ''
203   );
205   ###### interface
207   options = {
209     services.dhcpd4 = dhcpConfig "4";
210     services.dhcpd6 = dhcpConfig "6";
212   };
215   ###### implementation
217   config = mkIf (cfg4.enable || cfg6.enable) {
219     systemd.services = dhcpdService "4" cfg4 // dhcpdService "6" cfg6;
221   };