1{ config
2, lib
3, pkgs
4, ...
5}:
6
7with lib;
8
9let
10 cfg = config.services.kea;
11
12 format = pkgs.formats.json {};
13
14 chooseNotNull = x: y: if x != null then x else y;
15
16 ctrlAgentConfig = chooseNotNull cfg.ctrl-agent.configFile (format.generate "kea-ctrl-agent.conf" {
17 Control-agent = cfg.ctrl-agent.settings;
18 });
19
20 dhcp4Config = chooseNotNull cfg.dhcp4.configFile (format.generate "kea-dhcp4.conf" {
21 Dhcp4 = cfg.dhcp4.settings;
22 });
23
24 dhcp6Config = chooseNotNull cfg.dhcp6.configFile (format.generate "kea-dhcp6.conf" {
25 Dhcp6 = cfg.dhcp6.settings;
26 });
27
28 dhcpDdnsConfig = chooseNotNull cfg.dhcp-ddns.configFile (format.generate "kea-dhcp-ddns.conf" {
29 DhcpDdns = cfg.dhcp-ddns.settings;
30 });
31
32 package = pkgs.kea;
33in
34{
35 options.services.kea = with types; {
36 ctrl-agent = mkOption {
37 description = ''
38 Kea Control Agent configuration
39 '';
40 default = {};
41 type = submodule {
42 options = {
43 enable = mkEnableOption "Kea Control Agent";
44
45 extraArgs = mkOption {
46 type = listOf str;
47 default = [];
48 description = ''
49 List of additional arguments to pass to the daemon.
50 '';
51 };
52
53 configFile = mkOption {
54 type = nullOr path;
55 default = null;
56 description = ''
57 Kea Control Agent configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html>.
58
59 Takes preference over [settings](#opt-services.kea.ctrl-agent.settings).
60 Most users should prefer using [settings](#opt-services.kea.ctrl-agent.settings) instead.
61 '';
62 };
63
64 settings = mkOption {
65 type = format.type;
66 default = null;
67 description = ''
68 Kea Control Agent configuration as an attribute set, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html>.
69 '';
70 };
71 };
72 };
73 };
74
75 dhcp4 = mkOption {
76 description = ''
77 DHCP4 Server configuration
78 '';
79 default = {};
80 type = submodule {
81 options = {
82 enable = mkEnableOption "Kea DHCP4 server";
83
84 extraArgs = mkOption {
85 type = listOf str;
86 default = [];
87 description = ''
88 List of additional arguments to pass to the daemon.
89 '';
90 };
91
92 configFile = mkOption {
93 type = nullOr path;
94 default = null;
95 description = ''
96 Kea DHCP4 configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp4-srv.html>.
97
98 Takes preference over [settings](#opt-services.kea.dhcp4.settings).
99 Most users should prefer using [settings](#opt-services.kea.dhcp4.settings) instead.
100 '';
101 };
102
103 settings = mkOption {
104 type = format.type;
105 default = null;
106 example = {
107 valid-lifetime = 4000;
108 renew-timer = 1000;
109 rebind-timer = 2000;
110 interfaces-config = {
111 interfaces = [
112 "eth0"
113 ];
114 };
115 lease-database = {
116 type = "memfile";
117 persist = true;
118 name = "/var/lib/kea/dhcp4.leases";
119 };
120 subnet4 = [ {
121 subnet = "192.0.2.0/24";
122 pools = [ {
123 pool = "192.0.2.100 - 192.0.2.240";
124 } ];
125 } ];
126 };
127 description = ''
128 Kea DHCP4 configuration as an attribute set, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp4-srv.html>.
129 '';
130 };
131 };
132 };
133 };
134
135 dhcp6 = mkOption {
136 description = ''
137 DHCP6 Server configuration
138 '';
139 default = {};
140 type = submodule {
141 options = {
142 enable = mkEnableOption "Kea DHCP6 server";
143
144 extraArgs = mkOption {
145 type = listOf str;
146 default = [];
147 description = ''
148 List of additional arguments to pass to the daemon.
149 '';
150 };
151
152 configFile = mkOption {
153 type = nullOr path;
154 default = null;
155 description = ''
156 Kea DHCP6 configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp6-srv.html>.
157
158 Takes preference over [settings](#opt-services.kea.dhcp6.settings).
159 Most users should prefer using [settings](#opt-services.kea.dhcp6.settings) instead.
160 '';
161 };
162
163 settings = mkOption {
164 type = format.type;
165 default = null;
166 example = {
167 valid-lifetime = 4000;
168 renew-timer = 1000;
169 rebind-timer = 2000;
170 preferred-lifetime = 3000;
171 interfaces-config = {
172 interfaces = [
173 "eth0"
174 ];
175 };
176 lease-database = {
177 type = "memfile";
178 persist = true;
179 name = "/var/lib/kea/dhcp6.leases";
180 };
181 subnet6 = [ {
182 subnet = "2001:db8:1::/64";
183 pools = [ {
184 pool = "2001:db8:1::1-2001:db8:1::ffff";
185 } ];
186 } ];
187 };
188 description = ''
189 Kea DHCP6 configuration as an attribute set, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp6-srv.html>.
190 '';
191 };
192 };
193 };
194 };
195
196 dhcp-ddns = mkOption {
197 description = ''
198 Kea DHCP-DDNS configuration
199 '';
200 default = {};
201 type = submodule {
202 options = {
203 enable = mkEnableOption "Kea DDNS server";
204
205 extraArgs = mkOption {
206 type = listOf str;
207 default = [];
208 description = ''
209 List of additional arguments to pass to the daemon.
210 '';
211 };
212
213 configFile = mkOption {
214 type = nullOr path;
215 default = null;
216 description = ''
217 Kea DHCP-DDNS configuration as a path, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html>.
218
219 Takes preference over [settings](#opt-services.kea.dhcp-ddns.settings).
220 Most users should prefer using [settings](#opt-services.kea.dhcp-ddns.settings) instead.
221 '';
222 };
223
224 settings = mkOption {
225 type = format.type;
226 default = null;
227 example = {
228 ip-address = "127.0.0.1";
229 port = 53001;
230 dns-server-timeout = 100;
231 ncr-protocol = "UDP";
232 ncr-format = "JSON";
233 tsig-keys = [ ];
234 forward-ddns = {
235 ddns-domains = [ ];
236 };
237 reverse-ddns = {
238 ddns-domains = [ ];
239 };
240 };
241 description = ''
242 Kea DHCP-DDNS configuration as an attribute set, see <https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html>.
243 '';
244 };
245 };
246 };
247 };
248 };
249
250 config = let
251 commonServiceConfig = {
252 ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
253 DynamicUser = true;
254 User = "kea";
255 ConfigurationDirectory = "kea";
256 RuntimeDirectory = "kea";
257 RuntimeDirectoryPreserve = true;
258 StateDirectory = "kea";
259 UMask = "0077";
260 };
261 in mkIf (cfg.ctrl-agent.enable || cfg.dhcp4.enable || cfg.dhcp6.enable || cfg.dhcp-ddns.enable) (mkMerge [
262 {
263 environment.systemPackages = [ package ];
264 }
265
266 (mkIf cfg.ctrl-agent.enable {
267 assertions = [{
268 assertion = xor (cfg.ctrl-agent.settings == null) (cfg.ctrl-agent.configFile == null);
269 message = "Either services.kea.ctrl-agent.settings or services.kea.ctrl-agent.configFile must be set to a non-null value.";
270 }];
271
272 environment.etc."kea/ctrl-agent.conf".source = ctrlAgentConfig;
273
274 systemd.services.kea-ctrl-agent = {
275 description = "Kea Control Agent";
276 documentation = [
277 "man:kea-ctrl-agent(8)"
278 "https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html"
279 ];
280
281 after = [
282 "network-online.target"
283 "time-sync.target"
284 ];
285 wantedBy = [
286 "kea-dhcp4-server.service"
287 "kea-dhcp6-server.service"
288 "kea-dhcp-ddns-server.service"
289 ];
290
291 environment = {
292 KEA_PIDFILE_DIR = "/run/kea";
293 KEA_LOCKFILE_DIR = "/run/kea";
294 };
295
296 restartTriggers = [
297 ctrlAgentConfig
298 ];
299
300 serviceConfig = {
301 ExecStart = "${package}/bin/kea-ctrl-agent -c /etc/kea/ctrl-agent.conf ${lib.escapeShellArgs cfg.ctrl-agent.extraArgs}";
302 KillMode = "process";
303 Restart = "on-failure";
304 } // commonServiceConfig;
305 };
306 })
307
308 (mkIf cfg.dhcp4.enable {
309 assertions = [{
310 assertion = xor (cfg.dhcp4.settings == null) (cfg.dhcp4.configFile == null);
311 message = "Either services.kea.dhcp4.settings or services.kea.dhcp4.configFile must be set to a non-null value.";
312 }];
313
314 environment.etc."kea/dhcp4-server.conf".source = dhcp4Config;
315
316 systemd.services.kea-dhcp4-server = {
317 description = "Kea DHCP4 Server";
318 documentation = [
319 "man:kea-dhcp4(8)"
320 "https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp4-srv.html"
321 ];
322
323 after = [
324 "network-online.target"
325 "time-sync.target"
326 ];
327 wants = [
328 "network-online.target"
329 ];
330 wantedBy = [
331 "multi-user.target"
332 ];
333
334 environment = {
335 KEA_PIDFILE_DIR = "/run/kea";
336 KEA_LOCKFILE_DIR = "/run/kea";
337 };
338
339 restartTriggers = [
340 dhcp4Config
341 ];
342
343 serviceConfig = {
344 ExecStart = "${package}/bin/kea-dhcp4 -c /etc/kea/dhcp4-server.conf ${lib.escapeShellArgs cfg.dhcp4.extraArgs}";
345 # Kea does not request capabilities by itself
346 AmbientCapabilities = [
347 "CAP_NET_BIND_SERVICE"
348 "CAP_NET_RAW"
349 ];
350 CapabilityBoundingSet = [
351 "CAP_NET_BIND_SERVICE"
352 "CAP_NET_RAW"
353 ];
354 } // commonServiceConfig;
355 };
356 })
357
358 (mkIf cfg.dhcp6.enable {
359 assertions = [{
360 assertion = xor (cfg.dhcp6.settings == null) (cfg.dhcp6.configFile == null);
361 message = "Either services.kea.dhcp6.settings or services.kea.dhcp6.configFile must be set to a non-null value.";
362 }];
363
364 environment.etc."kea/dhcp6-server.conf".source = dhcp6Config;
365
366 systemd.services.kea-dhcp6-server = {
367 description = "Kea DHCP6 Server";
368 documentation = [
369 "man:kea-dhcp6(8)"
370 "https://kea.readthedocs.io/en/kea-${package.version}/arm/dhcp6-srv.html"
371 ];
372
373 after = [
374 "network-online.target"
375 "time-sync.target"
376 ];
377 wants = [
378 "network-online.target"
379 ];
380 wantedBy = [
381 "multi-user.target"
382 ];
383
384 environment = {
385 KEA_PIDFILE_DIR = "/run/kea";
386 KEA_LOCKFILE_DIR = "/run/kea";
387 };
388
389 restartTriggers = [
390 dhcp6Config
391 ];
392
393 serviceConfig = {
394 ExecStart = "${package}/bin/kea-dhcp6 -c /etc/kea/dhcp6-server.conf ${lib.escapeShellArgs cfg.dhcp6.extraArgs}";
395 # Kea does not request capabilities by itself
396 AmbientCapabilities = [
397 "CAP_NET_BIND_SERVICE"
398 ];
399 CapabilityBoundingSet = [
400 "CAP_NET_BIND_SERVICE"
401 ];
402 } // commonServiceConfig;
403 };
404 })
405
406 (mkIf cfg.dhcp-ddns.enable {
407 assertions = [{
408 assertion = xor (cfg.dhcp-ddns.settings == null) (cfg.dhcp-ddns.configFile == null);
409 message = "Either services.kea.dhcp-ddns.settings or services.kea.dhcp-ddns.configFile must be set to a non-null value.";
410 }];
411
412 environment.etc."kea/dhcp-ddns.conf".source = dhcpDdnsConfig;
413
414 systemd.services.kea-dhcp-ddns-server = {
415 description = "Kea DHCP-DDNS Server";
416 documentation = [
417 "man:kea-dhcp-ddns(8)"
418 "https://kea.readthedocs.io/en/kea-${package.version}/arm/ddns.html"
419 ];
420
421 wants = [ "network-online.target" ];
422 after = [
423 "network-online.target"
424 "time-sync.target"
425 ];
426 wantedBy = [
427 "multi-user.target"
428 ];
429
430 environment = {
431 KEA_PIDFILE_DIR = "/run/kea";
432 KEA_LOCKFILE_DIR = "/run/kea";
433 };
434
435 restartTriggers = [
436 dhcpDdnsConfig
437 ];
438
439 serviceConfig = {
440 ExecStart = "${package}/bin/kea-dhcp-ddns -c /etc/kea/dhcp-ddns.conf ${lib.escapeShellArgs cfg.dhcp-ddns.extraArgs}";
441 AmbientCapabilities = [
442 "CAP_NET_BIND_SERVICE"
443 ];
444 CapabilityBoundingSet = [
445 "CAP_NET_BIND_SERVICE"
446 ];
447 } // commonServiceConfig;
448 };
449 })
450
451 ]);
452
453 meta.maintainers = with maintainers; [ hexa ];
454 # uses attributes of the linked package
455 meta.buildDocsInSandbox = false;
456}