projects/guix·blob java-team · refs

1203 lines · 48.8 KiB

1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2017 Julien Lepiller <[email protected]>
3;;; Copyright © 2020 Pierre Langlois <[email protected]>
4;;; Copyright © 2021 Maxime Devos <[email protected]>
5;;; Copyright © 2022 Remco van 't Veer <[email protected]>
6;;; Copyright © 2024 Sören Tempel <[email protected]>
7;;; Copyright © 2026 Maxim Cournoyer <[email protected]>
8;;;
9;;; This file is part of GNU Guix.
10;;;
11;;; GNU Guix is free software; you can redistribute it and/or modify it
12;;; under the terms of the GNU General Public License as published by
13;;; the Free Software Foundation; either version 3 of the License, or (at
14;;; your option) any later version.
15;;;
16;;; GNU Guix is distributed in the hope that it will be useful, but
17;;; WITHOUT ANY WARRANTY; without even the implied warranty of
18;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19;;; GNU General Public License for more details.
20;;;
21;;; You should have received a copy of the GNU General Public License
22;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
23
24(define-module (gnu services dns)
25 #:use-module (gnu services)
26 #:use-module (gnu services configuration)
27 #:use-module (gnu services dbus)
28 #:use-module (gnu services shepherd)
29 #:use-module (gnu system shadow)
30 #:use-module (gnu packages admin)
31 #:use-module (gnu packages dns)
32 #:use-module (guix deprecation)
33 #:use-module (guix packages)
34 #:use-module (guix records)
35 #:use-module (guix gexp)
36 #:use-module (guix modules)
37 #:use-module (srfi srfi-1)
38 #:use-module (srfi srfi-26)
39 #:use-module (srfi srfi-34)
40 #:use-module (srfi srfi-35)
41 #:use-module (ice-9 match)
42 #:use-module (ice-9 regex)
43 #:export (knot-service-type
44 knot-acl-configuration
45 knot-key-configuration
46 knot-keystore-configuration
47 knot-zone-configuration
48 knot-remote-configuration
49 knot-policy-configuration
50 knot-configuration
51 define-zone-entries
52 zone-file
53 zone-entry
54
55 knot-resolver-service-type
56 knot-resolver-configuration
57
58 dnsmasq-service-type
59 dnsmasq-configuration
60 dnsmasq-configuration-package
61 dnsmasq-configuration-shepherd-provision
62 dnsmasq-configuration-shepherd-requirement
63 dnsmasq-configuration-pid-file
64 dnsmasq-configuration-no-hosts?
65 dnsmasq-configuration-port
66 dnsmasq-configuration-local-service?
67 dnsmasq-configuration-listen-address
68 dnsmasq-configuration-ipv4?
69 dnsmasq-configuration-ipv6?
70 dnsmasq-configuration-resolv-file
71 dnsmasq-configuration-no-resolv?
72 dnsmasq-configuration-authoritative-zones
73 dnsmasq-configuration-forward-private-reverse-lookup?
74 dnsmasq-configuration-query-servers-in-order?
75 dnsmasq-configuration-locals
76 dnsmasq-configuration-servers
77 dnsmasq-configuration-servers-file
78 dnsmasq-configuration-addresses
79 dnsmasq-configuration-cache-size
80 dnsmasq-configuration-negative-cache?
81 dnsmasq-configuration-cpe-id
82 dnsmasq-configuration-tftp-enable?
83 dnsmasq-configuration-tftp-no-fail?
84 dnsmasq-configuration-tftp-single-port?
85 dnsmasq-tftp-secure?
86 dnsmasq-tftp-max
87 dnsmasq-tftp-mtu
88 dnsmasq-tftp-no-blocksize?
89 dnsmasq-tftp-lowercase?
90 dnsmasq-tftp-port-range
91 dnsmasq-tftp-root
92 dnsmasq-tftp-unique-root
93 dnsmasq-configuration-conf-file
94 dnsmasq-configuration-conf-dir
95 dnsmasq-configuration-extra-options
96
97 unbound-service-type
98 unbound-configuration
99 unbound-configuration?
100 unbound-server
101 unbound-server?
102 unbound-zone
103 unbound-zone?
104 unbound-remote
105 unbound-remote?))
106
107;;;
108;;; Knot DNS.
109;;;
110
111(define-record-type* <knot-key-configuration>
112 knot-key-configuration make-knot-key-configuration
113 knot-key-configuration?
114 (id knot-key-configuration-id
115 (default ""))
116 (algorithm knot-key-configuration-algorithm
117 (default #f)); one of #f, or an algorithm name
118 (secret knot-key-configuration-secret
119 (default "")))
120
121(define-record-type* <knot-acl-configuration>
122 knot-acl-configuration make-knot-acl-configuration
123 knot-acl-configuration?
124 (id knot-acl-configuration-id
125 (default ""))
126 (address knot-acl-configuration-address
127 (default '()))
128 (key knot-acl-configuration-key
129 (default '()))
130 (action knot-acl-configuration-action
131 (default '()))
132 (deny? knot-acl-configuration-deny?
133 (default #f)))
134
135(define-record-type* <zone-entry>
136 zone-entry make-zone-entry
137 zone-entry?
138 (name zone-entry-name
139 (default "@"))
140 (ttl zone-entry-ttl
141 (default ""))
142 (class zone-entry-class
143 (default "IN"))
144 (type zone-entry-type
145 (default "A"))
146 (data zone-entry-data
147 (default "")))
148
149(define-record-type* <zone-file>
150 zone-file make-zone-file
151 zone-file?
152 (entries zone-file-entries
153 (default '()))
154 (origin zone-file-origin
155 (default ""))
156 (ns zone-file-ns
157 (default "ns"))
158 (mail zone-file-mail
159 (default "hostmaster"))
160 (serial zone-file-serial
161 (default 1))
162 (refresh zone-file-refresh
163 (default (* 12 3600)))
164 (retry zone-file-retry
165 (default (* 15 60)))
166 (expiry zone-file-expiry
167 (default (* 2 7 24 3600)))
168 (nx zone-file-nx
169 (default 3600)))
170(define-record-type* <knot-keystore-configuration>
171 knot-keystore-configuration make-knot-keystore-configuration
172 knot-keystore-configuration?
173 (id knot-keystore-configuration-id
174 (default ""))
175 (backend knot-keystore-configuration-backend
176 (default 'pem))
177 (config knot-keystore-configuration-config
178 (default "/var/lib/knot/keys/keys")))
179
180(define-record-type* <knot-policy-configuration>
181 knot-policy-configuration make-knot-policy-configuration
182 knot-policy-configuration?
183 (id knot-policy-configuration-id
184 (default ""))
185 (keystore knot-policy-configuration-keystore
186 (default "default"))
187 (manual? knot-policy-configuration-manual?
188 (default #f))
189 (single-type-signing? knot-policy-configuration-single-type-signing?
190 (default #f))
191 (algorithm knot-policy-configuration-algorithm
192 (default "ecdsap256sha256"))
193 (ksk-size knot-policy-configuration-ksk-size
194 (default 256))
195 (zsk-size knot-policy-configuration-zsk-size
196 (default 256))
197 (dnskey-ttl knot-policy-configuration-dnskey-ttl
198 (default 'default))
199 (zsk-lifetime knot-policy-configuration-zsk-lifetime
200 (default (* 30 24 3600)))
201 (propagation-delay knot-policy-configuration-propagation-delay
202 (default (* 24 3600)))
203 (rrsig-lifetime knot-policy-configuration-rrsig-lifetime
204 (default (* 14 24 3600)))
205 (rrsig-refresh knot-policy-configuration-rrsig-refresh
206 (default (* 7 24 3600)))
207 (nsec3? knot-policy-configuration-nsec3?
208 (default #f))
209 (nsec3-iterations knot-policy-configuration-nsec3-iterations
210 (default 5))
211 (nsec3-salt-length knot-policy-configuration-nsec3-salt-length
212 (default 8))
213 (nsec3-salt-lifetime knot-policy-configuration-nsec3-salt-lifetime
214 (default (* 30 24 3600))))
215
216(define-record-type* <knot-zone-configuration>
217 knot-zone-configuration make-knot-zone-configuration
218 knot-zone-configuration?
219 (domain knot-zone-configuration-domain
220 (default ""))
221 (file knot-zone-configuration-file
222 (default "")) ; the file where this zone is saved.
223 (zone knot-zone-configuration-zone
224 (default (zone-file))) ; initial content of the zone file
225 (master knot-zone-configuration-master
226 (default '()))
227 (ddns-master knot-zone-configuration-ddns-master
228 (default #f))
229 (notify knot-zone-configuration-notify
230 (default '()))
231 (acl knot-zone-configuration-acl
232 (default '()))
233 (semantic-checks? knot-zone-configuration-semantic-checks?
234 (default #f))
235 (zonefile-sync knot-zone-configuration-zonefile-sync
236 (default 0))
237 (zonefile-load knot-zone-configuration-zonefile-load
238 (default #f))
239 (journal-content knot-zone-configuration-journal-content
240 (default #f))
241 (max-journal-usage knot-zone-configuration-max-journal-usage
242 (default #f))
243 (max-journal-depth knot-zone-configuration-max-journal-depth
244 (default #f))
245 (max-zone-size knot-zone-configuration-max-zone-size
246 (default #f))
247 (dnssec-policy knot-zone-configuration-dnssec-policy
248 (default #f))
249 (serial-policy knot-zone-configuration-serial-policy
250 (default 'increment)))
251
252(define-record-type* <knot-remote-configuration>
253 knot-remote-configuration make-knot-remote-configuration
254 knot-remote-configuration?
255 (id knot-remote-configuration-id
256 (default ""))
257 (address knot-remote-configuration-address
258 (default '()))
259 (via knot-remote-configuration-via
260 (default '()))
261 (key knot-remote-configuration-key
262 (default #f)))
263
264(define-record-type* <knot-configuration>
265 knot-configuration make-knot-configuration
266 knot-configuration?
267 (knot knot-configuration-knot
268 (default knot))
269 (run-directory knot-configuration-run-directory
270 (default "/var/run/knot"))
271 (includes knot-configuration-includes
272 (default '()))
273 (listen-v4 knot-configuration-listen-v4
274 (default "0.0.0.0"))
275 (listen-v6 knot-configuration-listen-v6
276 (default "::"))
277 (listen-port knot-configuration-listen-port
278 (default 53))
279 (keys knot-configuration-keys
280 (default '()))
281 (keystores knot-configuration-keystores
282 (default '()))
283 (acls knot-configuration-acls
284 (default '()))
285 (remotes knot-configuration-remotes
286 (default '()))
287 (policies knot-configuration-policies
288 (default '()))
289 (zones knot-configuration-zones
290 (default '())))
291
292(define-syntax define-zone-entries
293 (syntax-rules ()
294 ((_ id (name ttl class type data) ...)
295 (define id (list (make-zone-entry name ttl class type data) ...)))))
296
297(define (error-out msg)
298 (raise (condition (&message (message msg)))))
299
300(define (verify-knot-key-configuration key)
301 (unless (knot-key-configuration? key)
302 (error-out "keys must be a list of only knot-key-configuration."))
303 (let ((id (knot-key-configuration-id key)))
304 (unless (and (string? id) (not (equal? id "")))
305 (error-out "key id must be a non empty string.")))
306 (unless (memq (knot-key-configuration-algorithm key)
307 '(#f hmac-md5 hmac-sha1 hmac-sha224 hmac-sha256 hmac-sha384 hmac-sha512))
308 (error-out "algorithm must be one of: #f, 'hmac-md5, 'hmac-sha1,
309'hmac-sha224, 'hmac-sha256, 'hmac-sha384 or 'hmac-sha512")))
310
311(define (verify-knot-keystore-configuration keystore)
312 (unless (knot-keystore-configuration? keystore)
313 (error-out "keystores must be a list of only knot-keystore-configuration."))
314 (let ((id (knot-keystore-configuration-id keystore)))
315 (unless (and (string? id) (not (equal? id "")))
316 (error-out "keystore id must be a non empty string.")))
317 (unless (memq (knot-keystore-configuration-backend keystore)
318 '(pem pkcs11))
319 (error-out "backend must be one of: 'pem or 'pkcs11")))
320
321(define (verify-knot-policy-configuration policy)
322 (unless (knot-policy-configuration? policy)
323 (error-out "policies must be a list of only knot-policy-configuration."))
324 (let ((id (knot-policy-configuration-id policy)))
325 (unless (and (string? id) (not (equal? id "")))
326 (error-out "policy id must be a non empty string."))))
327
328(define (verify-knot-acl-configuration acl)
329 (unless (knot-acl-configuration? acl)
330 (error-out "acls must be a list of only knot-acl-configuration."))
331 (let ((id (knot-acl-configuration-id acl))
332 (address (knot-acl-configuration-address acl))
333 (key (knot-acl-configuration-key acl))
334 (action (knot-acl-configuration-action acl)))
335 (unless (and (string? id) (not (equal? id "")))
336 (error-out "acl id must be a non empty string."))
337 (unless (and (list? address)
338 (every string? address))
339 (error-out "acl address must be a list of strings.")))
340 (unless (boolean? (knot-acl-configuration-deny? acl))
341 (error-out "deny? must be #t or #f.")))
342
343(define (verify-knot-zone-configuration zone)
344 (unless (knot-zone-configuration? zone)
345 (error-out "zones must be a list of only knot-zone-configuration."))
346 (let ((domain (knot-zone-configuration-domain zone)))
347 (unless (and (string? domain) (not (equal? domain "")))
348 (error-out "zone domain must be a non empty string."))))
349
350(define (verify-knot-remote-configuration remote)
351 (unless (knot-remote-configuration? remote)
352 (error-out "remotes must be a list of only knot-remote-configuration."))
353 (let ((id (knot-remote-configuration-id remote)))
354 (unless (and (string? id) (not (equal? id "")))
355 (error-out "remote id must be a non empty string."))))
356
357(define (verify-knot-configuration config)
358 (unless (file-like? (knot-configuration-knot config))
359 (error-out "knot configuration field must be a file-like object."))
360 (unless (string? (knot-configuration-run-directory config))
361 (error-out "run-directory must be a string."))
362 (unless (list? (knot-configuration-includes config))
363 (error-out "includes must be a list of strings or file-like objects."))
364 (unless (list? (knot-configuration-keys config))
365 (error-out "keys must be a list of knot-key-configuration."))
366 (for-each (lambda (key) (verify-knot-key-configuration key))
367 (knot-configuration-keys config))
368 (unless (list? (knot-configuration-keystores config))
369 (error-out "keystores must be a list of knot-keystore-configuration."))
370 (for-each (lambda (keystore) (verify-knot-keystore-configuration keystore))
371 (knot-configuration-keystores config))
372 (unless (list? (knot-configuration-acls config))
373 (error-out "acls must be a list of knot-acl-configuration."))
374 (for-each (lambda (acl) (verify-knot-acl-configuration acl))
375 (knot-configuration-acls config))
376 (unless (list? (knot-configuration-zones config))
377 (error-out "zones must be a list of knot-zone-configuration."))
378 (for-each (lambda (zone) (verify-knot-zone-configuration zone))
379 (knot-configuration-zones config))
380 (unless (list? (knot-configuration-policies config))
381 (error-out "policies must be a list of knot-policy-configuration."))
382 (for-each (lambda (policy) (verify-knot-policy-configuration policy))
383 (knot-configuration-policies config))
384 (unless (list? (knot-configuration-remotes config))
385 (error-out "remotes must be a list of knot-remote-configuration."))
386 (for-each (lambda (remote) (verify-knot-remote-configuration remote))
387 (knot-configuration-remotes config))
388 #t)
389
390(define (format-string-list l)
391 "Formats a list of string in YAML"
392 (if (eq? l '())
393 ""
394 (let ((l (reverse l)))
395 (string-append
396 "["
397 (fold (lambda (x1 x2)
398 (string-append (if (symbol? x1) (symbol->string x1) x1) ", "
399 (if (symbol? x2) (symbol->string x2) x2)))
400 (if (symbol? (car l)) (symbol->string (car l)) (car l)) (cdr l))
401 "]"))))
402
403(define (knot-acl-config acls)
404 (with-output-to-string
405 (lambda ()
406 (for-each
407 (lambda (acl-config)
408 (let ((id (knot-acl-configuration-id acl-config))
409 (address (knot-acl-configuration-address acl-config))
410 (key (knot-acl-configuration-key acl-config))
411 (action (knot-acl-configuration-action acl-config))
412 (deny? (knot-acl-configuration-deny? acl-config)))
413 (format #t " - id: ~a\n" id)
414 (unless (eq? address '())
415 (format #t " address: ~a\n" (format-string-list address)))
416 (unless (eq? key '())
417 (format #t " key: ~a\n" (format-string-list key)))
418 (unless (eq? action '())
419 (format #t " action: ~a\n" (format-string-list action)))
420 (format #t " deny: ~a\n" (if deny? "on" "off"))))
421 acls))))
422
423(define (knot-key-config keys)
424 (with-output-to-string
425 (lambda ()
426 (for-each
427 (lambda (key-config)
428 (let ((id (knot-key-configuration-id key-config))
429 (algorithm (knot-key-configuration-algorithm key-config))
430 (secret (knot-key-configuration-secret key-config)))
431 (format #t " - id: ~a\n" id)
432 (if algorithm
433 (format #t " algorithm: ~a\n" (symbol->string algorithm)))
434 (format #t " secret: ~a\n" secret)))
435 keys))))
436
437(define (knot-keystore-config keystores)
438 (with-output-to-string
439 (lambda ()
440 (for-each
441 (lambda (keystore-config)
442 (let ((id (knot-keystore-configuration-id keystore-config))
443 (backend (knot-keystore-configuration-backend keystore-config))
444 (config (knot-keystore-configuration-config keystore-config)))
445 (format #t " - id: ~a\n" id)
446 (format #t " backend: ~a\n" (symbol->string backend))
447 (format #t " config: \"~a\"\n" config)))
448 keystores))))
449
450(define (knot-policy-config policies)
451 (with-output-to-string
452 (lambda ()
453 (for-each
454 (lambda (policy-config)
455 (let ((id (knot-policy-configuration-id policy-config))
456 (keystore (knot-policy-configuration-keystore policy-config))
457 (manual? (knot-policy-configuration-manual? policy-config))
458 (single-type-signing? (knot-policy-configuration-single-type-signing?
459 policy-config))
460 (algorithm (knot-policy-configuration-algorithm policy-config))
461 (ksk-size (knot-policy-configuration-ksk-size policy-config))
462 (zsk-size (knot-policy-configuration-zsk-size policy-config))
463 (dnskey-ttl (knot-policy-configuration-dnskey-ttl policy-config))
464 (zsk-lifetime (knot-policy-configuration-zsk-lifetime policy-config))
465 (propagation-delay (knot-policy-configuration-propagation-delay
466 policy-config))
467 (rrsig-lifetime (knot-policy-configuration-rrsig-lifetime
468 policy-config))
469 (nsec3? (knot-policy-configuration-nsec3? policy-config))
470 (nsec3-iterations (knot-policy-configuration-nsec3-iterations
471 policy-config))
472 (nsec3-salt-length (knot-policy-configuration-nsec3-salt-length
473 policy-config))
474 (nsec3-salt-lifetime (knot-policy-configuration-nsec3-salt-lifetime
475 policy-config)))
476 (format #t " - id: ~a\n" id)
477 (format #t " keystore: ~a\n" keystore)
478 (format #t " manual: ~a\n" (if manual? "on" "off"))
479 (format #t " single-type-signing: ~a\n" (if single-type-signing?
480 "on" "off"))
481 (format #t " algorithm: ~a\n" algorithm)
482 (format #t " ksk-size: ~a\n" (number->string ksk-size))
483 (format #t " zsk-size: ~a\n" (number->string zsk-size))
484 (unless (eq? dnskey-ttl 'default)
485 (format #t " dnskey-ttl: ~a\n" dnskey-ttl))
486 (format #t " zsk-lifetime: ~a\n" zsk-lifetime)
487 (format #t " propagation-delay: ~a\n" propagation-delay)
488 (format #t " rrsig-lifetime: ~a\n" rrsig-lifetime)
489 (format #t " nsec3: ~a\n" (if nsec3? "on" "off"))
490 (format #t " nsec3-iterations: ~a\n"
491 (number->string nsec3-iterations))
492 (format #t " nsec3-salt-length: ~a\n"
493 (number->string nsec3-salt-length))
494 (format #t " nsec3-salt-lifetime: ~a\n" nsec3-salt-lifetime)))
495 policies))))
496
497(define (knot-remote-config remotes)
498 (with-output-to-string
499 (lambda ()
500 (for-each
501 (lambda (remote-config)
502 (let ((id (knot-remote-configuration-id remote-config))
503 (address (knot-remote-configuration-address remote-config))
504 (via (knot-remote-configuration-via remote-config))
505 (key (knot-remote-configuration-key remote-config)))
506 (format #t " - id: ~a\n" id)
507 (unless (eq? address '())
508 (format #t " address: ~a\n" (format-string-list address)))
509 (unless (eq? via '())
510 (format #t " via: ~a\n" (format-string-list via)))
511 (if key
512 (format #t " key: ~a\n" key))))
513 remotes))))
514
515(define (serialize-zone-entries entries)
516 (with-output-to-string
517 (lambda ()
518 (for-each
519 (lambda (entry)
520 (let ((name (zone-entry-name entry))
521 (ttl (zone-entry-ttl entry))
522 (class (zone-entry-class entry))
523 (type (zone-entry-type entry))
524 (data (zone-entry-data entry)))
525 (format #t "~a ~a ~a ~a ~a\n" name ttl class type data)))
526 entries))))
527
528(define (serialize-zone-file zone domain)
529 (computed-file (string-append domain ".zone")
530 #~(begin
531 (call-with-output-file #$output
532 (lambda (port)
533 (format port "$ORIGIN ~a.\n"
534 #$(zone-file-origin zone))
535 (format port "@ IN SOA ~a ~a (~a ~a ~a ~a ~a)\n"
536 #$(zone-file-ns zone)
537 #$(zone-file-mail zone)
538 #$(zone-file-serial zone)
539 #$(zone-file-refresh zone)
540 #$(zone-file-retry zone)
541 #$(zone-file-expiry zone)
542 #$(zone-file-nx zone))
543 (format port "~a\n"
544 #$(serialize-zone-entries (zone-file-entries zone))))))))
545
546(define (knot-zone-config zone)
547 (let ((content (knot-zone-configuration-zone zone)))
548 #~(with-output-to-string
549 (lambda ()
550 (let ((domain #$(knot-zone-configuration-domain zone))
551 (file #$(knot-zone-configuration-file zone))
552 (master (list #$@(knot-zone-configuration-master zone)))
553 (ddns-master #$(knot-zone-configuration-ddns-master zone))
554 (notify (list #$@(knot-zone-configuration-notify zone)))
555 (acl (list #$@(knot-zone-configuration-acl zone)))
556 (semantic-checks? #$(knot-zone-configuration-semantic-checks? zone))
557 (zonefile-sync #$(knot-zone-configuration-zonefile-sync zone))
558 (zonefile-load '#$(knot-zone-configuration-zonefile-load zone))
559 (journal-content #$(knot-zone-configuration-journal-content zone))
560 (max-journal-usage #$(knot-zone-configuration-max-journal-usage zone))
561 (max-journal-depth #$(knot-zone-configuration-max-journal-depth zone))
562 (max-zone-size #$(knot-zone-configuration-max-zone-size zone))
563 (dnssec-policy #$(knot-zone-configuration-dnssec-policy zone))
564 (serial-policy '#$(knot-zone-configuration-serial-policy zone)))
565 (format #t " - domain: ~a\n" domain)
566 (if (eq? master '())
567 ;; This server is a master
568 (if (equal? file "")
569 (format #t " file: ~a\n"
570 #$(serialize-zone-file content
571 (knot-zone-configuration-domain zone)))
572 (format #t " file: ~a\n" file))
573 ;; This server is a slave (has masters)
574 (begin
575 (format #t " master: ~a\n"
576 #$(format-string-list
577 (knot-zone-configuration-master zone)))
578 (if ddns-master (format #t " ddns-master ~a\n" ddns-master))))
579 (unless (eq? notify '())
580 (format #t " notify: ~a\n"
581 #$(format-string-list
582 (knot-zone-configuration-notify zone))))
583 (unless (eq? acl '())
584 (format #t " acl: ~a\n"
585 #$(format-string-list
586 (knot-zone-configuration-acl zone))))
587 (format #t " semantic-checks: ~a\n" (if semantic-checks? "on" "off"))
588 (if zonefile-sync
589 (format #t " zonefile-sync: ~a\n" zonefile-sync))
590 (if zonefile-load
591 (format #t " zonefile-load: ~a\n"
592 (symbol->string zonefile-load)))
593 (if journal-content
594 (format #t " journal-content: ~a\n"
595 (symbol->string journal-content)))
596 (if max-journal-usage
597 (format #t " max-journal-usage: ~a\n" max-journal-usage))
598 (if max-journal-depth
599 (format #t " max-journal-depth: ~a\n" max-journal-depth))
600 (if max-zone-size
601 (format #t " max-zone-size: ~a\n" max-zone-size))
602 (if dnssec-policy
603 (begin
604 (format #t " dnssec-signing: on\n")
605 (format #t " dnssec-policy: ~a\n" dnssec-policy)))
606 (format #t " serial-policy: ~a\n"
607 (symbol->string serial-policy)))))))
608
609(define (knot-config-file config)
610 (verify-knot-configuration config)
611 (computed-file "knot.conf"
612 #~(begin
613 (call-with-output-file #$output
614 (lambda (port)
615 (for-each (lambda (inc)
616 (format port "include: ~a\n" inc))
617 '#$(knot-configuration-includes config))
618 (format port "server:\n")
619 (format port " rundir: ~a\n" #$(knot-configuration-run-directory config))
620 (format port " user: knot\n")
621 (format port " listen: ~a@~a\n"
622 #$(knot-configuration-listen-v4 config)
623 #$(knot-configuration-listen-port config))
624 (format port " listen: ~a@~a\n"
625 #$(knot-configuration-listen-v6 config)
626 #$(knot-configuration-listen-port config))
627 (format port "\nkey:\n")
628 (format port #$(knot-key-config (knot-configuration-keys config)))
629 (format port "\nkeystore:\n")
630 (format port #$(knot-keystore-config (knot-configuration-keystores config)))
631 (format port "\nacl:\n")
632 (format port #$(knot-acl-config (knot-configuration-acls config)))
633 (format port "\nremote:\n")
634 (format port #$(knot-remote-config (knot-configuration-remotes config)))
635 (format port "\npolicy:\n")
636 (format port #$(knot-policy-config (knot-configuration-policies config)))
637 (unless #$(eq? (knot-configuration-zones config) '())
638 (format port "\nzone:\n")
639 (format port "~a\n"
640 (string-concatenate
641 (list #$@(map knot-zone-config
642 (knot-configuration-zones config)))))))))))
643
644(define %knot-accounts
645 (list (user-group (name "knot") (system? #t))
646 (user-account
647 (name "knot")
648 (group "knot")
649 (system? #t)
650 (comment "knot dns server user")
651 (home-directory "/var/empty")
652 (shell (file-append shadow "/sbin/nologin")))))
653
654(define (knot-activation config)
655 (with-imported-modules (source-module-closure '((gnu build activation)))
656 #~(begin
657 (use-modules (gnu build activation))
658 (mkdir-p/perms #$(knot-configuration-run-directory config)
659 (getpwnam "knot") #o755)
660 (mkdir-p/perms "/var/lib/knot" (getpwnam "knot") #o755)
661 (mkdir-p/perms "/var/lib/knot/keys" (getpwnam "knot") #o755)
662 (mkdir-p/perms "/var/lib/knot/keys/keys" (getpwnam "knot") #o755))))
663
664(define (knot-shepherd-service config)
665 (let* ((config-file (knot-config-file config))
666 (knot (knot-configuration-knot config)))
667 (list (shepherd-service
668 (documentation "Run the Knot DNS daemon.")
669 (provision '(knot dns))
670 (requirement '(networking user-processes))
671 (actions (list (shepherd-configuration-action config-file)))
672 (start #~(make-forkexec-constructor
673 (list (string-append #$knot "/sbin/knotd")
674 "-c" #$config-file)))
675 (stop #~(make-kill-destructor))))))
676
677(define knot-service-type
678 (service-type (name 'knot)
679 (extensions
680 (list (service-extension shepherd-root-service-type
681 knot-shepherd-service)
682 (service-extension activation-service-type
683 knot-activation)
684 (service-extension account-service-type
685 (const %knot-accounts))))
686 (description
687 "Run @uref{https://www.knot-dns.cz/, Knot}, an authoritative
688name server for the @acronym{DNS, Domain Name System}.")))
689
690
691;;;
692;;; Knot Resolver.
693;;;
694
695(define-record-type* <knot-resolver-configuration>
696 knot-resolver-configuration
697 make-knot-resolver-configuration
698 knot-resolver-configuration?
699 (package knot-resolver-configuration-package
700 (default knot-resolver))
701 (kresd-config-file knot-resolver-kresd-config-file
702 (default %kresd.conf))
703 (garbage-collection-interval knot-resolver-garbage-collection-interval
704 (default 1000)))
705
706(define %kresd.conf
707 (plain-file "kresd.conf" "-- -*- mode: lua -*-
708trust_anchors.add_file('/var/cache/knot-resolver/root.keys')
709net = { '127.0.0.1', '::1' }
710user('knot-resolver', 'knot-resolver')
711modules = { 'hints > iterate', 'stats', 'predict' }
712cache.size = 100 * MB
713"))
714
715(define %knot-resolver-accounts
716 (list (user-group
717 (name "knot-resolver")
718 (system? #t))
719 (user-account
720 (name "knot-resolver")
721 (group "knot-resolver")
722 (system? #t)
723 (home-directory "/var/cache/knot-resolver")
724 (shell (file-append shadow "/sbin/nologin")))))
725
726(define (knot-resolver-activation config)
727 #~(begin
728 (use-modules (guix build utils))
729 (let ((rundir "/var/cache/knot-resolver")
730 (owner (getpwnam "knot-resolver")))
731 (mkdir-p rundir)
732 (chown rundir (passwd:uid owner) (passwd:gid owner)))))
733
734(define knot-resolver-shepherd-services
735 (match-lambda
736 (($ <knot-resolver-configuration> package
737 kresd-config-file
738 garbage-collection-interval)
739 (list
740 (shepherd-service
741 (provision '(kresd))
742 (requirement '(user-processes networking))
743 (documentation "Run the Knot Resolver daemon.")
744 (start #~(make-forkexec-constructor
745 '(#$(file-append package "/sbin/kresd")
746 "-c" #$kresd-config-file "-n"
747 "/var/cache/knot-resolver")))
748 (stop #~(make-kill-destructor)))
749 (shepherd-service
750 (provision '(kres-cache-gc))
751 (requirement '(user-processes))
752 (documentation "Run the Knot Resolver Garbage Collector daemon.")
753 (start #~(make-forkexec-constructor
754 '(#$(file-append package "/sbin/kres-cache-gc")
755 "-d" #$(number->string garbage-collection-interval)
756 "-c" "/var/cache/knot-resolver")
757 #:user "knot-resolver"
758 #:group "knot-resolver"))
759 (stop #~(make-kill-destructor)))))))
760
761(define knot-resolver-service-type
762 (service-type
763 (name 'knot-resolver)
764 (extensions
765 (list (service-extension shepherd-root-service-type
766 knot-resolver-shepherd-services)
767 (service-extension activation-service-type
768 knot-resolver-activation)
769 (service-extension account-service-type
770 (const %knot-resolver-accounts))))
771 (default-value (knot-resolver-configuration))
772 (description "Run the Knot DNS Resolver.")))
773
774
775;;;
776;;; Dnsmasq.
777;;;
778
779(define-record-type* <dnsmasq-configuration>
780 dnsmasq-configuration make-dnsmasq-configuration
781 dnsmasq-configuration?
782 (package dnsmasq-configuration-package
783 (default dnsmasq)) ;file-like
784 (provision dnsmasq-configuration-provision ; deprecated
785 (default #f)
786 (sanitize warn-deprecated-dnsmasq-configuration-provision))
787 (shepherd-provision dnsmasq-configuration-shepherd-provision
788 (default '(dnsmasq)))
789 (shepherd-requirement dnsmasq-configuration-shepherd-requirement
790 (default '(user-processes networking)))
791 (no-hosts? dnsmasq-configuration-no-hosts?
792 (default #f)) ;boolean
793 (pid-file dnsmasq-configuration-pid-file
794 (default "/run/dnsmasq.pid")) ;string
795 (port dnsmasq-configuration-port
796 (default 53)) ;integer
797 (local-service? dnsmasq-configuration-local-service?
798 (default #t)) ;boolean
799 (listen-addresses dnsmasq-configuration-listen-address
800 (default '())) ;list of string
801 (ipv4? dnsmasq-configuration-ipv4?
802 (default #t))
803 (ipv6? dnsmasq-configuration-ipv6?
804 (default #t))
805 (resolv-file dnsmasq-configuration-resolv-file
806 (default "/etc/resolv.conf")) ;string
807 (no-resolv? dnsmasq-configuration-no-resolv?
808 (default #f)) ;boolean
809 (authoritative-servers dnsmasq-configuration-authoritative-servers
810 (default '())) ;list of strings
811 (authoritative-zones dnsmasq-configuration-authoritative-zones
812 (default '())) ;list of strings
813 (host-records dnsmasq-configuration-host-records
814 (default '())) ;list of strings
815 (forward-private-reverse-lookup?
816 dnsmasq-configuration-forward-private-reverse-lookup?
817 (default #t)) ;boolean
818 (query-servers-in-order?
819 dnsmasq-configuration-query-servers-in-order?
820 (default #f)) ;boolean
821 (locals dnsmasq-configuration-locals
822 (default '()))
823 (servers dnsmasq-configuration-servers
824 (default '())) ;list of string
825 (servers-file dnsmasq-configuration-servers-file
826 (default #f)) ;string|file-like
827 (addresses dnsmasq-configuration-addresses
828 (default '())) ;list of string
829 (cache-size dnsmasq-configuration-cache-size
830 (default 150)) ;integer
831 (negative-cache? dnsmasq-configuration-negative-cache?
832 (default #t)) ;boolean
833 (cpe-id dnsmasq-configuration-cpe-id
834 (default #f)) ;string
835 (tftp-enable? dnsmasq-configuration-tftp-enable?
836 (default #f)) ;boolean
837 (tftp-no-fail? dnsmasq-configuration-tftp-no-fail?
838 (default #f)) ;boolean
839 (tftp-single-port? dnsmasq-configuration-tftp-single-port?
840 (default #f)) ;boolean
841 (tftp-secure? dnsmasq-tftp-secure?
842 (default #f)) ;boolean
843 (tftp-max dnsmasq-tftp-max
844 (default #f)) ;integer
845 (tftp-mtu dnsmasq-tftp-mtu
846 (default #f)) ;integer
847 (tftp-no-blocksize? dnsmasq-tftp-no-blocksize?
848 (default #f)) ;boolean
849 (tftp-lowercase? dnsmasq-tftp-lowercase?
850 (default #f)) ;boolean
851 (tftp-port-range dnsmasq-tftp-port-range
852 (default #f)) ;string
853 (tftp-root dnsmasq-tftp-root
854 (default "/var/empty,lo")) ;string
855 (tftp-unique-root dnsmasq-tftp-unique-root
856 (default #f)) ;"" or "ip" or "mac"
857 (conf-file dnsmasq-configuration-conf-file
858 (default '())) ;list of string|file-like
859 (conf-dir dnsmasq-configuration-conf-dir
860 (default #f)) ;string|file-like
861 (extra-options dnsmasq-configuration-extra-options
862 (default '()))) ;list of string
863
864(define (warn-deprecated-dnsmasq-configuration-provision value)
865 (when (pair? value)
866 (warn-about-deprecation
867 'provision #f
868 #:replacement 'shepherd-provision))
869 value)
870
871(define (dnsmasq-shepherd-service config)
872 (match-record config <dnsmasq-configuration>
873 (package
874 provision
875 shepherd-provision
876 shepherd-requirement
877 pid-file
878 no-hosts?
879 port local-service? listen-addresses ipv4? ipv6?
880 resolv-file no-resolv?
881 authoritative-servers authoritative-zones host-records
882 forward-private-reverse-lookup? query-servers-in-order?
883 locals servers addresses servers-file
884 cache-size negative-cache?
885 cpe-id
886 tftp-enable? tftp-no-fail?
887 tftp-single-port? tftp-secure?
888 tftp-max tftp-mtu tftp-no-blocksize?
889 tftp-lowercase? tftp-port-range
890 tftp-root tftp-unique-root
891 conf-file conf-dir extra-options)
892 (shepherd-service
893 (provision (or provision shepherd-provision))
894 (requirement shepherd-requirement)
895 (documentation "Run the dnsmasq DNS server.")
896 (actions (list (dnsmasq-service-reload-action config)
897 (dnsmasq-service-stats-action config)))
898 (start #~(make-forkexec-constructor
899 (list
900 #$(file-append package "/sbin/dnsmasq")
901 "--keep-in-foreground"
902 (string-append "--pid-file=" #$pid-file)
903 #$@(if no-hosts?
904 '("--no-hosts")
905 '())
906 #$(format #f "--port=~a" port)
907 #$@(if local-service?
908 '("--local-service")
909 '())
910 #$@(map (cut format #f "--listen-address=~a" <>)
911 listen-addresses)
912 #$@(if (not ipv4?)
913 '("--filter-A")
914 '())
915 #$@(if (not ipv6?)
916 '("--filter-AAAA")
917 '())
918 #$(format #f "--resolv-file=~a" resolv-file)
919 #$@(if no-resolv?
920 '("--no-resolv")
921 '())
922 #$@(map (cut format #f "--auth-server=~a" <>)
923 authoritative-servers)
924 #$@(map (cut format #f "--auth-zone=~a" <>)
925 authoritative-zones)
926 #$@(map (cut format #f "--host-record=~a" <>)
927 host-records)
928 #$@(if forward-private-reverse-lookup?
929 '()
930 '("--bogus-priv"))
931 #$@(if query-servers-in-order?
932 '("--strict-order")
933 '())
934 #$@(if servers-file
935 (list #~(string-append "--servers-file=" #$servers-file))
936 '())
937 #$@(map (cut format #f "--local=~a" <>)
938 locals)
939 #$@(map (cut format #f "--server=~a" <>)
940 servers)
941 #$@(map (cut format #f "--address=~a" <>)
942 addresses)
943 #$(format #f "--cache-size=~a" cache-size)
944 #$@(if negative-cache?
945 '()
946 '("--no-negcache"))
947 #$@(if cpe-id
948 (list (format #f "--add-cpe-id=~a" cpe-id))
949 '())
950 #$@(if tftp-enable?
951 '("--enable-tftp")
952 '())
953 #$@(if tftp-no-fail?
954 '("--tftp-no-fail")
955 '())
956 #$@(if tftp-single-port?
957 '("--tftp-single-port")
958 '())
959 #$@(if tftp-secure?
960 '("--tftp-secure")
961 '())
962 #$@(if tftp-max
963 (list (format #f "--tftp-max=~a" tftp-max))
964 '())
965 #$@(if tftp-mtu
966 (list (format #f "--tftp-mtu=~a" tftp-mtu))
967 '())
968 #$@(if tftp-no-blocksize?
969 '("--tftp-no-blocksize")
970 '())
971 #$@(if tftp-lowercase?
972 '("--tftp-lowercase")
973 '())
974 #$@(if tftp-port-range
975 (list (format #f "--tftp-port-range=~a"
976 tftp-port-range))
977 '())
978 #$@(if tftp-root
979 (list (format #f "--tftp-root=~a" tftp-root))
980 '())
981 #$@(if tftp-unique-root
982 (list
983 (if (> (length tftp-unique-root) 0)
984 (format #f "--tftp-unique-root=~a" tftp-unique-root)
985 (format #f "--tftp-unique-root")))
986 '())
987 #$@(map (lambda (conf-file)
988 #~(string-append "--conf-file=" #$conf-file))
989 conf-file)
990 #$@(if conf-dir
991 (list #~(string-append "--conf-dir=" #$conf-dir))
992 '())
993 #$@extra-options)
994 #:pid-file #$pid-file))
995 (stop #~(make-kill-destructor)))))
996
997(define (dnsmasq-activation config)
998 #~(begin
999 (use-modules (guix build utils))
1000 ;; create directory to store dnsmasq lease file
1001 (mkdir-p "/var/lib/misc")))
1002
1003(define (dnsmasq-service-reload-action config)
1004 (shepherd-signal-action
1005 'reload SIGHUP
1006 #:documentation "Send a @code{SIGHUP} signal to @command{dnsmasq} to clear
1007cache and reload hosts files."))
1008
1009(define (dnsmasq-service-stats-action config)
1010 (shepherd-signal-action
1011 'stats SIGUSR1
1012 #:documentation "Send a @code{SIGUSR1} to write statistics to the system
1013log."))
1014
1015(define dnsmasq-service-type
1016 (service-type
1017 (name 'dnsmasq)
1018 (extensions
1019 (list (service-extension shepherd-root-service-type
1020 (compose list dnsmasq-shepherd-service))
1021 (service-extension dbus-root-service-type
1022 (compose list dnsmasq-configuration-package))
1023 (service-extension activation-service-type
1024 dnsmasq-activation)))
1025 (default-value (dnsmasq-configuration))
1026 (description "Run the dnsmasq DNS server.")))
1027
1028
1029;;;
1030;;; Unbound.
1031;;;
1032
1033(define (unbound-serialize-field field-name value)
1034 (let ((field (object->string field-name))
1035 (value (cond
1036 ((boolean? value) (if value "yes" "no"))
1037 ((string? value) value)
1038 (else (object->string value)))))
1039 (if (string=? field "extra-content")
1040 #~(string-append #$value "\n")
1041 #~(format #f " ~a: ~s~%" #$field #$value))))
1042
1043(define (unbound-serialize-alist field-name value)
1044 #~(string-append #$@(generic-serialize-alist list
1045 unbound-serialize-field
1046 value)))
1047
1048(define (unbound-serialize-section section-name value fields)
1049 #~(format #f "~a:~%~a"
1050 #$(object->string section-name)
1051 #$(serialize-configuration value fields)))
1052
1053(define unbound-serialize-string unbound-serialize-field)
1054(define unbound-serialize-boolean unbound-serialize-field)
1055
1056(define-maybe string (prefix unbound-))
1057(define-maybe list-of-strings (prefix unbound-))
1058(define-maybe boolean (prefix unbound-))
1059
1060(define (unbound-serialize-list-of-strings field-name value)
1061 #~(string-append #$@(map (cut unbound-serialize-string field-name <>) value)))
1062
1063(define-configuration unbound-zone
1064 (name
1065 string
1066 "Zone name.")
1067
1068 (forward-addr
1069 maybe-list-of-strings
1070 "IP address of server to forward to.")
1071
1072 (forward-tls-upstream
1073 maybe-boolean
1074 "Whether the queries to this forwarder use TLS for transport.")
1075
1076 (extra-options
1077 (alist '())
1078 "An association list of options to append.")
1079
1080 (prefix unbound-))
1081
1082(define (unbound-serialize-unbound-zone field-name value)
1083 (unbound-serialize-section field-name value unbound-zone-fields))
1084
1085(define (unbound-serialize-list-of-unbound-zone field-name value)
1086 #~(string-append #$@(map (cut unbound-serialize-unbound-zone field-name <>)
1087 value)))
1088
1089(define list-of-unbound-zone? (list-of unbound-zone?))
1090
1091(define-configuration unbound-remote
1092 (control-enable
1093 maybe-boolean
1094 "Enable remote control.")
1095
1096 (control-interface
1097 maybe-string
1098 "IP address or local socket path to listen on for remote control.")
1099
1100 (extra-options
1101 (alist '())
1102 "An association list of options to append.")
1103
1104 (prefix unbound-))
1105
1106(define (unbound-serialize-unbound-remote field-name value)
1107 (unbound-serialize-section field-name value unbound-remote-fields))
1108
1109(define-configuration unbound-server
1110 (interface
1111 maybe-list-of-strings
1112 "Interfaces listened on for queries from clients.")
1113
1114 (hide-version
1115 maybe-boolean
1116 "Refuse the version.server and version.bind queries.")
1117
1118 (hide-identity
1119 maybe-boolean
1120 "Refuse the id.server and hostname.bind queries.")
1121
1122 (tls-cert-bundle
1123 maybe-string
1124 "Certificate bundle file, used for DNS over TLS.")
1125
1126 (extra-options
1127 (alist '())
1128 "An association list of options to append.")
1129
1130 (prefix unbound-))
1131
1132(define (unbound-serialize-unbound-server field-name value)
1133 (unbound-serialize-section field-name value unbound-server-fields))
1134
1135(define-configuration unbound-configuration
1136 (server
1137 (unbound-server
1138 (unbound-server
1139 (interface '("127.0.0.1" "::1"))
1140
1141 (hide-version #t)
1142 (hide-identity #t)
1143
1144 (tls-cert-bundle "/etc/ssl/certs/ca-certificates.crt")))
1145 "General options for the Unbound server.")
1146
1147 (remote-control
1148 (unbound-remote
1149 (unbound-remote
1150 (control-enable #t)
1151 (control-interface "/run/unbound.sock")))
1152 "Remote control options for the daemon.")
1153
1154 (forward-zone
1155 (list-of-unbound-zone '())
1156 "A zone for which queries should be forwarded to another resolver.")
1157
1158 (extra-content
1159 maybe-string
1160 "Raw content to add to the configuration file.")
1161
1162 (prefix unbound-))
1163
1164(define (unbound-config-file config)
1165 (mixed-text-file "unbound.conf"
1166 (serialize-configuration
1167 config
1168 unbound-configuration-fields)))
1169
1170(define (unbound-shepherd-service config)
1171 (let ((config-file (unbound-config-file config)))
1172 (list (shepherd-service
1173 (documentation "Unbound daemon.")
1174 (provision '(unbound))
1175 ;; unbound may be bound to a particular IP address, hence
1176 ;; only start it after the networking service has started.
1177 (requirement '(user-processes networking))
1178 (actions (list (shepherd-configuration-action config-file)))
1179 (start #~(make-forkexec-constructor
1180 (list (string-append #$unbound "/sbin/unbound")
1181 "-d" "-p" "-c" #$config-file)))
1182 (stop #~(make-kill-destructor))))))
1183
1184(define unbound-account-service
1185 (list (user-group (name "unbound") (system? #t))
1186 (user-account
1187 (name "unbound")
1188 (group "unbound")
1189 (system? #t)
1190 (comment "Unbound daemon user")
1191 (home-directory "/var/empty")
1192 (shell (file-append shadow "/sbin/nologin")))))
1193
1194(define unbound-service-type
1195 (service-type (name 'unbound)
1196 (description "Run the Unbound DNS resolver.")
1197 (extensions
1198 (list (service-extension account-service-type
1199 (const unbound-account-service))
1200 (service-extension shepherd-root-service-type
1201 unbound-shepherd-service)))
1202 (compose concatenate)
1203 (default-value (unbound-configuration))))