dns.scm 44 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. ;;; GNU Guix --- Functional package management for GNU
  2. ;;; Copyright © 2017 Julien Lepiller <julien@lepiller.eu>
  3. ;;; Copyright © 2018 Oleg Pykhalov <go.wigust@gmail.com>
  4. ;;; Copyright © 2020 Pierre Langlois <pierre.langlois@gmx.com>
  5. ;;; Copyright © 2021 Maxime Devos <maximedevos@telenet.be>
  6. ;;; Copyright © 2022 Remco van 't Veer <remco@remworks.net>
  7. ;;;
  8. ;;; This file is part of GNU Guix.
  9. ;;;
  10. ;;; GNU Guix is free software; you can redistribute it and/or modify it
  11. ;;; under the terms of the GNU General Public License as published by
  12. ;;; the Free Software Foundation; either version 3 of the License, or (at
  13. ;;; your option) any later version.
  14. ;;;
  15. ;;; GNU Guix is distributed in the hope that it will be useful, but
  16. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  17. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. ;;; GNU General Public License for more details.
  19. ;;;
  20. ;;; You should have received a copy of the GNU General Public License
  21. ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
  22. (define-module (gnu services dns)
  23. #:use-module (gnu services)
  24. #:use-module (gnu services configuration)
  25. #:use-module (gnu services shepherd)
  26. #:use-module (gnu system shadow)
  27. #:use-module (gnu packages admin)
  28. #:use-module (gnu packages dns)
  29. #:use-module (guix packages)
  30. #:use-module (guix records)
  31. #:use-module (guix gexp)
  32. #:use-module (guix modules)
  33. #:use-module (srfi srfi-1)
  34. #:use-module (srfi srfi-26)
  35. #:use-module (srfi srfi-34)
  36. #:use-module (srfi srfi-35)
  37. #:use-module (ice-9 match)
  38. #:use-module (ice-9 regex)
  39. #:export (knot-service-type
  40. knot-acl-configuration
  41. knot-key-configuration
  42. knot-keystore-configuration
  43. knot-zone-configuration
  44. knot-remote-configuration
  45. knot-policy-configuration
  46. knot-configuration
  47. define-zone-entries
  48. zone-file
  49. zone-entry
  50. knot-resolver-service-type
  51. knot-resolver-configuration
  52. dnsmasq-service-type
  53. dnsmasq-configuration
  54. ddclient-service-type
  55. ddclient-configuration))
  56. ;;;
  57. ;;; Knot DNS.
  58. ;;;
  59. (define-record-type* <knot-key-configuration>
  60. knot-key-configuration make-knot-key-configuration
  61. knot-key-configuration?
  62. (id knot-key-configuration-id
  63. (default ""))
  64. (algorithm knot-key-configuration-algorithm
  65. (default #f)); one of #f, or an algorithm name
  66. (secret knot-key-configuration-secret
  67. (default "")))
  68. (define-record-type* <knot-acl-configuration>
  69. knot-acl-configuration make-knot-acl-configuration
  70. knot-acl-configuration?
  71. (id knot-acl-configuration-id
  72. (default ""))
  73. (address knot-acl-configuration-address
  74. (default '()))
  75. (key knot-acl-configuration-key
  76. (default '()))
  77. (action knot-acl-configuration-action
  78. (default '()))
  79. (deny? knot-acl-configuration-deny?
  80. (default #f)))
  81. (define-record-type* <zone-entry>
  82. zone-entry make-zone-entry
  83. zone-entry?
  84. (name zone-entry-name
  85. (default "@"))
  86. (ttl zone-entry-ttl
  87. (default ""))
  88. (class zone-entry-class
  89. (default "IN"))
  90. (type zone-entry-type
  91. (default "A"))
  92. (data zone-entry-data
  93. (default "")))
  94. (define-record-type* <zone-file>
  95. zone-file make-zone-file
  96. zone-file?
  97. (entries zone-file-entries
  98. (default '()))
  99. (origin zone-file-origin
  100. (default ""))
  101. (ns zone-file-ns
  102. (default "ns"))
  103. (mail zone-file-mail
  104. (default "hostmaster"))
  105. (serial zone-file-serial
  106. (default 1))
  107. (refresh zone-file-refresh
  108. (default (* 2 24 3600)))
  109. (retry zone-file-retry
  110. (default (* 15 60)))
  111. (expiry zone-file-expiry
  112. (default (* 2 7 24 3600)))
  113. (nx zone-file-nx
  114. (default 3600)))
  115. (define-record-type* <knot-keystore-configuration>
  116. knot-keystore-configuration make-knot-keystore-configuration
  117. knot-keystore-configuration?
  118. (id knot-keystore-configuration-id
  119. (default ""))
  120. (backend knot-keystore-configuration-backend
  121. (default 'pem))
  122. (config knot-keystore-configuration-config
  123. (default "/var/lib/knot/keys/keys")))
  124. (define-record-type* <knot-policy-configuration>
  125. knot-policy-configuration make-knot-policy-configuration
  126. knot-policy-configuration?
  127. (id knot-policy-configuration-id
  128. (default ""))
  129. (keystore knot-policy-configuration-keystore
  130. (default "default"))
  131. (manual? knot-policy-configuration-manual?
  132. (default #f))
  133. (single-type-signing? knot-policy-configuration-single-type-signing?
  134. (default #f))
  135. (algorithm knot-policy-configuration-algorithm
  136. (default "ecdsap256sha256"))
  137. (ksk-size knot-policy-configuration-ksk-size
  138. (default 256))
  139. (zsk-size knot-policy-configuration-zsk-size
  140. (default 256))
  141. (dnskey-ttl knot-policy-configuration-dnskey-ttl
  142. (default 'default))
  143. (zsk-lifetime knot-policy-configuration-zsk-lifetime
  144. (default (* 30 24 3600)))
  145. (propagation-delay knot-policy-configuration-propagation-delay
  146. (default (* 24 3600)))
  147. (rrsig-lifetime knot-policy-configuration-rrsig-lifetime
  148. (default (* 14 24 3600)))
  149. (rrsig-refresh knot-policy-configuration-rrsig-refresh
  150. (default (* 7 24 3600)))
  151. (nsec3? knot-policy-configuration-nsec3?
  152. (default #f))
  153. (nsec3-iterations knot-policy-configuration-nsec3-iterations
  154. (default 5))
  155. (nsec3-salt-length knot-policy-configuration-nsec3-salt-length
  156. (default 8))
  157. (nsec3-salt-lifetime knot-policy-configuration-nsec3-salt-lifetime
  158. (default (* 30 24 3600))))
  159. (define-record-type* <knot-zone-configuration>
  160. knot-zone-configuration make-knot-zone-configuration
  161. knot-zone-configuration?
  162. (domain knot-zone-configuration-domain
  163. (default ""))
  164. (file knot-zone-configuration-file
  165. (default "")) ; the file where this zone is saved.
  166. (zone knot-zone-configuration-zone
  167. (default (zone-file))) ; initial content of the zone file
  168. (master knot-zone-configuration-master
  169. (default '()))
  170. (ddns-master knot-zone-configuration-ddns-master
  171. (default #f))
  172. (notify knot-zone-configuration-notify
  173. (default '()))
  174. (acl knot-zone-configuration-acl
  175. (default '()))
  176. (semantic-checks? knot-zone-configuration-semantic-checks?
  177. (default #f))
  178. (zonefile-sync knot-zone-configuration-zonefile-sync
  179. (default 0))
  180. (zonefile-load knot-zone-configuration-zonefile-load
  181. (default #f))
  182. (journal-content knot-zone-configuration-journal-content
  183. (default #f))
  184. (max-journal-usage knot-zone-configuration-max-journal-usage
  185. (default #f))
  186. (max-journal-depth knot-zone-configuration-max-journal-depth
  187. (default #f))
  188. (max-zone-size knot-zone-configuration-max-zone-size
  189. (default #f))
  190. (dnssec-policy knot-zone-configuration-dnssec-policy
  191. (default #f))
  192. (serial-policy knot-zone-configuration-serial-policy
  193. (default 'increment)))
  194. (define-record-type* <knot-remote-configuration>
  195. knot-remote-configuration make-knot-remote-configuration
  196. knot-remote-configuration?
  197. (id knot-remote-configuration-id
  198. (default ""))
  199. (address knot-remote-configuration-address
  200. (default '()))
  201. (via knot-remote-configuration-via
  202. (default '()))
  203. (key knot-remote-configuration-key
  204. (default #f)))
  205. (define-record-type* <knot-configuration>
  206. knot-configuration make-knot-configuration
  207. knot-configuration?
  208. (knot knot-configuration-knot
  209. (default knot))
  210. (run-directory knot-configuration-run-directory
  211. (default "/var/run/knot"))
  212. (includes knot-configuration-includes
  213. (default '()))
  214. (listen-v4 knot-configuration-listen-v4
  215. (default "0.0.0.0"))
  216. (listen-v6 knot-configuration-listen-v6
  217. (default "::"))
  218. (listen-port knot-configuration-listen-port
  219. (default 53))
  220. (keys knot-configuration-keys
  221. (default '()))
  222. (keystores knot-configuration-keystores
  223. (default '()))
  224. (acls knot-configuration-acls
  225. (default '()))
  226. (remotes knot-configuration-remotes
  227. (default '()))
  228. (policies knot-configuration-policies
  229. (default '()))
  230. (zones knot-configuration-zones
  231. (default '())))
  232. (define-syntax define-zone-entries
  233. (syntax-rules ()
  234. ((_ id (name ttl class type data) ...)
  235. (define id (list (make-zone-entry name ttl class type data) ...)))))
  236. (define (error-out msg)
  237. (raise (condition (&message (message msg)))))
  238. (define (verify-knot-key-configuration key)
  239. (unless (knot-key-configuration? key)
  240. (error-out "keys must be a list of only knot-key-configuration."))
  241. (let ((id (knot-key-configuration-id key)))
  242. (unless (and (string? id) (not (equal? id "")))
  243. (error-out "key id must be a non empty string.")))
  244. (unless (memq (knot-key-configuration-algorithm key)
  245. '(#f hmac-md5 hmac-sha1 hmac-sha224 hmac-sha256 hmac-sha384 hmac-sha512))
  246. (error-out "algorithm must be one of: #f, 'hmac-md5, 'hmac-sha1,
  247. 'hmac-sha224, 'hmac-sha256, 'hmac-sha384 or 'hmac-sha512")))
  248. (define (verify-knot-keystore-configuration keystore)
  249. (unless (knot-keystore-configuration? keystore)
  250. (error-out "keystores must be a list of only knot-keystore-configuration."))
  251. (let ((id (knot-keystore-configuration-id keystore)))
  252. (unless (and (string? id) (not (equal? id "")))
  253. (error-out "keystore id must be a non empty string.")))
  254. (unless (memq (knot-keystore-configuration-backend keystore)
  255. '(pem pkcs11))
  256. (error-out "backend must be one of: 'pem or 'pkcs11")))
  257. (define (verify-knot-policy-configuration policy)
  258. (unless (knot-policy-configuration? policy)
  259. (error-out "policies must be a list of only knot-policy-configuration."))
  260. (let ((id (knot-policy-configuration-id policy)))
  261. (unless (and (string? id) (not (equal? id "")))
  262. (error-out "policy id must be a non empty string."))))
  263. (define (verify-knot-acl-configuration acl)
  264. (unless (knot-acl-configuration? acl)
  265. (error-out "acls must be a list of only knot-acl-configuration."))
  266. (let ((id (knot-acl-configuration-id acl))
  267. (address (knot-acl-configuration-address acl))
  268. (key (knot-acl-configuration-key acl))
  269. (action (knot-acl-configuration-action acl)))
  270. (unless (and (string? id) (not (equal? id "")))
  271. (error-out "acl id must be a non empty string."))
  272. (unless (and (list? address)
  273. (every string? address))
  274. (error-out "acl address must be a list of strings.")))
  275. (unless (boolean? (knot-acl-configuration-deny? acl))
  276. (error-out "deny? must be #t or #f.")))
  277. (define (verify-knot-zone-configuration zone)
  278. (unless (knot-zone-configuration? zone)
  279. (error-out "zones must be a list of only knot-zone-configuration."))
  280. (let ((domain (knot-zone-configuration-domain zone)))
  281. (unless (and (string? domain) (not (equal? domain "")))
  282. (error-out "zone domain must be a non empty string."))))
  283. (define (verify-knot-remote-configuration remote)
  284. (unless (knot-remote-configuration? remote)
  285. (error-out "remotes must be a list of only knot-remote-configuration."))
  286. (let ((id (knot-remote-configuration-id remote)))
  287. (unless (and (string? id) (not (equal? id "")))
  288. (error-out "remote id must be a non empty string."))))
  289. (define (verify-knot-configuration config)
  290. (unless (file-like? (knot-configuration-knot config))
  291. (error-out "knot configuration field must be a file-like object."))
  292. (unless (string? (knot-configuration-run-directory config))
  293. (error-out "run-directory must be a string."))
  294. (unless (list? (knot-configuration-includes config))
  295. (error-out "includes must be a list of strings or file-like objects."))
  296. (unless (list? (knot-configuration-keys config))
  297. (error-out "keys must be a list of knot-key-configuration."))
  298. (for-each (lambda (key) (verify-knot-key-configuration key))
  299. (knot-configuration-keys config))
  300. (unless (list? (knot-configuration-keystores config))
  301. (error-out "keystores must be a list of knot-keystore-configuration."))
  302. (for-each (lambda (keystore) (verify-knot-keystore-configuration keystore))
  303. (knot-configuration-keystores config))
  304. (unless (list? (knot-configuration-acls config))
  305. (error-out "acls must be a list of knot-acl-configuration."))
  306. (for-each (lambda (acl) (verify-knot-acl-configuration acl))
  307. (knot-configuration-acls config))
  308. (unless (list? (knot-configuration-zones config))
  309. (error-out "zones must be a list of knot-zone-configuration."))
  310. (for-each (lambda (zone) (verify-knot-zone-configuration zone))
  311. (knot-configuration-zones config))
  312. (unless (list? (knot-configuration-policies config))
  313. (error-out "policies must be a list of knot-policy-configuration."))
  314. (for-each (lambda (policy) (verify-knot-policy-configuration policy))
  315. (knot-configuration-policies config))
  316. (unless (list? (knot-configuration-remotes config))
  317. (error-out "remotes must be a list of knot-remote-configuration."))
  318. (for-each (lambda (remote) (verify-knot-remote-configuration remote))
  319. (knot-configuration-remotes config))
  320. #t)
  321. (define (format-string-list l)
  322. "Formats a list of string in YAML"
  323. (if (eq? l '())
  324. ""
  325. (let ((l (reverse l)))
  326. (string-append
  327. "["
  328. (fold (lambda (x1 x2)
  329. (string-append (if (symbol? x1) (symbol->string x1) x1) ", "
  330. (if (symbol? x2) (symbol->string x2) x2)))
  331. (if (symbol? (car l)) (symbol->string (car l)) (car l)) (cdr l))
  332. "]"))))
  333. (define (knot-acl-config acls)
  334. (with-output-to-string
  335. (lambda ()
  336. (for-each
  337. (lambda (acl-config)
  338. (let ((id (knot-acl-configuration-id acl-config))
  339. (address (knot-acl-configuration-address acl-config))
  340. (key (knot-acl-configuration-key acl-config))
  341. (action (knot-acl-configuration-action acl-config))
  342. (deny? (knot-acl-configuration-deny? acl-config)))
  343. (format #t " - id: ~a\n" id)
  344. (unless (eq? address '())
  345. (format #t " address: ~a\n" (format-string-list address)))
  346. (unless (eq? key '())
  347. (format #t " key: ~a\n" (format-string-list key)))
  348. (unless (eq? action '())
  349. (format #t " action: ~a\n" (format-string-list action)))
  350. (format #t " deny: ~a\n" (if deny? "on" "off"))))
  351. acls))))
  352. (define (knot-key-config keys)
  353. (with-output-to-string
  354. (lambda ()
  355. (for-each
  356. (lambda (key-config)
  357. (let ((id (knot-key-configuration-id key-config))
  358. (algorithm (knot-key-configuration-algorithm key-config))
  359. (secret (knot-key-configuration-secret key-config)))
  360. (format #t " - id: ~a\n" id)
  361. (if algorithm
  362. (format #t " algorithm: ~a\n" (symbol->string algorithm)))
  363. (format #t " secret: ~a\n" secret)))
  364. keys))))
  365. (define (knot-keystore-config keystores)
  366. (with-output-to-string
  367. (lambda ()
  368. (for-each
  369. (lambda (keystore-config)
  370. (let ((id (knot-keystore-configuration-id keystore-config))
  371. (backend (knot-keystore-configuration-backend keystore-config))
  372. (config (knot-keystore-configuration-config keystore-config)))
  373. (format #t " - id: ~a\n" id)
  374. (format #t " backend: ~a\n" (symbol->string backend))
  375. (format #t " config: \"~a\"\n" config)))
  376. keystores))))
  377. (define (knot-policy-config policies)
  378. (with-output-to-string
  379. (lambda ()
  380. (for-each
  381. (lambda (policy-config)
  382. (let ((id (knot-policy-configuration-id policy-config))
  383. (keystore (knot-policy-configuration-keystore policy-config))
  384. (manual? (knot-policy-configuration-manual? policy-config))
  385. (single-type-signing? (knot-policy-configuration-single-type-signing?
  386. policy-config))
  387. (algorithm (knot-policy-configuration-algorithm policy-config))
  388. (ksk-size (knot-policy-configuration-ksk-size policy-config))
  389. (zsk-size (knot-policy-configuration-zsk-size policy-config))
  390. (dnskey-ttl (knot-policy-configuration-dnskey-ttl policy-config))
  391. (zsk-lifetime (knot-policy-configuration-zsk-lifetime policy-config))
  392. (propagation-delay (knot-policy-configuration-propagation-delay
  393. policy-config))
  394. (rrsig-lifetime (knot-policy-configuration-rrsig-lifetime
  395. policy-config))
  396. (nsec3? (knot-policy-configuration-nsec3? policy-config))
  397. (nsec3-iterations (knot-policy-configuration-nsec3-iterations
  398. policy-config))
  399. (nsec3-salt-length (knot-policy-configuration-nsec3-salt-length
  400. policy-config))
  401. (nsec3-salt-lifetime (knot-policy-configuration-nsec3-salt-lifetime
  402. policy-config)))
  403. (format #t " - id: ~a\n" id)
  404. (format #t " keystore: ~a\n" keystore)
  405. (format #t " manual: ~a\n" (if manual? "on" "off"))
  406. (format #t " single-type-signing: ~a\n" (if single-type-signing?
  407. "on" "off"))
  408. (format #t " algorithm: ~a\n" algorithm)
  409. (format #t " ksk-size: ~a\n" (number->string ksk-size))
  410. (format #t " zsk-size: ~a\n" (number->string zsk-size))
  411. (unless (eq? dnskey-ttl 'default)
  412. (format #t " dnskey-ttl: ~a\n" dnskey-ttl))
  413. (format #t " zsk-lifetime: ~a\n" zsk-lifetime)
  414. (format #t " propagation-delay: ~a\n" propagation-delay)
  415. (format #t " rrsig-lifetime: ~a\n" rrsig-lifetime)
  416. (format #t " nsec3: ~a\n" (if nsec3? "on" "off"))
  417. (format #t " nsec3-iterations: ~a\n"
  418. (number->string nsec3-iterations))
  419. (format #t " nsec3-salt-length: ~a\n"
  420. (number->string nsec3-salt-length))
  421. (format #t " nsec3-salt-lifetime: ~a\n" nsec3-salt-lifetime)))
  422. policies))))
  423. (define (knot-remote-config remotes)
  424. (with-output-to-string
  425. (lambda ()
  426. (for-each
  427. (lambda (remote-config)
  428. (let ((id (knot-remote-configuration-id remote-config))
  429. (address (knot-remote-configuration-address remote-config))
  430. (via (knot-remote-configuration-via remote-config))
  431. (key (knot-remote-configuration-key remote-config)))
  432. (format #t " - id: ~a\n" id)
  433. (unless (eq? address '())
  434. (format #t " address: ~a\n" (format-string-list address)))
  435. (unless (eq? via '())
  436. (format #t " via: ~a\n" (format-string-list via)))
  437. (if key
  438. (format #t " key: ~a\n" key))))
  439. remotes))))
  440. (define (serialize-zone-entries entries)
  441. (with-output-to-string
  442. (lambda ()
  443. (for-each
  444. (lambda (entry)
  445. (let ((name (zone-entry-name entry))
  446. (ttl (zone-entry-ttl entry))
  447. (class (zone-entry-class entry))
  448. (type (zone-entry-type entry))
  449. (data (zone-entry-data entry)))
  450. (format #t "~a ~a ~a ~a ~a\n" name ttl class type data)))
  451. entries))))
  452. (define (serialize-zone-file zone domain)
  453. (computed-file (string-append domain ".zone")
  454. #~(begin
  455. (call-with-output-file #$output
  456. (lambda (port)
  457. (format port "$ORIGIN ~a.\n"
  458. #$(zone-file-origin zone))
  459. (format port "@ IN SOA ~a ~a (~a ~a ~a ~a ~a)\n"
  460. #$(zone-file-ns zone)
  461. #$(zone-file-mail zone)
  462. #$(zone-file-serial zone)
  463. #$(zone-file-refresh zone)
  464. #$(zone-file-retry zone)
  465. #$(zone-file-expiry zone)
  466. #$(zone-file-nx zone))
  467. (format port "~a\n"
  468. #$(serialize-zone-entries (zone-file-entries zone))))))))
  469. (define (knot-zone-config zone)
  470. (let ((content (knot-zone-configuration-zone zone)))
  471. #~(with-output-to-string
  472. (lambda ()
  473. (let ((domain #$(knot-zone-configuration-domain zone))
  474. (file #$(knot-zone-configuration-file zone))
  475. (master (list #$@(knot-zone-configuration-master zone)))
  476. (ddns-master #$(knot-zone-configuration-ddns-master zone))
  477. (notify (list #$@(knot-zone-configuration-notify zone)))
  478. (acl (list #$@(knot-zone-configuration-acl zone)))
  479. (semantic-checks? #$(knot-zone-configuration-semantic-checks? zone))
  480. (zonefile-sync #$(knot-zone-configuration-zonefile-sync zone))
  481. (zonefile-load '#$(knot-zone-configuration-zonefile-load zone))
  482. (journal-content #$(knot-zone-configuration-journal-content zone))
  483. (max-journal-usage #$(knot-zone-configuration-max-journal-usage zone))
  484. (max-journal-depth #$(knot-zone-configuration-max-journal-depth zone))
  485. (max-zone-size #$(knot-zone-configuration-max-zone-size zone))
  486. (dnssec-policy #$(knot-zone-configuration-dnssec-policy zone))
  487. (serial-policy '#$(knot-zone-configuration-serial-policy zone)))
  488. (format #t " - domain: ~a\n" domain)
  489. (if (eq? master '())
  490. ;; This server is a master
  491. (if (equal? file "")
  492. (format #t " file: ~a\n"
  493. #$(serialize-zone-file content
  494. (knot-zone-configuration-domain zone)))
  495. (format #t " file: ~a\n" file))
  496. ;; This server is a slave (has masters)
  497. (begin
  498. (format #t " master: ~a\n"
  499. #$(format-string-list
  500. (knot-zone-configuration-master zone)))
  501. (if ddns-master (format #t " ddns-master ~a\n" ddns-master))))
  502. (unless (eq? notify '())
  503. (format #t " notify: ~a\n"
  504. #$(format-string-list
  505. (knot-zone-configuration-notify zone))))
  506. (unless (eq? acl '())
  507. (format #t " acl: ~a\n"
  508. #$(format-string-list
  509. (knot-zone-configuration-acl zone))))
  510. (format #t " semantic-checks: ~a\n" (if semantic-checks? "on" "off"))
  511. (if zonefile-sync
  512. (format #t " zonefile-sync: ~a\n" zonefile-sync))
  513. (if zonefile-load
  514. (format #t " zonefile-load: ~a\n"
  515. (symbol->string zonefile-load)))
  516. (if journal-content
  517. (format #t " journal-content: ~a\n"
  518. (symbol->string journal-content)))
  519. (if max-journal-usage
  520. (format #t " max-journal-usage: ~a\n" max-journal-usage))
  521. (if max-journal-depth
  522. (format #t " max-journal-depth: ~a\n" max-journal-depth))
  523. (if max-zone-size
  524. (format #t " max-zone-size: ~a\n" max-zone-size))
  525. (if dnssec-policy
  526. (begin
  527. (format #t " dnssec-signing: on\n")
  528. (format #t " dnssec-policy: ~a\n" dnssec-policy)))
  529. (format #t " serial-policy: ~a\n"
  530. (symbol->string serial-policy)))))))
  531. (define (knot-config-file config)
  532. (verify-knot-configuration config)
  533. (computed-file "knot.conf"
  534. #~(begin
  535. (call-with-output-file #$output
  536. (lambda (port)
  537. (for-each (lambda (inc)
  538. (format port "include: ~a\n" inc))
  539. '#$(knot-configuration-includes config))
  540. (format port "server:\n")
  541. (format port " rundir: ~a\n" #$(knot-configuration-run-directory config))
  542. (format port " user: knot\n")
  543. (format port " listen: ~a@~a\n"
  544. #$(knot-configuration-listen-v4 config)
  545. #$(knot-configuration-listen-port config))
  546. (format port " listen: ~a@~a\n"
  547. #$(knot-configuration-listen-v6 config)
  548. #$(knot-configuration-listen-port config))
  549. (format port "\nkey:\n")
  550. (format port #$(knot-key-config (knot-configuration-keys config)))
  551. (format port "\nkeystore:\n")
  552. (format port #$(knot-keystore-config (knot-configuration-keystores config)))
  553. (format port "\nacl:\n")
  554. (format port #$(knot-acl-config (knot-configuration-acls config)))
  555. (format port "\nremote:\n")
  556. (format port #$(knot-remote-config (knot-configuration-remotes config)))
  557. (format port "\npolicy:\n")
  558. (format port #$(knot-policy-config (knot-configuration-policies config)))
  559. (unless #$(eq? (knot-configuration-zones config) '())
  560. (format port "\nzone:\n")
  561. (format port "~a\n"
  562. (string-concatenate
  563. (list #$@(map knot-zone-config
  564. (knot-configuration-zones config)))))))))))
  565. (define %knot-accounts
  566. (list (user-group (name "knot") (system? #t))
  567. (user-account
  568. (name "knot")
  569. (group "knot")
  570. (system? #t)
  571. (comment "knot dns server user")
  572. (home-directory "/var/empty")
  573. (shell (file-append shadow "/sbin/nologin")))))
  574. (define (knot-activation config)
  575. (with-imported-modules (source-module-closure '((gnu build activation)))
  576. #~(begin
  577. (use-modules (gnu build activation))
  578. (mkdir-p/perms #$(knot-configuration-run-directory config)
  579. (getpwnam "knot") #o755)
  580. (mkdir-p/perms "/var/lib/knot" (getpwnam "knot") #o755)
  581. (mkdir-p/perms "/var/lib/knot/keys" (getpwnam "knot") #o755)
  582. (mkdir-p/perms "/var/lib/knot/keys/keys" (getpwnam "knot") #o755))))
  583. (define (knot-shepherd-service config)
  584. (let* ((config-file (knot-config-file config))
  585. (knot (knot-configuration-knot config)))
  586. (list (shepherd-service
  587. (documentation "Run the Knot DNS daemon.")
  588. (provision '(knot dns))
  589. (requirement '(networking))
  590. (start #~(make-forkexec-constructor
  591. (list (string-append #$knot "/sbin/knotd")
  592. "-c" #$config-file)))
  593. (stop #~(make-kill-destructor))))))
  594. (define knot-service-type
  595. (service-type (name 'knot)
  596. (extensions
  597. (list (service-extension shepherd-root-service-type
  598. knot-shepherd-service)
  599. (service-extension activation-service-type
  600. knot-activation)
  601. (service-extension account-service-type
  602. (const %knot-accounts))))
  603. (description
  604. "Run @uref{https://www.knot-dns.cz/, Knot}, an authoritative
  605. name server for the @acronym{DNS, Domain Name System}.")))
  606. ;;;
  607. ;;; Knot Resolver.
  608. ;;;
  609. (define-record-type* <knot-resolver-configuration>
  610. knot-resolver-configuration
  611. make-knot-resolver-configuration
  612. knot-resolver-configuration?
  613. (package knot-resolver-configuration-package
  614. (default knot-resolver))
  615. (kresd-config-file knot-resolver-kresd-config-file
  616. (default %kresd.conf))
  617. (garbage-collection-interval knot-resolver-garbage-collection-interval
  618. (default 1000)))
  619. (define %kresd.conf
  620. (plain-file "kresd.conf" "-- -*- mode: lua -*-
  621. trust_anchors.add_file('/var/cache/knot-resolver/root.keys')
  622. net = { '127.0.0.1', '::1' }
  623. user('knot-resolver', 'knot-resolver')
  624. modules = { 'hints > iterate', 'stats', 'predict' }
  625. cache.size = 100 * MB
  626. "))
  627. (define %knot-resolver-accounts
  628. (list (user-group
  629. (name "knot-resolver")
  630. (system? #t))
  631. (user-account
  632. (name "knot-resolver")
  633. (group "knot-resolver")
  634. (system? #t)
  635. (home-directory "/var/cache/knot-resolver")
  636. (shell (file-append shadow "/sbin/nologin")))))
  637. (define (knot-resolver-activation config)
  638. #~(begin
  639. (use-modules (guix build utils))
  640. (let ((rundir "/var/cache/knot-resolver")
  641. (owner (getpwnam "knot-resolver")))
  642. (mkdir-p rundir)
  643. (chown rundir (passwd:uid owner) (passwd:gid owner)))))
  644. (define knot-resolver-shepherd-services
  645. (match-lambda
  646. (($ <knot-resolver-configuration> package
  647. kresd-config-file
  648. garbage-collection-interval)
  649. (list
  650. (shepherd-service
  651. (provision '(kresd))
  652. (requirement '(networking))
  653. (documentation "Run the Knot Resolver daemon.")
  654. (start #~(make-forkexec-constructor
  655. '(#$(file-append package "/sbin/kresd")
  656. "-c" #$kresd-config-file "-n"
  657. "/var/cache/knot-resolver")))
  658. (stop #~(make-kill-destructor)))
  659. (shepherd-service
  660. (provision '(kres-cache-gc))
  661. (requirement '(user-processes))
  662. (documentation "Run the Knot Resolver Garbage Collector daemon.")
  663. (start #~(make-forkexec-constructor
  664. '(#$(file-append package "/sbin/kres-cache-gc")
  665. "-d" #$(number->string garbage-collection-interval)
  666. "-c" "/var/cache/knot-resolver")
  667. #:user "knot-resolver"
  668. #:group "knot-resolver"))
  669. (stop #~(make-kill-destructor)))))))
  670. (define knot-resolver-service-type
  671. (service-type
  672. (name 'knot-resolver)
  673. (extensions
  674. (list (service-extension shepherd-root-service-type
  675. knot-resolver-shepherd-services)
  676. (service-extension activation-service-type
  677. knot-resolver-activation)
  678. (service-extension account-service-type
  679. (const %knot-resolver-accounts))))
  680. (default-value (knot-resolver-configuration))
  681. (description "Run the Knot DNS Resolver.")))
  682. ;;;
  683. ;;; Dnsmasq.
  684. ;;;
  685. (define-record-type* <dnsmasq-configuration>
  686. dnsmasq-configuration make-dnsmasq-configuration
  687. dnsmasq-configuration?
  688. (package dnsmasq-configuration-package
  689. (default dnsmasq)) ;file-like
  690. (no-hosts? dnsmasq-configuration-no-hosts?
  691. (default #f)) ;boolean
  692. (port dnsmasq-configuration-port
  693. (default 53)) ;integer
  694. (local-service? dnsmasq-configuration-local-service?
  695. (default #t)) ;boolean
  696. (listen-addresses dnsmasq-configuration-listen-address
  697. (default '())) ;list of string
  698. (resolv-file dnsmasq-configuration-resolv-file
  699. (default "/etc/resolv.conf")) ;string
  700. (no-resolv? dnsmasq-configuration-no-resolv?
  701. (default #f)) ;boolean
  702. (forward-private-reverse-lookup?
  703. dnsmasq-configuration-forward-private-reverse-lookup?
  704. (default #t)) ;boolean
  705. (query-servers-in-order?
  706. dnsmasq-configuration-query-servers-in-order?
  707. (default #f)) ;boolean
  708. (servers dnsmasq-configuration-servers
  709. (default '())) ;list of string
  710. (addresses dnsmasq-configuration-addresses
  711. (default '())) ;list of string
  712. (cache-size dnsmasq-configuration-cache-size
  713. (default 150)) ;integer
  714. (negative-cache? dnsmasq-configuration-negative-cache?
  715. (default #t)) ;boolean
  716. (cpe-id dnsmasq-configuration-cpe-id
  717. (default #t)) ;string
  718. (tftp-enable? dnsmasq-configuration-tftp-enable?
  719. (default #f)) ;boolean
  720. (tftp-no-fail? dnsmasq-configuration-tftp-no-fail?
  721. (default #f)) ;boolean
  722. (tftp-single-port? dnsmasq-configuration-tftp-single-port?
  723. (default #f)) ;boolean
  724. (tftp-secure? dnsmasq-tftp-secure?
  725. (default #f)) ;boolean
  726. (tftp-max dnsmasq-tftp-max
  727. (default #f)) ;integer
  728. (tftp-mtu dnsmasq-tftp-mtu
  729. (default #f)) ;integer
  730. (tftp-no-blocksize? dnsmasq-tftp-no-blocksize?
  731. (default #f)) ;boolean
  732. (tftp-lowercase? dnsmasq-tftp-lowercase?
  733. (default #f)) ;boolean
  734. (tftp-port-range dnsmasq-tftp-port-range
  735. (default #f)) ;string
  736. (tftp-root dnsmasq-tftp-root
  737. (default "/var/empty,lo")) ;string
  738. (tftp-unique-root dnsmasq-tftp-unique-root
  739. (default #f))) ;"" or "ip" or "mac"
  740. (define (dnsmasq-shepherd-service config)
  741. (match-record config <dnsmasq-configuration>
  742. (package
  743. no-hosts?
  744. port local-service? listen-addresses
  745. resolv-file no-resolv?
  746. forward-private-reverse-lookup? query-servers-in-order?
  747. servers addresses
  748. cache-size negative-cache?
  749. cpe-id
  750. tftp-enable? tftp-no-fail?
  751. tftp-single-port? tftp-secure?
  752. tftp-max tftp-mtu tftp-no-blocksize?
  753. tftp-lowercase? tftp-port-range
  754. tftp-root tftp-unique-root)
  755. (shepherd-service
  756. (provision '(dnsmasq))
  757. (requirement '(networking))
  758. (documentation "Run the dnsmasq DNS server.")
  759. (start #~(make-forkexec-constructor
  760. '(#$(file-append package "/sbin/dnsmasq")
  761. "--keep-in-foreground"
  762. "--pid-file=/run/dnsmasq.pid"
  763. #$@(if no-hosts?
  764. '("--no-hosts")
  765. '())
  766. #$(format #f "--port=~a" port)
  767. #$@(if local-service?
  768. '("--local-service")
  769. '())
  770. #$@(map (cut format #f "--listen-address=~a" <>)
  771. listen-addresses)
  772. #$(format #f "--resolv-file=~a" resolv-file)
  773. #$@(if no-resolv?
  774. '("--no-resolv")
  775. '())
  776. #$@(if forward-private-reverse-lookup?
  777. '()
  778. '("--bogus-priv"))
  779. #$@(if query-servers-in-order?
  780. '("--strict-order")
  781. '())
  782. #$@(map (cut format #f "--server=~a" <>)
  783. servers)
  784. #$@(map (cut format #f "--address=~a" <>)
  785. addresses)
  786. #$(format #f "--cache-size=~a" cache-size)
  787. #$@(if negative-cache?
  788. '()
  789. '("--no-negcache"))
  790. #$@(if cpe-id
  791. (list (format #f "--add-cpe-id=~a" cpe-id))
  792. '())
  793. #$@(if tftp-enable?
  794. '("--enable-tftp")
  795. '())
  796. #$@(if tftp-no-fail?
  797. '("--tftp-no-fail")
  798. '())
  799. #$@(if tftp-single-port?
  800. '("--tftp-single-port")
  801. '())
  802. #$@(if tftp-secure?
  803. '("--tftp-secure?")
  804. '())
  805. #$@(if tftp-max
  806. (list (format #f "--tftp-max=~a" tftp-max))
  807. '())
  808. #$@(if tftp-mtu
  809. (list (format #f "--tftp-mtu=~a" tftp-mtu))
  810. '())
  811. #$@(if tftp-no-blocksize?
  812. '("--tftp-no-blocksize")
  813. '())
  814. #$@(if tftp-lowercase?
  815. '("--tftp-lowercase")
  816. '())
  817. #$@(if tftp-port-range
  818. (list (format #f "--tftp-port-range=~a"
  819. tftp-port-range))
  820. '())
  821. #$@(if tftp-root
  822. (list (format #f "--tftp-root=~a" tftp-root))
  823. '())
  824. #$@(if tftp-unique-root
  825. (list
  826. (if (> (length tftp-unique-root) 0)
  827. (format #f "--tftp-unique-root=~a" tftp-unique-root)
  828. (format #f "--tftp-unique-root")))
  829. '()))
  830. #:pid-file "/run/dnsmasq.pid"))
  831. (stop #~(make-kill-destructor)))))
  832. (define (dnsmasq-activation config)
  833. #~(begin
  834. (use-modules (guix build utils))
  835. ;; create directory to store dnsmasq lease file
  836. (mkdir-p "/var/lib/misc")))
  837. (define dnsmasq-service-type
  838. (service-type
  839. (name 'dnsmasq)
  840. (extensions
  841. (list (service-extension shepherd-root-service-type
  842. (compose list dnsmasq-shepherd-service))
  843. (service-extension activation-service-type
  844. dnsmasq-activation)))
  845. (default-value (dnsmasq-configuration))
  846. (description "Run the dnsmasq DNS server.")))
  847. ;;;
  848. ;;; ddclient
  849. ;;;
  850. (define (uglify-field-name field-name)
  851. (string-delete #\? (symbol->string field-name)))
  852. (define (serialize-field field-name val)
  853. (when (not (member field-name '(group secret-file user)))
  854. (format #t "~a=~a\n" (uglify-field-name field-name) val)))
  855. (define (serialize-boolean field-name val)
  856. (serialize-field field-name (if val "yes" "no")))
  857. (define (serialize-integer field-name val)
  858. (serialize-field field-name (number->string val)))
  859. (define (serialize-string field-name val)
  860. (if (and (string? val) (string=? val ""))
  861. ""
  862. (serialize-field field-name val)))
  863. (define (serialize-list field-name val)
  864. (if (null? val) "" (serialize-field field-name (string-join val))))
  865. (define (serialize-extra-options extra-options)
  866. (string-join extra-options "\n" 'suffix))
  867. (define-configuration ddclient-configuration
  868. (ddclient
  869. (file-like ddclient)
  870. "The ddclient package.")
  871. (daemon
  872. (integer 300)
  873. "The period after which ddclient will retry to check IP and domain name.")
  874. (syslog
  875. (boolean #t)
  876. "Use syslog for the output.")
  877. (mail
  878. (string "root")
  879. "Mail to user.")
  880. (mail-failure
  881. (string "root")
  882. "Mail failed update to user.")
  883. (pid
  884. (string "/var/run/ddclient/ddclient.pid")
  885. "The ddclient PID file.")
  886. (ssl
  887. (boolean #t)
  888. "Enable SSL support.")
  889. (user
  890. (string "ddclient")
  891. "Specifies the user name or ID that is used when running ddclient
  892. program.")
  893. (group
  894. (string "ddclient")
  895. "Group of the user who will run the ddclient program.")
  896. (secret-file
  897. (string "/etc/ddclient/secrets.conf")
  898. "Secret file which will be appended to @file{ddclient.conf} file. This
  899. file contains credentials for use by ddclient. You are expected to create it
  900. manually.")
  901. (extra-options
  902. (list '())
  903. "Extra options will be appended to @file{ddclient.conf} file."))
  904. (define (ddclient-account config)
  905. "Return the user accounts and user groups for CONFIG."
  906. (let ((ddclient-user (ddclient-configuration-user config))
  907. (ddclient-group (ddclient-configuration-group config)))
  908. (list (user-group
  909. (name ddclient-group)
  910. (system? #t))
  911. (user-account
  912. (name ddclient-user)
  913. (system? #t)
  914. (group ddclient-group)
  915. (comment "ddclientd privilege separation user")
  916. (home-directory (string-append "/var/run/" ddclient-user))))))
  917. (define (ddclient-activation config)
  918. "Return the activation GEXP for CONFIG."
  919. (with-imported-modules '((guix build utils)
  920. (ice-9 rdelim))
  921. #~(begin
  922. (use-modules (guix build utils)
  923. (ice-9 rdelim))
  924. (let ((ddclient-user
  925. (passwd:uid (getpw #$(ddclient-configuration-user config))))
  926. (ddclient-group
  927. (passwd:gid (getpw #$(ddclient-configuration-group config))))
  928. (ddclient-secret-file
  929. #$(ddclient-configuration-secret-file config)))
  930. ;; 'ddclient' complains about ddclient.conf file permissions, which
  931. ;; rules out /gnu/store. Thus we copy the ddclient.conf to /etc.
  932. (for-each (lambda (dir)
  933. (mkdir-p dir)
  934. (chmod dir #o700)
  935. (chown dir ddclient-user ddclient-group))
  936. '("/var/cache/ddclient" "/var/run/ddclient"
  937. "/etc/ddclient"))
  938. (with-output-to-file "/etc/ddclient/ddclient.conf"
  939. (lambda ()
  940. (display
  941. (string-append
  942. "# Generated by 'ddclient-service'.\n\n"
  943. #$(with-output-to-string
  944. (lambda ()
  945. (serialize-configuration config
  946. ddclient-configuration-fields)))
  947. (if (string-null? ddclient-secret-file)
  948. ""
  949. (format #f "\n\n# Appended from '~a'.\n\n~a"
  950. ddclient-secret-file
  951. (with-input-from-file ddclient-secret-file
  952. read-string)))))))
  953. (chmod "/etc/ddclient/ddclient.conf" #o600)
  954. (chown "/etc/ddclient/ddclient.conf"
  955. ddclient-user ddclient-group)))))
  956. (define (ddclient-shepherd-service config)
  957. "Return a <shepherd-service> for ddclient with CONFIG."
  958. (let ((ddclient (ddclient-configuration-ddclient config))
  959. (ddclient-pid (ddclient-configuration-pid config))
  960. (ddclient-user (ddclient-configuration-user config))
  961. (ddclient-group (ddclient-configuration-group config)))
  962. (list (shepherd-service
  963. (provision '(ddclient))
  964. (documentation "Run ddclient daemon.")
  965. (start #~(make-forkexec-constructor
  966. (list #$(file-append ddclient "/bin/ddclient")
  967. "-foreground"
  968. "-file" "/etc/ddclient/ddclient.conf")
  969. #:pid-file #$ddclient-pid
  970. #:environment-variables
  971. (list "SSL_CERT_DIR=/run/current-system/profile\
  972. /etc/ssl/certs"
  973. "SSL_CERT_FILE=/run/current-system/profile\
  974. /etc/ssl/certs/ca-certificates.crt")
  975. #:user #$ddclient-user
  976. #:group #$ddclient-group))
  977. (stop #~(make-kill-destructor))))))
  978. (define ddclient-service-type
  979. (service-type
  980. (name 'ddclient)
  981. (extensions
  982. (list (service-extension account-service-type
  983. ddclient-account)
  984. (service-extension shepherd-root-service-type
  985. ddclient-shepherd-service)
  986. (service-extension activation-service-type
  987. ddclient-activation)))
  988. (default-value (ddclient-configuration))
  989. (description "Configure address updating utility for dynamic DNS services,
  990. ddclient.")))
  991. (define (generate-ddclient-documentation)
  992. (generate-documentation
  993. `((ddclient-configuration ,ddclient-configuration-fields))
  994. 'ddclient-configuration))