projects/guix·blob master · refs

2868 lines · 113.4 KiB

1;;; GNU Guix --- Functional package management for GNU
2;;; Copyright © 2013-2025 Ludovic Courtès <[email protected]>
3;;; Copyright © 2015 Mark H Weaver <[email protected]>
4;;; Copyright © 2016, 2018, 2020 Efraim Flashner <[email protected]>
5;;; Copyright © 2016 John Darrington <[email protected]>
6;;; Copyright © 2017 Clément Lassieur <[email protected]>
7;;; Copyright © 2017 Thomas Danckaert <[email protected]>
8;;; Copyright © 2017, 2018 Marius Bakke <[email protected]>
9;;; Copyright © 2018 Tobias Geerinckx-Rice <[email protected]>
10;;; Copyright © 2018 Chris Marusich <[email protected]>
11;;; Copyright © 2018 Arun Isaac <[email protected]>
12;;; Copyright © 2019 Florian Pelz <[email protected]>
13;;; Copyright © 2019, 2021, 2024, 2025 Maxim Cournoyer <[email protected]>
14;;; Copyright © 2019 Sou Bunnbu <[email protected]>
15;;; Copyright © 2019 Alex Griffin <[email protected]>
16;;; Copyright © 2020 Brice Waegeneire <[email protected]>
17;;; Copyright © 2021 Oleg Pykhalov <[email protected]>
18;;; Copyright © 2021 Christine Lemmer-Webber <[email protected]>
19;;; Copyright © 2021 Maxime Devos <[email protected]>
20;;; Copyright © 2021 Guillaume Le Vaillant <[email protected]>
21;;; Copyright © 2022, 2023 Andrew Tropin <[email protected]>
22;;; Copyright © 2023 Declan Tsien <[email protected]>
23;;; Copyright © 2023 Bruno Victal <[email protected]>
24;;; Copyright © 2023 muradm <[email protected]>
25;;; Copyright © 2024 Nigko Yerden <[email protected]>
26;;; Copyright © 2025 45mg <[email protected]>
27;;; Copyright © 2025 Andreas Enge <[email protected]>
28;;;
29;;; This file is part of GNU Guix.
30;;;
31;;; GNU Guix is free software; you can redistribute it and/or modify it
32;;; under the terms of the GNU General Public License as published by
33;;; the Free Software Foundation; either version 3 of the License, or (at
34;;; your option) any later version.
35;;;
36;;; GNU Guix is distributed in the hope that it will be useful, but
37;;; WITHOUT ANY WARRANTY; without even the implied warranty of
38;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
39;;; GNU General Public License for more details.
40;;;
41;;; You should have received a copy of the GNU General Public License
42;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>.
43
44;;; Commentary:
45;;;
46;;; Networking services.
47;;;
48;;; Code:
49
50(define-module (gnu services networking)
51 #:use-module (gnu home services utils)
52 #:use-module (gnu services)
53 #:use-module (gnu services base)
54 #:use-module (gnu services configuration)
55 #:use-module (gnu services linux)
56 #:use-module (gnu services shepherd)
57 #:use-module (gnu services dbus)
58 #:use-module (gnu services admin)
59 #:use-module (gnu system shadow)
60 #:use-module (gnu system pam)
61 #:use-module ((gnu system file-systems) #:select (file-system-mapping))
62 #:use-module (gnu packages admin)
63 #:use-module (gnu packages base)
64 #:use-module (gnu packages bash)
65 #:use-module (gnu packages cluster)
66 #:use-module (gnu packages connman)
67 #:use-module (gnu packages dns)
68 #:use-module (gnu packages freedesktop)
69 #:use-module (gnu packages linux)
70 #:use-module (gnu packages tor)
71 #:use-module (gnu packages usb-modeswitch)
72 #:use-module (gnu packages messaging)
73 #:use-module (gnu packages networking)
74 #:use-module (gnu packages nss)
75 #:use-module (gnu packages ntp)
76 #:use-module (gnu packages gnome)
77 #:use-module (gnu packages ipfs)
78 #:use-module (gnu build linux-container)
79 #:autoload (guix least-authority) (least-authority-wrapper)
80 #:use-module (guix gexp)
81 #:use-module (guix records)
82 #:use-module (guix modules)
83 #:use-module (guix packages)
84 #:use-module (guix deprecation)
85 #:use-module (guix diagnostics)
86 #:autoload (guix ui) (display-hint)
87 #:use-module (guix i18n)
88 #:use-module (rnrs enums)
89 #:use-module (srfi srfi-1)
90 #:use-module (srfi srfi-9)
91 #:use-module (srfi srfi-26)
92 #:use-module (srfi srfi-43)
93 #:use-module ((ice-9 curried-definitions) #:select (define))
94 #:use-module (ice-9 format)
95 #:use-module (ice-9 match)
96 #:use-module (ice-9 string-fun)
97 #:use-module (json)
98 #:re-export (static-networking-service
99 static-networking-service-type)
100 #:export (%facebook-host-aliases ;deprecated
101 block-facebook-hosts-service-type
102
103 dhcpcd-service-type
104 dhcpcd-configuration
105 dhcpcd-configuration?
106 dhcpcd-configuration-interfaces
107 dhcpcd-configuration-command-arguments
108 dhcpcd-configuration-host-name
109 dhcpcd-configuration-duid
110 dhcpcd-configuration-persistent?
111 dhcpcd-configuration-option
112 dhcpcd-configuration-require
113 dhcpcd-configuration-slaac
114 dhcpcd-configuration-no-option
115 dhcpcd-configuration-no-hook
116 dhcpcd-configuration-static
117 dhcpcd-configuration-vendor-class-id
118 dhcpcd-configuration-client-id
119 dhcpcd-configuration-extra-content
120 dhcpcd-configuration-shepherd-requirement
121
122 ntp-configuration
123 ntp-configuration?
124 ntp-configuration-ntp
125 ntp-configuration-servers
126 ntp-allow-large-adjustment?
127
128 %ntp-servers
129 ntp-server
130 ntp-server-type
131 ntp-server-address
132 ntp-server-options
133
134 ntp-service-type
135
136 %openntpd-servers
137 openntpd-configuration
138 openntpd-configuration?
139 openntpd-service-type
140
141 inetd-configuration
142 inetd-configuration?
143 inetd-configuration-program
144 inetd-configuration-entries
145 inetd-entry
146 inetd-entry?
147 inetd-entry-node
148 inetd-entry-name
149 inetd-entry-socket-type
150 inetd-entry-protocol
151 inetd-entry-wait?
152 inetd-entry-user
153 inetd-entry-program
154 inetd-entry-arguments
155 inetd-service-type
156
157 opendht-configuration
158 opendht-configuration-peer-discovery?
159 opendht-configuration-verbose?
160 opendht-configuration-bootstrap-host
161 opendht-configuration-port
162 opendht-configuration-proxy-server-port
163 opendht-configuration-proxy-server-port-tls
164 opendht-configuration->command-line-arguments
165
166 opendht-shepherd-service
167 opendht-service-type
168
169 tor-configuration
170 tor-configuration?
171 tor-configuration-tor
172 tor-configuration-config-file
173 tor-configuration-hidden-services
174 tor-configuration-socks-socket-type
175 tor-configuration-control-socket-path
176 tor-configuration-transport-plugins
177 tor-configuration-auto-start
178 tor-onion-service-configuration
179 tor-onion-service-configuration?
180 tor-onion-service-configuration-name
181 tor-onion-service-configuration-mapping
182 tor-transport-plugin
183 tor-transport-plugin?
184 tor-plugin-role
185 tor-plugin-protocol
186 tor-plugin-program
187 tor-hidden-service ; deprecated
188 tor-service-type
189
190 network-manager-configuration
191 network-manager-configuration?
192 network-manager-configuration-shepherd-requirement
193 network-manager-configuration-dns
194 network-manager-configuration-vpn-plugins
195 network-manager-service-type
196
197 connman-general-configuration
198 connman-general-configuration?
199 connman-configuration
200 connman-configuration?
201 connman-configuration-connman
202 connman-configuration-shepherd-requirement
203 connman-configuration-disable-vpn?
204 connman-configuration-iwd?
205 connman-service-type
206
207 modem-manager-configuration
208 modem-manager-configuration?
209 modem-manager-service-type
210
211 usb-modeswitch-configuration
212 usb-modeswitch-configuration?
213 usb-modeswitch-configuration-usb-modeswitch
214 usb-modeswitch-configuration-usb-modeswitch-data
215 usb-modeswitch-service-type
216
217 wpa-supplicant-configuration
218 wpa-supplicant-configuration?
219 wpa-supplicant-configuration-wpa-supplicant
220 wpa-supplicant-configuration-requirement
221 wpa-supplicant-configuration-shepherd-requirement
222 wpa-supplicant-configuration-shepherd-provision
223 wpa-supplicant-configuration-pid-file
224 wpa-supplicant-configuration-dbus?
225 wpa-supplicant-configuration-interface
226 wpa-supplicant-configuration-config-file
227 wpa-supplicant-configuration-extra-options
228 wpa-supplicant-service-type
229
230 iwd-configuration
231 iwd-configuration-config
232 iwd-configuration-ignored-interfaces
233 iwd-configuration-ignored-phys
234 iwd-configuration-interfaces
235 iwd-configuration-iwd
236 iwd-configuration-phys
237 iwd-configuration-shepherd-provision
238 iwd-configuration-shepherd-requirement
239 iwd-service-type
240 iwd-general-settings
241 iwd-network-settings
242 iwd-scan-settings
243 iwd-settings
244
245 hostapd-configuration
246 hostapd-configuration?
247 hostapd-configuration-package
248 hostapd-configuration-interface
249 hostapd-configuration-ssid
250 hostapd-configuration-broadcast-ssid?
251 hostapd-configuration-channel
252 hostapd-configuration-driver
253 hostapd-service-type
254
255 simulated-wifi-service-type
256
257 openvswitch-service-type
258 openvswitch-configuration
259
260 iptables-configuration
261 iptables-configuration?
262 iptables-configuration-iptables
263 iptables-configuration-ipv4-rules
264 iptables-configuration-ipv6-rules
265 iptables-service-type
266
267 nftables-service-type
268 nftables-configuration
269 nftables-configuration?
270 nftables-configuration-package
271 nftables-configuration-debug-levels
272 nftables-configuration-ruleset
273 %default-nftables-ruleset
274
275 pagekite-service-type
276 pagekite-configuration
277 pagekite-configuration?
278 pagekite-configuration-package
279 pagekite-configuration-kitename
280 pagekite-configuration-kitesecret
281 pagekite-configuration-frontend
282 pagekite-configuration-kites
283 pagekite-configuration-extra-file
284
285 yggdrasil-service-type
286 yggdrasil-configuration
287 yggdrasil-configuration?
288 yggdrasil-configuration-autoconf?
289 yggdrasil-configuration-config-file
290 yggdrasil-configuration-log-level
291 yggdrasil-configuration-log-to
292 yggdrasil-configuration-json-config
293 yggdrasil-configuration-package
294
295 ipfs-service-type
296 ipfs-configuration
297 ipfs-configuration?
298 ipfs-configuration-package
299 ipfs-configuration-gateway
300 ipfs-configuration-api
301
302 keepalived-configuration
303 keepalived-configuration?
304 keepalived-service-type))
305
306(define %unroutable-ipv4
307 ;; Unroutable address, as per <https://www.rfc-editor.org/rfc/rfc5737>.
308 "203.0.113.1")
309
310(define %unroutable-ipv6
311 ;; Unroutable address, as per <https://www.rfc-editor.org/rfc/rfc6666>.
312 "0100::")
313
314(define facebook-host-aliases
315 ;; This is the list of known Facebook hosts to be added to /etc/hosts if you
316 ;; are to block it.
317 (let ((domains '("facebook.com" "www.facebook.com"
318 "login.facebook.com" "www.login.facebook.com"
319 "fbcdn.net" "www.fbcdn.net" "fbcdn.com" "www.fbcdn.com"
320 "static.ak.fbcdn.net" "static.ak.connect.facebook.com"
321 "connect.facebook.net" "www.connect.facebook.net"
322 "apps.facebook.com")))
323 (append-map (lambda (name)
324 (map (lambda (addr)
325 (host addr name))
326 (list %unroutable-ipv4 %unroutable-ipv6)))
327 domains)))
328
329(define-deprecated %facebook-host-aliases
330 block-facebook-hosts-service-type
331 (string-join
332 (map (lambda (x)
333 (string-append (host-address x) "\t"
334 (host-canonical-name x) "\n"))
335 facebook-host-aliases)))
336
337(define block-facebook-hosts-service-type
338 (service-type
339 (name 'block-facebook-hosts)
340 (extensions
341 (list (service-extension hosts-service-type
342 (const facebook-host-aliases))))
343 (default-value #f)
344 (description "Add a list of known Facebook hosts to @file{/etc/hosts}")))
345
346
347;;
348;; DHCPCD.
349;;
350
351(define (serialize-field-name field-name)
352 (let ((str (symbol->string field-name)))
353 (string-replace-substring
354 (if (string-suffix? "?" str)
355 (string-drop-right str 1)
356 str)
357 "-" "")))
358
359(define (dhcpcd-serialize-string field-name value)
360 (if (equal? field-name 'extra-content)
361 #~(string-append #$value "\n")
362 #~(format #f "~a ~a~%" #$(serialize-field-name field-name) #$value)))
363
364(define (dhcpcd-serialize-boolean field-name value)
365 (if value
366 #~(format #f "~a~%" #$(serialize-field-name field-name))
367 ""))
368
369(define (dhcpcd-serialize-list-of-strings field-name value)
370 #~(string-append #$@(map (cut dhcpcd-serialize-string field-name <>) value)))
371
372;; Some fields (e.g. host-name) can be specified with an empty string argument.
373;; Therefore, we need a maybe type to differentiate disabled/empty-string.
374(define-maybe string (prefix dhcpcd-))
375
376(define-configuration dhcpcd-configuration
377 (interfaces
378 (list '())
379 "List of networking interfaces---e.g., @code{\"eth0\"}---to start a DHCP client
380for. If no interface is specified (i.e., the list is empty) then @command{dhcpcd}
381discovers available Ethernet interfaces, that can be configured, automatically."
382 empty-serializer)
383 (command-arguments
384 (list '("-q" "-q"))
385 "List of additional command-line options."
386 empty-serializer)
387 (package
388 (file-like dhcpcd)
389 "The dhcpcd package to use."
390 empty-serializer)
391
392 ;; The following defaults replicate the default dhcpcd configuration file.
393 ;;
394 ;; See https://github.com/NetworkConfiguration/dhcpcd/tree/v10.0.10#configuration
395 (host-name
396 (maybe-string "")
397 "Host name to send via DHCP, defaults to the current system host name.")
398 (duid
399 (maybe-string "")
400 "DHCPv4 clients require a unique client identifier, this option uses the DHCPv6
401Unique Identifier as a DHCPv4 client identifier as well. For more information, refer
402to @uref{https://www.rfc-editor.org/rfc/rfc4361, RFC 4361} and @code{dhcpcd.conf(5)}.")
403 (persistent?
404 (boolean #t)
405 "When false, de-configure the interface when @command{dhcpcd} exits.")
406 (option
407 (list-of-strings
408 '("rapid_commit"
409 "domain_name_servers"
410 "domain_name"
411 "domain_search"
412 "host_name"
413 "classless_static_routes"
414 "interface_mtu"))
415 "List of options to request from the server.")
416 (require
417 (list-of-strings '("dhcp_server_identifier"))
418 "List of options to require in responses.")
419 (slaac
420 (maybe-string "private")
421 "Interface identifier used for SLAAC generated IPv6 addresses.")
422
423 ;; Common options not set in the default configuration file.
424 (no-option
425 (list-of-strings '())
426 "List of options to remove from the message before it's processed.")
427 (no-hook
428 (list-of-strings '())
429 "List of hook script which should not be invoked.")
430 (static
431 (list-of-strings '())
432 "DHCP client can request different options from a DHCP server, through
433@code{static} it is possible to configure static values for selected options. For
434example, @code{\"domain_name_servers=127.0.0.1\"}.")
435 (vendor-class-id
436 maybe-string
437 "Set the DHCP Vendor Class (e.g., @code{MSFT}). For more information, refer
438to @uref{https://www.rfc-editor.org/rfc/rfc2132#section-9.13,RFC 2132}.")
439 (client-id
440 maybe-string
441 "Use the interface hardware address or the given string as a client identifier,
442this is mutually exclusive with the @code{duid} option.")
443
444 ;; Escape hatch for the generated configuration file.
445 (extra-content
446 maybe-string
447 "Extra content to append to the configuration as-is.")
448
449 (shepherd-provision
450 (list-of-symbols '(networking))
451 "This is a list of symbols naming Shepherd services provided by this service."
452 empty-serializer)
453
454 (shepherd-requirement
455 (list-of-symbols '())
456 "This is a list of symbols naming Shepherd services that this service
457will depend on."
458 empty-serializer)
459
460 (prefix dhcpcd-))
461
462(define (dhcpcd-config-file config)
463 (mixed-text-file "dhcpcd.conf"
464 (serialize-configuration
465 config
466 dhcpcd-configuration-fields)))
467
468(define dhcpcd-account-service
469 (list (user-group (name "dhcpcd") (system? #t))
470 (user-account
471 (name "dhcpcd")
472 (group "dhcpcd")
473 (system? #t)
474 (comment "dhcpcd daemon user")
475 (home-directory "/var/empty")
476 (shell (file-append shadow "/sbin/nologin")))))
477
478(define (dhcpcd-shepherd-service config)
479 (match-record config <dhcpcd-configuration>
480 (command-arguments interfaces package
481 shepherd-provision shepherd-requirement)
482 (let ((config-file (dhcpcd-config-file config)))
483 (list (shepherd-service
484 (documentation "dhcpcd daemon.")
485 (provision shepherd-provision)
486 (requirement `(user-processes udev ,@shepherd-requirement))
487 (actions (list (shepherd-configuration-action config-file)))
488 (start
489 #~(make-forkexec-constructor
490 (list (string-append #$package "/sbin/dhcpcd")
491 #$@command-arguments "-B" "-f" #$config-file
492 #$@interfaces)))
493 (stop #~(make-kill-destructor)))))))
494
495(define dhcpcd-service-type
496 (service-type (name 'dhcpcd)
497 (description "Run the dhcpcd daemon.")
498 (extensions
499 (list (service-extension account-service-type
500 (const dhcpcd-account-service))
501 (service-extension shepherd-root-service-type
502 dhcpcd-shepherd-service)))
503 (compose concatenate)
504 (default-value (dhcpcd-configuration))))
505
506
507;;;
508;;; NTP.
509;;;
510
511(define ntp-server-types (make-enumeration
512 '(pool
513 server
514 peer
515 broadcast
516 manycastclient)))
517
518(define-record-type* <ntp-server>
519 ntp-server make-ntp-server
520 ntp-server?
521 ;; The type can be one of the symbols of the NTP-SERVER-TYPE? enumeration.
522 (type ntp-server-type
523 (default 'server))
524 (address ntp-server-address) ; a string
525 ;; The list of options can contain single option names or tuples in the form
526 ;; '(name value).
527 (options ntp-server-options
528 (default '())))
529
530(define (ntp-server->string ntp-server)
531 ;; Serialize the NTP server object as a string, ready to use in the NTP
532 ;; configuration file.
533 (define (flatten lst)
534 (reverse
535 (let loop ((x lst)
536 (res '()))
537 (if (list? x)
538 (fold loop res x)
539 (cons (format #f "~a" x) res)))))
540
541 (match-record ntp-server <ntp-server>
542 (type address options)
543 ;; XXX: It'd be neater if fields were validated at the syntax level (for
544 ;; static ones at least). Perhaps the Guix record type could support a
545 ;; predicate property on a field?
546 (unless (enum-set-member? type ntp-server-types)
547 (error "Invalid NTP server type" type))
548 (string-join (cons* (symbol->string type)
549 address
550 (flatten options)))))
551
552(define %ntp-servers
553 ;; Default set of NTP servers. These URLs are managed by the NTP Pool project.
554 ;; Within Guix, Leo Famulari <[email protected]> is the administrative contact
555 ;; for this NTP pool "zone".
556 ;; The full list of available URLs are 0.guix.pool.ntp.org,
557 ;; 1.guix.pool.ntp.org, 2.guix.pool.ntp.org, and 3.guix.pool.ntp.org. We
558 ;; use 2.guix.pool.ntp.org as default as it supports IPv6, contrary to the
559 ;; others.
560 (list
561 (ntp-server
562 (type 'pool)
563 (address "2.guix.pool.ntp.org")
564 (options '("iburst"))))) ;as recommended in the ntpd manual
565
566(define-record-type* <ntp-configuration>
567 ntp-configuration make-ntp-configuration
568 ntp-configuration?
569 (ntp ntp-configuration-ntp
570 (default ntp))
571 (servers ntp-configuration-servers ;list of <ntp-server> objects
572 (default %ntp-servers))
573 (allow-large-adjustment? ntp-allow-large-adjustment?
574 (default #t))) ;as recommended in the ntpd manual
575
576(define (ntp-shepherd-service config)
577 (match-record config <ntp-configuration>
578 (ntp servers allow-large-adjustment?)
579 ;; TODO: Add authentication support.
580 (define config
581 (string-append "driftfile /var/run/ntpd/ntp.drift\n"
582 (string-join (map ntp-server->string servers) "\n")
583 "
584# Disable status queries as a workaround for CVE-2013-5211:
585# <http://support.ntp.org/bin/view/Main/SecurityNotice#DRDoS_Amplification_Attack_using>.
586restrict default kod nomodify notrap nopeer noquery limited
587restrict -6 default kod nomodify notrap nopeer noquery limited
588
589# Yet, allow use of the local 'ntpq'.
590restrict 127.0.0.1
591restrict -6 ::1
592
593# This is required to use servers from a pool directive when using the 'nopeer'
594# option by default, as documented in the 'ntp.conf' manual.
595restrict source notrap nomodify noquery\n"))
596
597 (define ntpd.conf
598 (plain-file "ntpd.conf" config))
599
600 (list (shepherd-service
601 (provision '(ntpd))
602 (documentation "Run the Network Time Protocol (NTP) daemon.")
603 (requirement '(user-processes networking))
604 (actions (list (shepherd-configuration-action ntpd.conf)))
605 (start #~(make-forkexec-constructor
606 (list (string-append #$ntp "/bin/ntpd") "-n"
607 "-c" #$ntpd.conf "-u" "ntpd"
608 #$@(if allow-large-adjustment?
609 '("-g")
610 '()))
611 #:log-file "/var/log/ntpd.log"))
612 (stop #~(make-kill-destructor))))))
613
614(define %ntp-accounts
615 (list (user-account
616 (name "ntpd")
617 (group "nogroup")
618 (system? #t)
619 (comment "NTP daemon user")
620 (home-directory "/var/empty")
621 (shell (file-append shadow "/sbin/nologin")))))
622
623
624(define (ntp-service-activation config)
625 "Return the activation gexp for CONFIG."
626 (with-imported-modules '((guix build utils))
627 #~(begin
628 (use-modules (guix build utils))
629 (define %user
630 (getpw "ntpd"))
631
632 (let ((directory "/var/run/ntpd"))
633 (mkdir-p directory)
634 (chown directory (passwd:uid %user) (passwd:gid %user))))))
635
636(define ntp-service-type
637 (service-type (name 'ntp)
638 (extensions
639 (list (service-extension shepherd-root-service-type
640 ntp-shepherd-service)
641 (service-extension account-service-type
642 (const %ntp-accounts))
643 (service-extension activation-service-type
644 ntp-service-activation)))
645 (description
646 "Run the @command{ntpd}, the Network Time Protocol (NTP)
647daemon of the @uref{http://www.ntp.org, Network Time Foundation}. The daemon
648will keep the system clock synchronized with that of the given servers.")
649 (default-value (ntp-configuration))))
650
651
652;;;
653;;; OpenNTPD.
654;;;
655
656(define %openntpd-servers
657 (map ntp-server-address %ntp-servers))
658
659(define-record-type* <openntpd-configuration>
660 openntpd-configuration make-openntpd-configuration
661 openntpd-configuration?
662 (openntpd openntpd-configuration-openntpd
663 (default openntpd))
664 (listen-on openntpd-listen-on
665 (default '("127.0.0.1"
666 "::1")))
667 (query-from openntpd-query-from
668 (default '()))
669 (sensor openntpd-sensor
670 (default '()))
671 (server openntpd-server
672 (default '()))
673 (servers openntpd-servers
674 (default %openntpd-servers))
675 (constraint-from openntpd-constraint-from
676 (default '()))
677 (constraints-from openntpd-constraints-from
678 (default '())))
679
680(define (openntpd-configuration->string config)
681
682 (define (quote-field? name)
683 (member name '("constraints from")))
684
685 (match-record config <openntpd-configuration>
686 (listen-on query-from sensor server servers constraint-from
687 constraints-from)
688 (string-append
689 (string-join
690 (concatenate
691 (filter-map (lambda (field values)
692 (match values
693 (() #f) ;discard entry with filter-map
694 ((val ...) ;validate value type
695 (map (lambda (value)
696 (if (quote-field? field)
697 (format #f "~a \"~a\"" field value)
698 (format #f "~a ~a" field value)))
699 values))))
700 ;; The entry names.
701 '("listen on" "query from" "sensor" "server" "servers"
702 "constraint from" "constraints from")
703 ;; The corresponding entry values.
704 (list listen-on query-from sensor server servers
705 constraint-from constraints-from)))
706 "\n")
707 "\n"))) ;add a trailing newline
708
709(define (openntpd-shepherd-service config)
710 (let ((openntpd (openntpd-configuration-openntpd config)))
711
712 (define ntpd.conf
713 (plain-file "ntpd.conf" (openntpd-configuration->string config)))
714
715 (list (shepherd-service
716 (provision '(ntpd))
717 (documentation "Run the Network Time Protocol (NTP) daemon.")
718 (requirement '(user-processes networking))
719 (start #~(make-forkexec-constructor
720 (list (string-append #$openntpd "/sbin/ntpd")
721 "-f" #$ntpd.conf
722 "-d") ;; don't daemonize
723 ;; When ntpd is daemonized it repeatedly tries to respawn
724 ;; while running, leading shepherd to disable it. To
725 ;; prevent spamming stderr, redirect output to logfile.
726 #:log-file "/var/log/ntpd.log"))
727 (stop #~(make-kill-destructor))
728 (actions (list (shepherd-configuration-action ntpd.conf)))))))
729
730(define (openntpd-service-activation config)
731 "Return the activation gexp for CONFIG."
732 (with-imported-modules '((guix build utils))
733 #~(begin
734 (use-modules (guix build utils))
735
736 (mkdir-p "/var/db")
737 (mkdir-p "/var/run")
738 (unless (file-exists? "/var/db/ntpd.drift")
739 (with-output-to-file "/var/db/ntpd.drift"
740 (lambda _
741 (format #t "0.0")))))))
742
743(define openntpd-service-type
744 (service-type (name 'openntpd)
745 (extensions
746 (list (service-extension shepherd-root-service-type
747 openntpd-shepherd-service)
748 (service-extension account-service-type
749 (const %ntp-accounts))
750 (service-extension profile-service-type
751 (compose list openntpd-configuration-openntpd))
752 (service-extension activation-service-type
753 openntpd-service-activation)))
754 (default-value (openntpd-configuration))
755 (description
756 "Run the @command{ntpd}, the Network Time Protocol (NTP)
757daemon, as implemented by @uref{http://www.openntpd.org, OpenNTPD}. The
758daemon will keep the system clock synchronized with that of the given servers.")))
759
760
761;;;
762;;; Inetd.
763;;;
764
765(define-record-type* <inetd-configuration> inetd-configuration
766 make-inetd-configuration
767 inetd-configuration?
768 (program inetd-configuration-program ;file-like
769 (default (file-append inetutils "/libexec/inetd")))
770 (entries inetd-configuration-entries ;list of <inetd-entry>
771 (default '())))
772
773(define-record-type* <inetd-entry> inetd-entry make-inetd-entry
774 inetd-entry?
775 (node inetd-entry-node ;string or #f
776 (default #f))
777 (name inetd-entry-name) ;string, from /etc/services
778
779 (socket-type inetd-entry-socket-type) ;stream | dgram | raw |
780 ;rdm | seqpacket
781 (protocol inetd-entry-protocol) ;string, from /etc/protocols
782
783 (wait? inetd-entry-wait? ;Boolean
784 (default #t))
785 (user inetd-entry-user) ;string
786
787 (program inetd-entry-program ;string or file-like object
788 (default "internal"))
789 (arguments inetd-entry-arguments ;list of strings or file-like objects
790 (default '())))
791
792(define (inetd-config-file entries)
793 (apply mixed-text-file "inetd.conf"
794 (map
795 (lambda (entry)
796 (let* ((node (inetd-entry-node entry))
797 (name (inetd-entry-name entry))
798 (socket
799 (if node (string-append node ":" name) name))
800 (type
801 (match (inetd-entry-socket-type entry)
802 ((or 'stream 'dgram 'raw 'rdm 'seqpacket)
803 (symbol->string (inetd-entry-socket-type entry)))))
804 (protocol (inetd-entry-protocol entry))
805 (wait (if (inetd-entry-wait? entry) "wait" "nowait"))
806 (user (inetd-entry-user entry))
807 (program (inetd-entry-program entry))
808 (args (inetd-entry-arguments entry)))
809 #~(string-append
810 (string-join
811 (list #$@(list socket type protocol wait user program) #$@args)
812 " ") "\n")))
813 entries)))
814
815(define (inetd-shepherd-service config)
816 (let ((entries (inetd-configuration-entries config)))
817 (if (null? entries)
818 '() ;do nothing
819 (let ((program (inetd-configuration-program config)))
820 (list (shepherd-service
821 (documentation "Run inetd.")
822 (provision '(inetd))
823 (requirement '(user-processes networking syslogd))
824 (start #~(make-forkexec-constructor
825 (list #$program #$(inetd-config-file entries))
826 #:pid-file "/var/run/inetd.pid"))
827 (stop #~(make-kill-destructor))))))))
828
829(define-public inetd-service-type
830 (service-type
831 (name 'inetd)
832 (extensions
833 (list (service-extension shepherd-root-service-type
834 inetd-shepherd-service)))
835
836 ;; The service can be extended with additional lists of entries.
837 (compose concatenate)
838 (extend (lambda (config entries)
839 (inetd-configuration
840 (inherit config)
841 (entries (append (inetd-configuration-entries config)
842 entries)))))
843 (description
844 "Start @command{inetd}, the @dfn{Internet superserver}. It is responsible
845for listening on Internet sockets and spawning the corresponding services on
846demand.")))
847
848
849;;;
850;;; OpenDHT, the distributed hash table network used by Jami
851;;;
852
853(define-maybe/no-serialization number)
854(define-maybe/no-serialization string)
855
856;;; To generate the documentation of the following configuration record, you
857;;; can evaluate: (configuration->documentation 'opendht-configuration)
858(define-configuration/no-serialization opendht-configuration
859 (opendht
860 (file-like opendht)
861 "The @code{opendht} package to use.")
862 (peer-discovery?
863 (boolean #false)
864 "Whether to enable the multicast local peer discovery mechanism.")
865 (enable-logging?
866 (boolean #false)
867 "Whether to enable logging messages to syslog. It is disabled by default
868as it is rather verbose.")
869 (debug?
870 (boolean #false)
871 "Whether to enable debug-level logging messages. This has no effect if
872logging is disabled.")
873 (bootstrap-host
874 (maybe-string "bootstrap.jami.net:4222")
875 "The node host name that is used to make the first connection to the
876network. A specific port value can be provided by appending the @code{:PORT}
877suffix. By default, it uses the Jami bootstrap nodes, but any host can be
878specified here. It's also possible to disable bootstrapping by explicitly
879setting this field to @code{%unset-value}.")
880 (port
881 (maybe-number 4222)
882 "The UDP port to bind to. When left unspecified, an available port is
883automatically selected.")
884 (proxy-server-port
885 maybe-number
886 "Spawn a proxy server listening on the specified port.")
887 (proxy-server-port-tls
888 maybe-number
889 "Spawn a proxy server listening to TLS connections on the specified
890port."))
891
892(define %opendht-accounts
893 ;; User account and groups for Tor.
894 (list (user-group (name "opendht") (system? #t))
895 (user-account
896 (name "opendht")
897 (group "opendht")
898 (system? #t)
899 (comment "OpenDHT daemon user")
900 (home-directory "/var/empty")
901 (shell (file-append shadow "/sbin/nologin")))))
902
903(define (opendht-configuration->command-line-arguments config)
904 "Derive the command line arguments used to launch the OpenDHT daemon from
905CONFIG, an <opendht-configuration> object."
906 (match-record config <opendht-configuration>
907 (opendht bootstrap-host enable-logging? port debug? peer-discovery?
908 proxy-server-port proxy-server-port-tls)
909 (let ((dhtnode (least-authority-wrapper
910 ;; XXX: Work around lack of support for multiple outputs
911 ;; in 'file-append'.
912 (computed-file "dhtnode"
913 #~(symlink
914 (string-append #$opendht:tools
915 "/bin/dhtnode")
916 #$output))
917 #:name "dhtnode"
918 #:mappings (list (file-system-mapping
919 (source "/dev/log") ;for syslog
920 (target source)))
921 #:namespaces (delq 'net %namespaces))))
922 `(,dhtnode
923 "--service" ;non-forking mode
924 ,@(if (string? bootstrap-host)
925 (list "--bootstrap" bootstrap-host))
926 ,@(if enable-logging?
927 (list "--syslog")
928 '())
929 ,@(if (number? port)
930 (list "--port" (number->string port))
931 '())
932 ,@(if debug?
933 (list "--verbose")
934 '())
935 ,@(if peer-discovery?
936 (list "--peer-discovery")
937 '())
938 ,@(if (number? proxy-server-port)
939 (list "--proxyserver" (number->string proxy-server-port))
940 '())
941 ,@(if (number? proxy-server-port-tls)
942 (list "--proxyserverssl" (number->string proxy-server-port-tls))
943 '())))))
944
945(define (opendht-shepherd-service config)
946 "Return a <shepherd-service> running OpenDHT."
947 (shepherd-service
948 (documentation "Run an OpenDHT node.")
949 (provision '(opendht dhtnode dhtproxy))
950 (requirement '(user-processes networking syslogd))
951 (start #~(make-forkexec-constructor
952 (list #$@(opendht-configuration->command-line-arguments config))
953 #:user "opendht"
954 #:group "opendht"))
955 (stop #~(make-kill-destructor))))
956
957(define opendht-service-type
958 (service-type
959 (name 'opendht)
960 (default-value (opendht-configuration))
961 (extensions
962 (list (service-extension shepherd-root-service-type
963 (compose list opendht-shepherd-service))
964 (service-extension account-service-type
965 (const %opendht-accounts))))
966 (description "Run the OpenDHT @command{dhtnode} command that allows
967participating in the distributed hash table based OpenDHT network. The
968service can be configured to act as a proxy to the distributed network, which
969can be useful for portable devices where minimizing energy consumption is
970paramount. OpenDHT was originally based on Kademlia and adapted for
971applications in communication. It is used by Jami, for example.")))
972
973
974;;;
975;;; Tor.
976;;;
977
978(define-record-type* <tor-configuration>
979 tor-configuration make-tor-configuration
980 tor-configuration?
981 (tor tor-configuration-tor
982 (default tor))
983 (config-file tor-configuration-config-file
984 (default (plain-file "empty" "")))
985 (hidden-services tor-configuration-hidden-services
986 (default '()))
987 (socks-socket-type tor-configuration-socks-socket-type ; 'tcp or 'unix
988 (default 'tcp))
989 (control-socket? tor-configuration-control-socket-path
990 (default #f))
991 (transport-plugins tor-configuration-transport-plugins
992 (default '()))
993 (auto-start? tor-configuration-auto-start
994 (default #t)))
995
996(define %tor-accounts
997 ;; User account and groups for Tor.
998 (list (user-group (name "tor") (system? #t))
999 (user-account
1000 (name "tor")
1001 (group "tor")
1002 (system? #t)
1003 (comment "Tor daemon user")
1004 (home-directory "/var/empty")
1005 (shell (file-append shadow "/sbin/nologin")))))
1006
1007(define-configuration/no-serialization tor-onion-service-configuration
1008 (name
1009 string
1010 "Name for this Onion Service. This creates a
1011@file{/var/lib/tor/hidden-services/@var{name}} directory, where the
1012@file{hostname} file contains the @indicateurl{.onion} host name for this
1013Onion Service.")
1014
1015 (mapping
1016 alist
1017 "Association list of port to address mappings. The following example:
1018@lisp
1019'((22 \"127.0.0.1:22\")
1020 (80 \"127.0.0.1:8080\"))
1021@end lisp
1022maps ports 22 and 80 of the Onion Service to the local ports 22 and 8080."))
1023
1024(define-record-type* <tor-transport-plugin>
1025 tor-transport-plugin make-tor-transport-plugin
1026 tor-transport-plugin?
1027 (role tor-plugin-role
1028 (default 'client)
1029 (sanitize (lambda (value)
1030 (if (memq value '(client server))
1031 value
1032 (configuration-field-error #f 'role value)))))
1033 (protocol tor-plugin-protocol
1034 (default "obfs4"))
1035 (program tor-plugin-program))
1036
1037(define (tor-configuration->torrc config)
1038 "Return a 'torrc' file for CONFIG."
1039 (match-record config <tor-configuration>
1040 (tor config-file hidden-services socks-socket-type control-socket?
1041 transport-plugins)
1042 (computed-file
1043 "torrc"
1044 (with-imported-modules '((guix build utils))
1045 #~(begin
1046 (use-modules (guix build utils)
1047 (ice-9 match))
1048
1049 (call-with-output-file #$output
1050 (lambda (port)
1051 (display "\
1052### These lines were generated from your system configuration:
1053DataDirectory /var/lib/tor
1054Log notice stderr\n" port)
1055 (when (eq? 'unix '#$socks-socket-type)
1056 (display "\
1057SocksPort unix:/var/run/tor/socks-sock
1058UnixSocksGroupWritable 1\n" port))
1059 (when #$control-socket?
1060 (display "\
1061ControlSocket unix:/var/run/tor/control-sock GroupWritable RelaxDirModeCheck
1062ControlSocketsGroupWritable 1\n"
1063 port))
1064
1065 (for-each (match-lambda
1066 ((service (ports hosts) ...)
1067 (format port "\
1068HiddenServiceDir /var/lib/tor/hidden-services/~a~%"
1069 service)
1070 (for-each (lambda (tcp-port host)
1071 (format port "\
1072HiddenServicePort ~a ~a~%"
1073 tcp-port host))
1074 ports hosts)))
1075 '#$(map (match-lambda
1076 (($ <tor-onion-service-configuration> name mapping)
1077 (cons name mapping)))
1078 hidden-services))
1079
1080 (for-each (match-lambda
1081 ((role-string protocol program)
1082 (format port "\
1083~aTransportPlugin ~a exec ~a~%"
1084 role-string protocol program)))
1085 '#$(map (match-lambda
1086 (($ <tor-transport-plugin> role protocol program)
1087 (list (if (eq? role 'client)
1088 "Client"
1089 "Server")
1090 protocol
1091 program)))
1092 transport-plugins))
1093
1094 (display "\
1095### End of automatically generated lines.\n\n" port)
1096
1097 ;; Append the user's config file.
1098 (call-with-input-file #$config-file
1099 (lambda (input)
1100 (dump-port input port)))
1101 #t)))))))
1102
1103(define (tor-shepherd-service config)
1104 "Return a <shepherd-service> running Tor."
1105 (let* ((torrc (tor-configuration->torrc config))
1106 (transport-plugins (tor-configuration-transport-plugins config))
1107 (auto-start? (tor-configuration-auto-start config))
1108 (tor (least-authority-wrapper
1109 (file-append (tor-configuration-tor config) "/bin/tor")
1110 #:name "tor"
1111 #:mappings (append
1112 (list (file-system-mapping
1113 (source "/var/lib/tor")
1114 (target source)
1115 (writable? #t))
1116 (file-system-mapping
1117 (source "/var/run/tor")
1118 (target source)
1119 (writable? #t))
1120 (file-system-mapping
1121 (source torrc)
1122 (target source))
1123
1124 ;; Transport plugins like the lyrebird
1125 ;; webtunnel need X.509 certificates.
1126 (file-system-mapping
1127 (source (file-append nss-certs "/etc/ssl/certs"))
1128 (target "/etc/ssl/certs")))
1129 (map (lambda (plugin)
1130 (file-system-mapping
1131 (source (tor-plugin-program plugin))
1132 (target source)))
1133 transport-plugins))
1134 #:namespaces (delq 'net %namespaces))))
1135 (list (shepherd-service
1136 (provision '(tor))
1137
1138 ;; Tor needs at least one network interface to be up, hence the
1139 ;; dependency on 'loopback'.
1140 (requirement '(user-processes loopback syslogd))
1141
1142 ;; XXX: #:pid-file won't work because the wrapped 'tor'
1143 ;; program would print its PID within the user namespace
1144 ;; instead of its actual PID outside. There's no inetd or
1145 ;; systemd socket activation support either (there's
1146 ;; 'sd_notify' though), so we're stuck with that.
1147 (start #~(make-forkexec-constructor
1148 (list #$tor "-f" #$torrc)
1149 #:user "tor" #:group "tor"))
1150 (auto-start? auto-start?)
1151 (stop #~(make-kill-destructor))
1152 (actions (list (shepherd-configuration-action torrc)))
1153 (documentation "Run the Tor anonymous network overlay.")))))
1154
1155(define (tor-activation config)
1156 "Set up directories for Tor and its hidden services, if any."
1157 #~(begin
1158 (use-modules (guix build utils))
1159
1160 (define %user
1161 (getpw "tor"))
1162
1163 (define (initialize service)
1164 (let ((directory (string-append "/var/lib/tor/hidden-services/"
1165 service)))
1166 (mkdir-p directory)
1167 (chown directory (passwd:uid %user) (passwd:gid %user))
1168
1169 ;; The daemon bails out if we give wider permissions.
1170 (chmod directory #o700)))
1171
1172 ;; Allow Tor to write its PID file.
1173 (mkdir-p "/var/run/tor")
1174 (chown "/var/run/tor" (passwd:uid %user) (passwd:gid %user))
1175 ;; Set the group permissions to rw so that if the system administrator
1176 ;; has specified UnixSocksGroupWritable=1 in their torrc file, members
1177 ;; of the "tor" group will be able to use the SOCKS socket.
1178 (chmod "/var/run/tor" #o750)
1179
1180 ;; Allow Tor to access the hidden services' directories.
1181 (mkdir-p "/var/lib/tor")
1182 (chown "/var/lib/tor" (passwd:uid %user) (passwd:gid %user))
1183 (chmod "/var/lib/tor" #o700)
1184
1185 ;; Make sure /var/lib is accessible to the 'tor' user.
1186 (chmod "/var/lib" #o755)
1187
1188 (for-each initialize
1189 '#$(map tor-onion-service-configuration-name
1190 (tor-configuration-hidden-services config)))))
1191
1192(define tor-service-type
1193 (service-type (name 'tor)
1194 (extensions
1195 (list (service-extension shepherd-root-service-type
1196 tor-shepherd-service)
1197 (service-extension account-service-type
1198 (const %tor-accounts))
1199 (service-extension activation-service-type
1200 tor-activation)))
1201
1202 ;; This can be extended with Tor Onion Services.
1203 (compose concatenate)
1204 (extend (lambda (config services)
1205 (tor-configuration
1206 (inherit config)
1207 (hidden-services
1208 (append (tor-configuration-hidden-services config)
1209 services)))))
1210 (default-value (tor-configuration))
1211 (description
1212 "Run the @uref{https://torproject.org, Tor} anonymous
1213networking daemon.")))
1214
1215(define-deprecated (tor-hidden-service name mapping)
1216 #f
1217 "Define a new Tor @dfn{hidden service} called @var{name} and implementing
1218@var{mapping}. @var{mapping} is a list of port/host tuples, such as:
1219
1220@example
1221 '((22 \"127.0.0.1:22\")
1222 (80 \"127.0.0.1:8080\"))
1223@end example
1224
1225In this example, port 22 of the hidden service is mapped to local port 22, and
1226port 80 is mapped to local port 8080.
1227
1228This creates a @file{/var/lib/tor/hidden-services/@var{name}} directory, where
1229the @file{hostname} file contains the @code{.onion} host name for the hidden
1230service.
1231
1232See @uref{https://www.torproject.org/docs/tor-hidden-service.html.en, the Tor
1233project's documentation} for more information."
1234 (simple-service 'tor-hidden-service
1235 tor-service-type
1236 (list (tor-onion-service-configuration
1237 (name name)
1238 (mapping mapping)))))
1239
1240
1241;;;
1242;;; ModemManager
1243;;;
1244
1245(define-record-type* <modem-manager-configuration>
1246 modem-manager-configuration make-modem-manager-configuration
1247 modem-manager-configuration?
1248 (modem-manager modem-manager-configuration-modem-manager
1249 (default modem-manager)))
1250
1251
1252;;;
1253;;; NetworkManager
1254;;;
1255
1256;; TODO: deprecated field, remove later.
1257(define-with-syntax-properties (warn-iwd?-field-deprecation
1258 (value properties))
1259 (when value
1260 (warning (source-properties->location properties)
1261 (G_ "the 'iwd?' field is deprecated, please use \
1262'shepherd-requirement' field instead~%")))
1263 value)
1264
1265(define-record-type* <network-manager-configuration>
1266 network-manager-configuration make-network-manager-configuration
1267 network-manager-configuration?
1268 (network-manager network-manager-configuration-network-manager
1269 (default network-manager))
1270 (shepherd-requirement network-manager-configuration-shepherd-requirement
1271 (default '(wireless-daemon)))
1272 (dns network-manager-configuration-dns
1273 (default "default"))
1274 (vpn-plugins network-manager-configuration-vpn-plugins ;list of file-like
1275 (default '()))
1276 (iwd? network-manager-configuration-iwd? ; TODO: deprecated field, remove.
1277 (default #f)
1278 (sanitize warn-iwd?-field-deprecation))
1279 (extra-configuration-files
1280 network-manager-configuration-extra-configuration-files
1281 (default '())) ;'((file-name-string file-like-object) ...)
1282 (dnsmasq-configuration-files
1283 network-manager-configuration-dnsmasq-configuration-files
1284 (default '())))
1285
1286(define (network-manager-activation config)
1287 ;; Activation gexp for NetworkManager
1288 (match-record config <network-manager-configuration>
1289 (network-manager dns vpn-plugins extra-configuration-files dnsmasq-configuration-files)
1290 #~(begin
1291 (use-modules (guix build utils))
1292 (mkdir-p "/etc/NetworkManager/system-connections")
1293 #$@(if (equal? dns "dnsmasq")
1294 ;; create directory to store dnsmasq lease file
1295 '((mkdir-p "/var/lib/misc"))
1296 '())
1297 #$@(if (pair? dnsmasq-configuration-files) ;if non-empty
1298 ;; If /etc/NetworkManager/dnsmasq.d is a symlink to a store file,
1299 ;; delete it.
1300 `((when (false-if-exception
1301 (store-file-name? (readlink "/etc/NetworkManager/dnsmasq.d")))
1302 (delete-file "/etc/NetworkManager/dnsmasq.d"))
1303 (symlink
1304 ,(file-union "network-manager-dnsmasq-configuration-directory"
1305 dnsmasq-configuration-files)
1306 "/etc/NetworkManager/dnsmasq.d"))
1307 '())
1308 #$@(if (pair? extra-configuration-files) ;if non-empty
1309 ;; If /etc/NetworkManager/conf.d is a symlink to a store file,
1310 ;; delete it.
1311 `((when (false-if-exception
1312 (store-file-name? (readlink "/etc/NetworkManager/conf.d")))
1313 (delete-file "/etc/NetworkManager/conf.d"))
1314 ;; If it exists but is not a symlink to a store file, then
1315 ;; this will fail with EEXIST; we leave this for the user to
1316 ;; handle, since they probably created the directory
1317 ;; themselves.
1318 (symlink
1319 ,(file-union "network-manager-configuration-directory"
1320 extra-configuration-files)
1321 "/etc/NetworkManager/conf.d"))
1322 '())
1323 ;; Ensure "/etc/ipsec.secrets" exists, which is required by the
1324 ;; nm-l2tp plugin.
1325 (mkdir-p "/etc/ipsec.secrets"))))
1326
1327(define (vpn-plugin-directory plugins)
1328 "Return a directory containing PLUGINS, the NM VPN plugins."
1329 (directory-union "network-manager-vpn-plugins" plugins))
1330
1331(define (network-manager-accounts config)
1332 "Return the list of <user-account> and <user-group> for CONFIG."
1333 (define nologin
1334 (file-append shadow "/sbin/nologin"))
1335
1336 (define accounts
1337 (append-map (lambda (package)
1338 (map (lambda (name)
1339 (user-account (system? #t)
1340 (name name)
1341 (group "network-manager")
1342 (comment "NetworkManager helper")
1343 (home-directory "/var/empty")
1344 (create-home-directory? #f)
1345 (shell nologin)))
1346 (or (assoc-ref (package-properties package)
1347 'user-accounts)
1348 '())))
1349 (network-manager-configuration-vpn-plugins config)))
1350
1351 (match accounts
1352 (()
1353 '())
1354 (_
1355 (cons (user-group (name "network-manager") (system? #t))
1356 accounts))))
1357
1358(define (network-manager-environment config)
1359 (match-record config <network-manager-configuration>
1360 (network-manager dns vpn-plugins)
1361 ;; Define this variable in the global environment such that
1362 ;; "nmcli connection import type openvpn file foo.ovpn" works.
1363 `(("NM_VPN_PLUGIN_DIR"
1364 . ,(file-append (vpn-plugin-directory vpn-plugins)
1365 "/lib/NetworkManager/VPN")))))
1366
1367(define (network-manager-shepherd-service config)
1368 (match-record config <network-manager-configuration>
1369 (network-manager shepherd-requirement dns vpn-plugins iwd?)
1370 (let* ((iwd? (or iwd? ; TODO: deprecated field, remove later.
1371 (and shepherd-requirement
1372 (memq 'iwd shepherd-requirement))))
1373 (conf (plain-file "NetworkManager.conf"
1374 (string-append
1375 "[main]\ndns=" dns "\n"
1376 (if iwd? "[device]\nwifi.backend=iwd\n" ""))))
1377 (vpn (vpn-plugin-directory vpn-plugins)))
1378 (list (shepherd-service
1379 (documentation "Run the NetworkManager.")
1380 (provision '(NetworkManager networking))
1381 (requirement `(user-processes dbus-system loopback
1382 ,@shepherd-requirement
1383 ;; TODO: iwd? is deprecated and should be passed
1384 ;; with shepherd-requirement, remove later.
1385 ,@(if iwd? '(iwd) '())))
1386 (actions (list (shepherd-configuration-action conf)))
1387 (start
1388 #~(lambda _
1389 (let ((pid
1390 (fork+exec-command
1391 (list #$(file-append network-manager
1392 "/sbin/NetworkManager")
1393 (string-append "--config=" #$conf)
1394 "--no-daemon")
1395 #:environment-variables
1396 (list (string-append "NM_VPN_PLUGIN_DIR=" #$vpn
1397 "/lib/NetworkManager/VPN")
1398 ;; Override non-existent default users
1399 "NM_OPENVPN_USER="
1400 "NM_OPENVPN_GROUP="
1401 ;; Allow NetworkManager to find the modules.
1402 (string-append
1403 "LINUX_MODULE_DIRECTORY="
1404 "/run/booted-system/kernel/lib/modules")))))
1405 ;; XXX: Despite the "online" name, this doesn't guarantee
1406 ;; WAN connectivity, it merely waits for NetworkManager
1407 ;; to finish starting-up. This is required otherwise
1408 ;; services will fail since the network interfaces be
1409 ;; absent until NetworkManager finishes setting them up.
1410 (system* #$(file-append network-manager "/bin/nm-online")
1411 "--wait-for-startup" "--quiet")
1412 ;; XXX: Finally, return the pid from running
1413 ;; fork+exec-command to shepherd.
1414 pid)))
1415 (stop #~(make-kill-destructor)))))))
1416
1417(define network-manager-service-type
1418 (let ((config->packages
1419 (lambda (config)
1420 (match-record config <network-manager-configuration>
1421 (network-manager vpn-plugins)
1422 `(,network-manager ,@vpn-plugins)))))
1423
1424 (service-type
1425 (name 'network-manager)
1426 (extensions
1427 (list (service-extension shepherd-root-service-type
1428 network-manager-shepherd-service)
1429 (service-extension dbus-root-service-type config->packages)
1430 (service-extension polkit-service-type
1431 (compose
1432 list
1433 network-manager-configuration-network-manager))
1434 (service-extension account-service-type
1435 network-manager-accounts)
1436 (service-extension activation-service-type
1437 network-manager-activation)
1438 (service-extension session-environment-service-type
1439 network-manager-environment)
1440 ;; Add network-manager to the system profile.
1441 (service-extension profile-service-type config->packages)))
1442 (default-value (network-manager-configuration))
1443 (description
1444 "Run @uref{https://wiki.gnome.org/Projects/NetworkManager,
1445NetworkManager}, a network management daemon that aims to simplify wired and
1446wireless networking."))))
1447
1448
1449;;;
1450;;; Connman
1451;;;
1452
1453(define (connman-general-configuration-field-name field-name)
1454 (let* ((str->camel (lambda (s)
1455 (string-concatenate
1456 (map string-capitalize (string-split s #\-)))))
1457 (str (if (symbol? field-name)
1458 (str->camel (symbol->string field-name))
1459 field-name)))
1460 (cond
1461 ((string-suffix? "?" str) (connman-general-configuration-field-name
1462 (string-drop-right str 1)))
1463 ((string-contains str "RegulatoryDomain") (connman-general-configuration-field-name
1464 (string-replace-substring str "RegulatoryDomain" "Regdom")))
1465 ((string-contains str "Url") (connman-general-configuration-field-name
1466 (string-replace-substring str "Url" "URL")))
1467 ((string-contains str "Ip") (connman-general-configuration-field-name
1468 (string-replace-substring str "Ip" "IP")))
1469 ((string-contains str "6To4") (connman-general-configuration-field-name
1470 (string-replace-substring str "6To4" "6to4")))
1471 (#t str))))
1472
1473(define (connman-general-configuration-serialize-string field-name value)
1474 (let ((param (connman-general-configuration-field-name field-name)))
1475 #~(string-append #$param " = " #$value "\n")))
1476
1477(define (connman-general-configuration-serialize-number field-name value)
1478 (connman-general-configuration-serialize-string
1479 field-name (number->string value)))
1480
1481(define (connman-general-configuration-serialize-list field-name value)
1482 (connman-general-configuration-serialize-string
1483 field-name (string-join value ",")))
1484
1485(define (connman-general-configuration-serialize-boolean field-name value)
1486 (connman-general-configuration-serialize-string
1487 field-name (if value "true" "false")))
1488
1489(define-maybe boolean (prefix connman-general-configuration-))
1490(define-maybe number (prefix connman-general-configuration-))
1491(define-maybe string (prefix connman-general-configuration-))
1492(define-maybe list (prefix connman-general-configuration-))
1493
1494(define-configuration connman-general-configuration
1495 (input-request-timeout
1496 maybe-number
1497 "Set input request timeout. Default is 120 seconds. The request for inputs
1498like passphrase will timeout after certain amount of time. Use this setting to
1499increase the value in case of different user interface designs.")
1500 (browser-launch-timeout
1501 maybe-number
1502 "Set browser launch timeout. Default is 300 seconds. The request for
1503launching a browser for portal pages will timeout after certain amount of
1504time. Use this setting to increase the value in case of different user
1505interface designs.")
1506 (background-scanning?
1507 maybe-boolean
1508 "Enable background scanning. Default is true. If wifi is disconnected, the
1509background scanning will follow a simple back off mechanism from 3s up to 5
1510minutes. Then, it will stay in 5 minutes unless user specifically asks for
1511scanning through a D-Bus call. If so, the mechanism will start again from
15123s. This feature activates also the background scanning while being connected,
1513which is required for roaming on wifi. When @code{background-scanning?} is false,
1514ConnMan will not perform any scan regardless of wifi is connected or not,
1515unless it is requested by the user through a D-Bus call.")
1516 (use-gateways-as-timeservers?
1517 maybe-boolean
1518 "Assume that service gateways also function as timeservers. Default is false.")
1519 (fallback-timeservers
1520 maybe-list
1521 "List of Fallback timeservers. These timeservers are used for NTP sync
1522when there are no timeservers set by the user or by the service, and when
1523@code{use-gateways-as-timeservers?} is @code{#f}. These can contain a mixed
1524combination of fully qualified domain names, IPv4 and IPv6 addresses.")
1525 (fallback-nameservers
1526 maybe-list
1527 "List of fallback nameservers appended to the list of nameservers given
1528by the service. The nameserver entries must be in numeric format,
1529host names are ignored.")
1530 (default-auto-connect-technologies
1531 maybe-list
1532 "List of technologies that are marked autoconnectable by default. The
1533default value for this entry when empty is @code{\"ethernet\"}, @code{\"wifi\"},
1534@code{\"cellular\"}. Services that are automatically connected must have been
1535set up and saved to storage beforehand.")
1536 (default-favourite-technologies
1537 maybe-list
1538 "List of technologies that are marked favorite by default. The default
1539value for this entry when empty is @code{\"ethernet\"}. Connects to services
1540from this technology even if not setup and saved to storage.")
1541 (always-connected-technologies
1542 maybe-list
1543 "List of technologies which are always connected regardless of
1544preferred-technologies setting (@code{auto-connect?} @code{#t}). The default
1545value is empty and this feature is disabled unless explicitly enabled.")
1546 (preferred-technologies
1547 maybe-list
1548 "List of preferred technologies from the most preferred one to the least
1549preferred one. Services of the listed technology type will be tried one by
1550one in the order given, until one of them gets connected or they are all
1551tried. A service of a preferred technology type in state 'ready' will get
1552the default route when compared to another preferred type further down the
1553list with state 'ready' or with a non-preferred type; a service of a
1554preferred technology type in state 'online' will get the default route when
1555compared to either a non-preferred type or a preferred type further down
1556in the list.")
1557 (network-interface-blacklist
1558 maybe-list
1559 "List of blacklisted network interfaces. Found interfaces will be
1560compared to the list and will not be handled by ConnMan, if their first
1561characters match any of the list entries. Default value is @code{\"vmnet\"},
1562@code{\"vboxnet\"}, @code{\"virbr\"}, @code{\"ifb\"}.")
1563 (allow-hostname-updates?
1564 maybe-boolean
1565 "Allow ConnMan to change the system hostname. This can happen for
1566example if we receive DHCP hostname option. Default value is @code{#t}.")
1567 (allow-domainname-updates?
1568 maybe-boolean
1569 "Allow connman to change the system domainname. This can happen for
1570example if we receive DHCP domainname option. Default value is @code{#t}.")
1571 (single-connected-technology?
1572 maybe-boolean
1573 "Keep only a single connected technology at any time. When a new
1574service is connected by the user or a better one is found according to
1575preferred-technologies, the new service is kept connected and all the
1576other previously connected services are disconnected. With this setting
1577it does not matter whether the previously connected services are
1578in 'online' or 'ready' states, the newly connected service is the only
1579one that will be kept connected. A service connected by the user will
1580be used until going out of network coverage. With this setting enabled
1581applications will notice more network breaks than normal. Note this
1582options can't be used with VPNs. Default value is @code{#f}.")
1583 (tethering-technologies
1584 maybe-list
1585 "List of technologies that are allowed to enable tethering. The
1586default value is @code{\"wifi\"}, @code{\"bluetooth\"},
1587@code{\"gadget\"}. Only those technologies listed here are used for
1588tethering. If one wants to tether ethernet, then add @code{\"ethernet\"}
1589in the list. Note that if ethernet tethering is enabled, then a DHCP
1590server is started on all ethernet interfaces. Tethered ethernet should
1591never be connected to corporate or home network as it will disrupt normal
1592operation of these networks. Due to this ethernet is not tethered by
1593default. Do not activate ethernet tethering unless you really know
1594what you are doing.")
1595 (persistent-tethering-mode?
1596 maybe-boolean
1597 "Restore earlier tethering status when returning from offline mode,
1598re-enabling a technology, and after restarts and reboots. Default
1599value is @code{#f}.")
1600 (enable-6to4?
1601 maybe-boolean
1602 "Automatically enable anycast 6to4 if possible. This is not
1603recommended, as the use of 6to4 will generally lead to a severe
1604degradation of connection quality. See RFC6343. Default value
1605is @code{#f} (as recommended by RFC6343 section 4.1).")
1606 (vendor-class-id
1607 maybe-string
1608 "Set DHCP option 60 (Vendor Class ID) to the given string. This
1609option can be used by DHCP servers to identify specific clients
1610without having to rely on MAC address ranges, etc.")
1611 (enable-online-check?
1612 maybe-boolean
1613 "Enable or disable use of HTTP GET as an online status check. When
1614a service is in a READY state, and is selected as default, ConnMan will
1615issue an HTTP GET request to verify that end-to-end connectivity is
1616successful. Only then the service will be transitioned to ONLINE
1617state. If this setting is false, the default service will remain
1618in READY state. Default value is @code{#t}.")
1619 (online-check-ipv4-url
1620 maybe-string
1621 "IPv4 URL used during the online status check. Please refer to
1622the README for more detailed information. Default value is
1623@url{http://ipv4.connman.net/online/status.html}.")
1624 (online-check-ipv6-url
1625 maybe-string
1626 "IPv6 URL used during the online status check. Please refer to
1627the README for more detailed information. Default value is
1628@url{http://ipv6.connman.net/online/status.html}.")
1629 (online-check-initial-interval
1630 maybe-number
1631 "Range of intervals between two online check requests. Please
1632refer to the README for more detailed information. Default value
1633is @samp{1}.")
1634 (online-check-max-interval
1635 maybe-number
1636 "Range of intervals between two online check requests. Please
1637refer to the README for more detailed information. Default value
1638is @samp{1}.")
1639 (enable-online-to-ready-transition?
1640 maybe-boolean
1641 "WARNING: This is an experimental feature. In addition to
1642@code{enable-online-check} setting, enable or disable use of HTTP GET
1643to detect the loss of end-to-end connectivity. If this setting is
1644@code{#f}, when the default service transitions to ONLINE state, the
1645HTTP GET request is no more called until next cycle, initiated by a
1646transition of the default service to DISCONNECT state. If this
1647setting is @code{#t}, the HTTP GET request keeps being called to
1648guarantee that end-to-end connectivity is still successful. If not,
1649the default service will transition to READY state, enabling another
1650service to become the default one, in replacement. Default value
1651is @code{#f}.")
1652 (auto-connect-roaming-services?
1653 maybe-boolean
1654 "Automatically connect roaming services. This is not recommended
1655unless you know you won't have any billing problem. Default value
1656is @code{#f}.")
1657 (address-conflict-detection?
1658 maybe-boolean
1659 "Enable or disable the implementation of IPv4 address conflict
1660detection according to RFC5227. ConnMan will send probe ARP packets
1661to see if an IPv4 address is already in use before assigning the
1662address to an interface. If an address conflict occurs for a
1663statically configured address, an IPv4LL address will be chosen
1664instead (according to RFC3927). If an address conflict occurs for
1665an address offered via DHCP, ConnMan sends a DHCP DECLINE once
1666and for the second conflict resorts to finding an IPv4LL
1667address. Default value is @code{#f}.")
1668 (localtime
1669 maybe-string
1670 "Path to localtime file. Defaults to @file{/etc/localtime}.")
1671 (regulatory-domain-follows-timezone?
1672 maybe-boolean
1673 "Enable regulatory domain to be changed along timezone changes.
1674With this option set to true each time the timezone changes the first
1675present ISO3166 country code is read from
1676@file{/usr/share/zoneinfo/zone1970.tab} and set as regulatory domain
1677value. Default value is @code{#f}.")
1678 (resolv-conf
1679 maybe-string
1680 "Path to resolv.conf file. If the file does not exist, but
1681intermediate directories exist, it will be created. If this option
1682is not set, it tries to write into @file{/var/run/connman/resolv.conf}
1683if it fails (@file{/var/run/connman} does not exist or is not
1684writeable). If you do not want to update resolv.conf, you can
1685set @file{/dev/null}.")
1686 (prefix connman-general-configuration-))
1687
1688(define-record-type* <connman-configuration>
1689 connman-configuration make-connman-configuration
1690 connman-configuration?
1691 (connman connman-configuration-connman
1692 (default connman))
1693 (shepherd-requirement connman-configuration-shepherd-requirement
1694 (default '()))
1695 (disable-vpn? connman-configuration-disable-vpn?
1696 (default #f))
1697 (iwd? connman-configuration-iwd?
1698 (default #f)
1699 (sanitize warn-iwd?-field-deprecation))
1700 (general-configuration connman-configuration-general-configuration
1701 (default (connman-general-configuration))))
1702
1703(define (connman-activation config)
1704 (let ((disable-vpn? (connman-configuration-disable-vpn? config)))
1705 (with-imported-modules '((guix build utils))
1706 #~(begin
1707 (use-modules (guix build utils))
1708 (mkdir-p "/var/lib/connman/")
1709 (unless #$disable-vpn?
1710 (mkdir-p "/var/lib/connman-vpn/"))))))
1711
1712(define (connman-shepherd-service config)
1713 (match-record config <connman-configuration> (connman shepherd-requirement
1714 disable-vpn? iwd?
1715 general-configuration)
1716 (let ((iwd? (or iwd? ; TODO: deprecated field, remove later.
1717 (and shepherd-requirement
1718 (memq 'iwd shepherd-requirement))))
1719 (config (mixed-text-file
1720 "main.conf"
1721 "[General]\n"
1722 (serialize-configuration
1723 general-configuration
1724 connman-general-configuration-fields))))
1725 (list (shepherd-service
1726 (documentation "Run Connman")
1727 (provision '(connman networking))
1728 (requirement `(user-processes dbus-system loopback
1729 ,@shepherd-requirement
1730 ;; TODO: iwd? is deprecated and should be passed
1731 ;; with shepherd-requirement, remove later.
1732 ,@(if iwd? '(iwd) '())))
1733 (start #~(make-forkexec-constructor
1734 (list (string-append #$connman
1735 "/sbin/connmand")
1736 (string-append "--config=" #$config)
1737 "--nodaemon"
1738 "--nodnsproxy"
1739 #$@(if disable-vpn? '("--noplugin=vpn") '())
1740 #$@(if iwd? '("--wifi=iwd_agent") '()))
1741
1742 ;; As connman(8) notes, when passing '-n', connman
1743 ;; "directs log output to the controlling terminal in
1744 ;; addition to syslog." Redirect stdout and stderr
1745 ;; to avoid spamming the console (XXX: for some reason
1746 ;; redirecting to /dev/null doesn't work.)
1747 #:log-file "/var/log/connman.log"))
1748 (stop #~(make-kill-destructor)))))))
1749
1750(define connman-service-type
1751 (let ((connman-package (compose list connman-configuration-connman)))
1752 (service-type (name 'connman)
1753 (extensions
1754 (list (service-extension shepherd-root-service-type
1755 connman-shepherd-service)
1756 (service-extension polkit-service-type
1757 connman-package)
1758 (service-extension dbus-root-service-type
1759 connman-package)
1760 (service-extension activation-service-type
1761 connman-activation)
1762 ;; Add connman to the system profile.
1763 (service-extension profile-service-type
1764 connman-package)))
1765 (default-value (connman-configuration))
1766 (description
1767 "Run @url{https://01.org/connman,Connman},
1768a network connection manager."))))
1769
1770
1771;;;
1772;;; Modem manager
1773;;;
1774
1775(define modem-manager-service-type
1776 (let ((config->package
1777 (lambda (config)
1778 (list (modem-manager-configuration-modem-manager config)))))
1779 (service-type (name 'modem-manager)
1780 (extensions
1781 (list (service-extension dbus-root-service-type
1782 config->package)
1783 (service-extension udev-service-type
1784 config->package)
1785 (service-extension polkit-service-type
1786 config->package)))
1787 (default-value (modem-manager-configuration))
1788 (description
1789 "Run @uref{https://wiki.gnome.org/Projects/ModemManager,
1790ModemManager}, a modem management daemon that aims to simplify dialup
1791networking."))))
1792
1793
1794;;;
1795;;; USB_ModeSwitch
1796;;;
1797
1798(define-record-type* <usb-modeswitch-configuration>
1799 usb-modeswitch-configuration make-usb-modeswitch-configuration
1800 usb-modeswitch-configuration?
1801 (usb-modeswitch usb-modeswitch-configuration-usb-modeswitch
1802 (default usb-modeswitch))
1803 (usb-modeswitch-data usb-modeswitch-configuration-usb-modeswitch-data
1804 (default usb-modeswitch-data))
1805 (config-file usb-modeswitch-configuration-config-file
1806 (default #~(string-append #$usb-modeswitch:dispatcher
1807 "/etc/usb_modeswitch.conf"))))
1808
1809(define (usb-modeswitch-sh usb-modeswitch config-file)
1810 "Build a copy of usb_modeswitch.sh located in package USB-MODESWITCH,
1811modified to pass the CONFIG-FILE in its calls to usb_modeswitch_dispatcher,
1812and wrap it to actually find the dispatcher in USB-MODESWITCH. The script
1813will be run by USB_ModeSwitch’s udev rules file when a modeswitchable USB
1814device is detected."
1815 (computed-file
1816 "usb_modeswitch-sh"
1817 (with-imported-modules '((guix build utils))
1818 #~(begin
1819 (use-modules (guix build utils))
1820 (let ((cfg-param
1821 #$(if config-file
1822 #~(string-append " --config-file=" #$config-file)
1823 "")))
1824 (mkdir #$output)
1825 (install-file (string-append #$usb-modeswitch:dispatcher
1826 "/lib/udev/usb_modeswitch")
1827 #$output)
1828
1829 ;; insert CFG-PARAM into usb_modeswitch_dispatcher command-lines
1830 (substitute* (string-append #$output "/usb_modeswitch")
1831 (("(exec usb_modeswitch_dispatcher .*)( 2>>)" _ left right)
1832 (string-append left cfg-param right))
1833 (("(exec usb_modeswitch_dispatcher .*)( &)" _ left right)
1834 (string-append left cfg-param right)))
1835
1836 ;; wrap-program needs bash in PATH:
1837 (putenv (string-append "PATH=" #$bash "/bin"))
1838 (wrap-program (string-append #$output "/usb_modeswitch")
1839 `("PATH" ":" = (,(string-append #$coreutils "/bin")
1840 ,(string-append
1841 #$usb-modeswitch:dispatcher
1842 "/bin")))))))))
1843
1844(define (usb-modeswitch-configuration->udev-rules config)
1845 "Build a rules file for extending udev-service-type from the rules in the
1846usb-modeswitch package specified in CONFIG. The rules file will invoke
1847usb_modeswitch.sh from the usb-modeswitch package, modified to pass the right
1848config file."
1849 (match-record config <usb-modeswitch-configuration>
1850 (usb-modeswitch usb-modeswitch-data config-file)
1851 (computed-file
1852 "usb_modeswitch.rules"
1853 (with-imported-modules '((guix build utils))
1854 #~(begin
1855 (use-modules (guix build utils))
1856 (let ((in (string-append #$usb-modeswitch-data
1857 "/udev/40-usb_modeswitch.rules"))
1858 (out (string-append #$output "/lib/udev/rules.d"))
1859 (script #$(usb-modeswitch-sh usb-modeswitch config-file)))
1860 (mkdir-p out)
1861 (chdir out)
1862 (install-file in out)
1863 (substitute* "40-usb_modeswitch.rules"
1864 (("PROGRAM=\"usb_modeswitch")
1865 (string-append "PROGRAM=\"" script "/usb_modeswitch"))
1866 (("RUN\\+=\"usb_modeswitch")
1867 (string-append "RUN+=\"" script "/usb_modeswitch")))))))))
1868
1869(define usb-modeswitch-service-type
1870 (service-type
1871 (name 'usb-modeswitch)
1872 (extensions
1873 (list
1874 (service-extension
1875 udev-service-type
1876 (lambda (config)
1877 (let ((rules (usb-modeswitch-configuration->udev-rules config)))
1878 (list rules))))))
1879 (default-value (usb-modeswitch-configuration))
1880 (description "Run @uref{http://www.draisberghof.de/usb_modeswitch/,
1881USB_ModeSwitch}, a mode switching tool for controlling USB devices with
1882multiple @dfn{modes}. When plugged in for the first time many USB
1883devices (primarily high-speed WAN modems) act like a flash storage containing
1884installers for Windows drivers. USB_ModeSwitch replays the sequence the
1885Windows drivers would send to switch their mode from storage to modem (or
1886whatever the thing is supposed to do).")))
1887
1888
1889;;;
1890;;; WPA supplicant
1891;;;
1892
1893(define-with-syntax-properties (warn-deprecated-wpa-supplicant-requirement
1894 (value properties))
1895 (unless (unspecified? value)
1896 (warning (source-properties->location properties)
1897 (G_ "the 'requirement' field is deprecated, please use \
1898'shepherd-requirement' field instead~%")))
1899 value)
1900
1901(define-record-type* <wpa-supplicant-configuration>
1902 wpa-supplicant-configuration make-wpa-supplicant-configuration
1903 wpa-supplicant-configuration?
1904 (wpa-supplicant wpa-supplicant-configuration-wpa-supplicant ;file-like
1905 (default wpa-supplicant))
1906 (requirement wpa-supplicant-configuration-requirement ;list of symbols
1907 (sanitize warn-deprecated-wpa-supplicant-requirement)
1908 (default *unspecified*))
1909 (pid-file wpa-supplicant-configuration-pid-file ;string
1910 (default "/var/run/wpa_supplicant.pid"))
1911 (dbus? wpa-supplicant-configuration-dbus? ;Boolean
1912 (default #t))
1913 (interface wpa-supplicant-configuration-interface ;#f | string
1914 (default #f))
1915 (config-file wpa-supplicant-configuration-config-file ;#f | <file-like>
1916 (default #f))
1917 (extra-options wpa-supplicant-configuration-extra-options ;list of strings
1918 (default '()))
1919 (shepherd-provision wpa-supplicant-configuration-shepherd-provision ;list of symbols
1920 (default '(wpa-supplicant wireless-daemon)))
1921 (shepherd-requirement wpa-supplicant-configuration-shepherd-requirement ;list of symbols
1922 (default '(user-processes loopback syslogd))))
1923
1924(define (wpa-supplicant-shepherd-service config)
1925 (match-record config <wpa-supplicant-configuration>
1926 (wpa-supplicant requirement pid-file dbus?
1927 shepherd-requirement shepherd-provision
1928 interface config-file extra-options)
1929 (list (shepherd-service
1930 (documentation "Run the WPA supplicant daemon")
1931 (provision shepherd-provision)
1932 (requirement `(,@(if dbus? '(dbus-system) '())
1933 ,@(or (if (unspecified? requirement) #f requirement)
1934 shepherd-requirement)))
1935 (start #~(make-forkexec-constructor
1936 (list (string-append #$wpa-supplicant
1937 "/sbin/wpa_supplicant")
1938 (string-append "-P" #$pid-file)
1939 "-B" ;run in background
1940 "-s" ;log to syslogd
1941 #$@(if dbus?
1942 #~("-u")
1943 #~())
1944 #$@(if interface
1945 #~((string-append "-i" #$interface))
1946 #~())
1947 #$@(if config-file
1948 #~((string-append "-c" #$config-file))
1949 #~())
1950 #$@extra-options)
1951 #:pid-file #$pid-file))
1952 (stop #~(make-kill-destructor))))))
1953
1954(define wpa-supplicant-service-type
1955 (let ((config->package
1956 (lambda (config)
1957 (list (wpa-supplicant-configuration-wpa-supplicant config)))))
1958 (service-type (name 'wpa-supplicant)
1959 (extensions
1960 (list (service-extension shepherd-root-service-type
1961 wpa-supplicant-shepherd-service)
1962 (service-extension dbus-root-service-type config->package)
1963 (service-extension profile-service-type config->package)))
1964 (description "Run the WPA Supplicant daemon, a service that
1965implements authentication, key negotiation and more for wireless networks.")
1966 (default-value (wpa-supplicant-configuration)))))
1967
1968
1969;;;
1970;;; IWD
1971;;;
1972(define (iwd-uglify-field-name name)
1973 (object->camel-case-string name 'upper))
1974
1975(define (iwd-serialize-base field-name val)
1976 (format #f "~a=~a\n" field-name val))
1977
1978(define (iwd-serialize-field field-name val)
1979 (iwd-serialize-base (iwd-uglify-field-name field-name) val))
1980
1981(define iwd-serialize-number iwd-serialize-field)
1982
1983(define (iwd-serialize-boolean field-name value)
1984 (iwd-serialize-field
1985 (string-trim-right (symbol->string field-name) #\?)
1986 (if value "true" "false")))
1987
1988(define (iwd-serialize-alist field-name value)
1989 (if (null? value)
1990 ""
1991 #~(string-append #$@(generic-serialize-alist list
1992 iwd-serialize-base
1993 value))))
1994
1995(define-enumerated-field-type resolving-service
1996 (none systemd resolvconf)
1997 (prefix iwd-))
1998
1999(define-configuration iwd-general-settings
2000 (enable-network-configuration?
2001 (boolean #f)
2002 "Setting this option to true enables @code{iwd} to configure the network
2003interfaces with the IP addresses.")
2004 (extra-options
2005 (alist '())
2006 "An association list of option symbols/strings to string values to be
2007appended to the General settings group.")
2008
2009 (prefix iwd-))
2010
2011(define-configuration iwd-network-settings
2012 (enable-ipv6?
2013 (boolean #t)
2014 "Sets the global default that tells @code{iwd} whether it should configure
2015IPv6 addresses and routes")
2016
2017 (name-resolving-service
2018 (resolving-service 'none)
2019 "Configures a DNS resolution method used by the system.")
2020
2021 (extra-options
2022 (alist '())
2023 "An association list of option symbols/strings to string values to be
2024appended to the Network settings group.")
2025
2026 (prefix iwd-))
2027
2028(define-configuration iwd-scan-settings
2029 (disable-periodic-scan?
2030 (boolean #f)
2031 "Setting this option to @code{#t} will prevent @code{iwd} from issuing the
2032periodic scans for the available networks while disconnected.")
2033
2034 (initial-periodic-scan-interval
2035 (number 10)
2036 "The initial periodic scan interval upon disconnect (in seconds).")
2037
2038 (maximum-periodic-scan-interval
2039 (number 300)
2040 "The maximum periodic scan interval (in seconds).")
2041
2042 (disable-roaming-scan?
2043 (boolean #f)
2044 "Setting this option to @code{#t} will prevent @code{iwd} from trying to scan
2045when roaming decisions are activated.")
2046
2047 (extra-options
2048 (alist '())
2049 "An association list of option symbols/strings to string values to be
2050appended to the Scan settings group.")
2051
2052 (prefix iwd-))
2053
2054(define-maybe iwd-network-settings)
2055(define-maybe iwd-scan-settings)
2056
2057(define ((iwd-serialize-config-section fields) name cfg)
2058 #~(format #f "[~a]\n~a\n"
2059 #$(string-upcase (object->string name) 0 1)
2060 #$(serialize-configuration cfg fields)))
2061
2062(define serialize-iwd-network-settings
2063 (iwd-serialize-config-section iwd-network-settings-fields))
2064
2065(define serialize-iwd-scan-settings
2066 (iwd-serialize-config-section iwd-scan-settings-fields))
2067
2068(define serialize-iwd-general-settings
2069 (iwd-serialize-config-section iwd-general-settings-fields))
2070
2071(define-configuration iwd-settings
2072 (general
2073 (iwd-general-settings (iwd-general-settings))
2074 "General settings.")
2075
2076 (network
2077 (maybe-iwd-network-settings (iwd-network-settings))
2078 "Network settings.")
2079
2080 (scan
2081 maybe-iwd-scan-settings
2082 "Scan settings.")
2083
2084 (extra-config
2085 (list-of-strings '())
2086 "Extra configuration values to append to the IWD configuration file."
2087 (serializer (lambda (_ value) (string-join value "\n" 'suffix)))))
2088
2089(define-configuration/no-serialization iwd-configuration
2090 (iwd
2091 (file-like iwd)
2092 "The IWD package to use.")
2093
2094 (interfaces
2095 (list-of-strings '())
2096 "If this is set, it must specify @dfn{glob patterns} matching network
2097interfaces that IWD will control.")
2098
2099 (ignored-interfaces
2100 (list-of-strings '())
2101 "If this is set, it must specify @dfn{glob patterns} matching network
2102interfaces that IWD will not manage.")
2103
2104 (phys
2105 (list-of-strings '())
2106 "If this is set, it must specify @dfn{glob patterns} matching network
2107PHYs names that IWD will control.")
2108
2109 (ignored-phys
2110 (list-of-strings '())
2111 "If this is set, it must specify @dfn{glob patterns} matching network
2112PHYs names that IWD will not manage.")
2113
2114 (shepherd-requirement
2115 (list-of-symbols '())
2116 "Shepherd requirements the service should depend on.")
2117
2118 (shepherd-provision
2119 (list-of-symbols '(iwd wireless-daemon))
2120 "The name(s) of the service.")
2121
2122 (config
2123 (iwd-settings (iwd-settings))
2124 "Configuration settings."))
2125
2126(define (iwd-generate-documentation)
2127 (configuration->documentation 'iwd-configuration)
2128 (configuration->documentation 'iwd-settings)
2129 (configuration->documentation 'iwd-general-settings)
2130 (configuration->documentation 'iwd-network-settings)
2131 (configuration->documentation 'iwd-scan-settings))
2132
2133(define (iwd-config-file config)
2134 "Return an IWD configuration file."
2135 (mixed-text-file "main.conf"
2136 (serialize-configuration
2137 (iwd-configuration-config config)
2138 iwd-settings-fields)))
2139
2140(define (iwd-environment config)
2141 (let ((resolver
2142 (and=> (iwd-settings-network (iwd-configuration-config config))
2143 iwd-network-settings-name-resolving-service)))
2144
2145 (if (eq? resolver 'resolvconf)
2146 #~(list (string-append "PATH=" #$openresolv "/sbin"))
2147 #~(list))))
2148
2149(define (iwd-shepherd-service config)
2150 (match-record config <iwd-configuration>
2151 (iwd interfaces ignored-interfaces
2152 phys ignored-phys
2153 shepherd-requirement shepherd-provision)
2154
2155 (list (shepherd-service
2156 (documentation "Run the iNet Wireless Daemon, iwd.")
2157 (provision shepherd-provision)
2158 (requirement `(user-processes dbus-system loopback ,@shepherd-requirement))
2159 (start #~(make-forkexec-constructor
2160 (list (string-append #$iwd "/libexec/iwd")
2161 "--logger=syslog"
2162 #$@(if (null? interfaces) '()
2163 (list (string-append "--interfaces="
2164 (string-join interfaces ","))))
2165 #$@(if (null? ignored-interfaces) '()
2166 (list (string-append "--nointerfaces="
2167 (string-join ignored-interfaces ","))))
2168 #$@(if (null? phys) '()
2169 (list (string-append "--phys="
2170 (string-join phys ","))))
2171 #$@(if (null? ignored-phys) '()
2172 (list (string-append "--nophys="
2173 (string-join ignored-phys ",")))))
2174
2175 #:environment-variables
2176 #$(iwd-environment config)))
2177 (stop #~(make-kill-destructor))))))
2178
2179(define (iwd-etc-service config)
2180 `(("iwd/main.conf" ,(iwd-config-file config))))
2181
2182(define iwd-service-type
2183 (let ((add-iwd-package (compose list iwd-configuration-iwd)))
2184 (service-type (name 'iwd)
2185 (extensions
2186 (list (service-extension shepherd-root-service-type
2187 iwd-shepherd-service)
2188 (service-extension etc-service-type
2189 iwd-etc-service)
2190 (service-extension dbus-root-service-type
2191 add-iwd-package)
2192 (service-extension profile-service-type
2193 add-iwd-package)))
2194 (default-value (iwd-configuration))
2195 (description
2196 "Run the iNet Wireless Daemon,
2197@url{https://iwd.wiki.kernel.org/,iwd}, a network connection manager."))))
2198
2199
2200;;;
2201;;; Hostapd.
2202;;;
2203
2204(define-record-type* <hostapd-configuration>
2205 hostapd-configuration make-hostapd-configuration
2206 hostapd-configuration?
2207 (package hostapd-configuration-package
2208 (default hostapd))
2209 (interface hostapd-configuration-interface ;string
2210 (default "wlan0"))
2211 (ssid hostapd-configuration-ssid) ;string
2212 (broadcast-ssid? hostapd-configuration-broadcast-ssid? ;Boolean
2213 (default #t))
2214 (channel hostapd-configuration-channel ;integer
2215 (default 1))
2216 (driver hostapd-configuration-driver ;string
2217 (default "nl80211"))
2218 ;; See <https://w1.fi/cgit/hostap/plain/hostapd/hostapd.conf> for a list of
2219 ;; additional options we could add.
2220 (extra-settings hostapd-configuration-extra-settings ;string
2221 (default "")))
2222
2223(define (hostapd-configuration-file config)
2224 "Return the configuration file for CONFIG, a <hostapd-configuration>."
2225 (match-record config <hostapd-configuration>
2226 (interface ssid broadcast-ssid? channel driver extra-settings)
2227 (plain-file "hostapd.conf"
2228 (string-append "\
2229# Generated from your Guix configuration.
2230
2231interface=" interface "
2232ssid=" ssid "
2233ignore_broadcast_ssid=" (if broadcast-ssid? "0" "1") "
2234channel=" (number->string channel) "\n"
2235extra-settings "\n"))))
2236
2237(define* (hostapd-shepherd-services config #:key (requirement '()))
2238 "Return Shepherd services for hostapd."
2239 (list (shepherd-service
2240 (provision '(hostapd))
2241 (requirement `(user-processes ,@requirement))
2242 (documentation "Run the hostapd WiFi access point daemon.")
2243 (start #~(make-forkexec-constructor
2244 (list #$(file-append (hostapd-configuration-package config)
2245 "/sbin/hostapd")
2246 #$(hostapd-configuration-file config))
2247 #:log-file "/var/log/hostapd.log"))
2248 (stop #~(make-kill-destructor)))))
2249
2250(define hostapd-service-type
2251 (service-type
2252 (name 'hostapd)
2253 (extensions
2254 (list (service-extension shepherd-root-service-type
2255 hostapd-shepherd-services)))
2256 (description
2257 "Run the @uref{https://w1.fi/hostapd/, hostapd} daemon for Wi-Fi access
2258points and authentication servers.")))
2259
2260(define (simulated-wifi-shepherd-services config)
2261 "Return Shepherd services to run hostapd with CONFIG, a
2262<hostapd-configuration>, as well as services to set up WiFi hardware
2263simulation."
2264 (append (hostapd-shepherd-services config
2265 #:requirement
2266 '(unblocked-wifi
2267 kernel-module-loader))
2268 (list (shepherd-service
2269 (provision '(unblocked-wifi))
2270 (requirement '(file-systems kernel-module-loader))
2271 (documentation
2272 "Unblock WiFi devices for use by mac80211_hwsim.")
2273 (start #~(lambda _
2274 (invoke #$(file-append util-linux "/sbin/rfkill")
2275 "unblock" "0")
2276 (invoke #$(file-append util-linux "/sbin/rfkill")
2277 "unblock" "1")))
2278 (one-shot? #t)))))
2279
2280(define simulated-wifi-service-type
2281 (service-type
2282 (name 'simulated-wifi)
2283 (extensions
2284 (list (service-extension shepherd-root-service-type
2285 simulated-wifi-shepherd-services)
2286 (service-extension kernel-module-loader-service-type
2287 (const '("mac80211_hwsim")))))
2288 (default-value (hostapd-configuration
2289 (interface "wlan1")
2290 (ssid "Test Network")))
2291 (description "Run hostapd to simulate WiFi connectivity.")))
2292
2293
2294;;;
2295;;; Open vSwitch
2296;;;
2297
2298(define-record-type* <openvswitch-configuration>
2299 openvswitch-configuration make-openvswitch-configuration
2300 openvswitch-configuration?
2301 (package openvswitch-configuration-package
2302 (default openvswitch)))
2303
2304(define (openvswitch-activation config)
2305 (let ((ovsdb-tool (file-append (openvswitch-configuration-package config)
2306 "/bin/ovsdb-tool")))
2307 (with-imported-modules '((guix build utils))
2308 #~(begin
2309 (use-modules (guix build utils))
2310 (mkdir-p "/var/run/openvswitch")
2311 (mkdir-p "/var/lib/openvswitch")
2312 (let ((conf.db "/var/lib/openvswitch/conf.db"))
2313 (unless (file-exists? conf.db)
2314 (system* #$ovsdb-tool "create" conf.db)))))))
2315
2316(define (openvswitch-shepherd-service config)
2317 (let* ((package (openvswitch-configuration-package config))
2318 (ovsdb-server (file-append package "/sbin/ovsdb-server"))
2319 (ovs-vswitchd (file-append package "/sbin/ovs-vswitchd")))
2320 (list (shepherd-service
2321 (provision '(ovsdb))
2322 (requirement '(user-processes))
2323 (documentation "Run the Open vSwitch database server.")
2324 (start #~(make-forkexec-constructor
2325 (list #$ovsdb-server "--pidfile"
2326 "--remote=punix:/var/run/openvswitch/db.sock")
2327 #:pid-file "/var/run/openvswitch/ovsdb-server.pid"))
2328 (stop #~(make-kill-destructor)))
2329 (shepherd-service
2330 (provision '(vswitchd))
2331 (requirement '(user-processes ovsdb))
2332 (documentation "Run the Open vSwitch daemon.")
2333 (start #~(make-forkexec-constructor
2334 (list #$ovs-vswitchd "--pidfile")
2335 #:pid-file "/var/run/openvswitch/ovs-vswitchd.pid"))
2336 (stop #~(make-kill-destructor))))))
2337
2338(define openvswitch-service-type
2339 (service-type
2340 (name 'openvswitch)
2341 (extensions
2342 (list (service-extension activation-service-type
2343 openvswitch-activation)
2344 (service-extension profile-service-type
2345 (compose list openvswitch-configuration-package))
2346 (service-extension shepherd-root-service-type
2347 openvswitch-shepherd-service)))
2348 (description
2349 "Run @uref{http://www.openvswitch.org, Open vSwitch}, a multilayer virtual
2350switch designed to enable massive network automation through programmatic
2351extension.")
2352 (default-value (openvswitch-configuration))))
2353
2354;;;
2355;;; iptables
2356;;;
2357
2358(define %iptables-accept-all-rules
2359 (plain-file "iptables-accept-all.rules"
2360 "*filter
2361:INPUT ACCEPT
2362:FORWARD ACCEPT
2363:OUTPUT ACCEPT
2364COMMIT
2365"))
2366
2367(define-record-type* <iptables-configuration>
2368 iptables-configuration make-iptables-configuration iptables-configuration?
2369 (iptables iptables-configuration-iptables
2370 (default iptables))
2371 (ipv4-rules iptables-configuration-ipv4-rules
2372 (default %iptables-accept-all-rules))
2373 (ipv6-rules iptables-configuration-ipv6-rules
2374 (default %iptables-accept-all-rules)))
2375
2376(define (iptables-shepherd-service config)
2377 (match-record config <iptables-configuration>
2378 (iptables ipv4-rules ipv6-rules)
2379 (let ((iptables-restore (file-append iptables "/sbin/iptables-restore"))
2380 (ip6tables-restore (file-append iptables "/sbin/ip6tables-restore")))
2381 (shepherd-service
2382 (documentation "Packet filtering framework")
2383 (provision '(iptables))
2384 (start #~(lambda _
2385 (invoke #$iptables-restore #$ipv4-rules)
2386 (invoke #$ip6tables-restore #$ipv6-rules)))
2387 (stop #~(lambda _
2388 (invoke #$iptables-restore #$%iptables-accept-all-rules)
2389 (invoke #$ip6tables-restore #$%iptables-accept-all-rules)))))))
2390
2391(define iptables-service-type
2392 (service-type
2393 (name 'iptables)
2394 (default-value (iptables-configuration))
2395 (description
2396 "Run @command{iptables-restore}, setting up the specified rules.")
2397 (extensions
2398 (list (service-extension shepherd-root-service-type
2399 (compose list iptables-shepherd-service))))))
2400
2401;;;
2402;;; nftables.
2403;;;
2404
2405(define %default-nftables-ruleset
2406 (plain-file "nftables.conf" "\
2407# A simple and safe firewall
2408table inet filter {
2409 chain input {
2410 type filter hook input priority 0; policy drop;
2411
2412 # early drop of invalid connections
2413 ct state invalid drop
2414
2415 # allow established/related connections
2416 ct state { established, related } accept
2417
2418 # allow from loopback
2419 iif lo accept
2420 # drop connections to lo not coming from lo
2421 iif != lo ip daddr 127.0.0.1/8 drop
2422 iif != lo ip6 daddr ::1/128 drop
2423
2424 # allow icmp
2425 ip protocol icmp accept
2426 ip6 nexthdr icmpv6 accept
2427
2428 # allow ssh
2429 tcp dport ssh accept
2430
2431 # reject everything else
2432 reject with icmpx type port-unreachable
2433 }
2434 chain forward {
2435 type filter hook forward priority 0; policy drop;
2436 }
2437 chain output {
2438 type filter hook output priority 0; policy accept;
2439 }
2440}
2441"))
2442
2443(define (debug-level? x)
2444 (member x '(scanner parser eval netlink mnl proto-ctx segtree all)))
2445
2446(define list-of-debug-levels?
2447 (list-of debug-level?))
2448
2449(define-maybe/no-serialization list-of-debug-levels)
2450
2451(define-configuration/no-serialization nftables-configuration
2452 (package
2453 (file-like nftables)
2454 "The @code{nftables} package to use.")
2455 (debug-levels
2456 maybe-list-of-debug-levels
2457 "A list of debug levels, for enabling debugging output. Valid debug level values
2458are the @samp{scanner}, @samp{parser}, @samp{eval}, @samp{netlink},
2459@samp{mnl}, @samp{proto-ctx}, @samp{segtree} or @samp{all} symbols.")
2460 (ruleset
2461 (file-like %default-nftables-ruleset)
2462 "A file-like object containing the complete nftables ruleset. The default
2463ruleset rejects all incoming connections except those to TCP port 22, with
2464connections from the loopback interface are allowed."))
2465
2466(define (nftables-shepherd-service config)
2467 (match-record config <nftables-configuration>
2468 (package debug-levels ruleset)
2469 (let ((nft (file-append package "/sbin/nft")))
2470 (shepherd-service
2471 (documentation "Packet filtering and classification")
2472 (actions (list (shepherd-configuration-action ruleset)))
2473 (provision '(nftables))
2474 (start #~(lambda _
2475 (invoke #$nft
2476 #$@(if (maybe-value-set? debug-levels)
2477 (list (format #f "--debug=~{~a~^,~}"
2478 debug-levels))
2479 #~())
2480 "--file" #$ruleset)))
2481 (stop #~(lambda _
2482 (invoke #$nft "flush" "ruleset")))))))
2483
2484(define nftables-service-type
2485 (service-type
2486 (name 'nftables)
2487 (description
2488 "Run @command{nft}, setting up the specified ruleset.")
2489 (extensions
2490 (list (service-extension shepherd-root-service-type
2491 (compose list nftables-shepherd-service))
2492 (service-extension profile-service-type
2493 (compose list nftables-configuration-package))))
2494 (default-value (nftables-configuration))))
2495
2496
2497;;;
2498;;; PageKite
2499;;;
2500
2501(define-record-type* <pagekite-configuration>
2502 pagekite-configuration
2503 make-pagekite-configuration
2504 pagekite-configuration?
2505 (package pagekite-configuration-package
2506 (default pagekite))
2507 (kitename pagekite-configuration-kitename
2508 (default #f))
2509 (kitesecret pagekite-configuration-kitesecret
2510 (default #f))
2511 (frontend pagekite-configuration-frontend
2512 (default #f))
2513 (kites pagekite-configuration-kites
2514 (default '("http:@kitename:localhost:80:@kitesecret")))
2515 (extra-file pagekite-configuration-extra-file
2516 (default #f)))
2517
2518(define (pagekite-configuration-file config)
2519 (match-record config <pagekite-configuration>
2520 (package kitename kitesecret frontend kites extra-file)
2521 (mixed-text-file "pagekite.rc"
2522 (if extra-file
2523 (string-append "optfile = " extra-file "\n")
2524 "")
2525 (if kitename
2526 (string-append "kitename = " kitename "\n")
2527 "")
2528 (if kitesecret
2529 (string-append "kitesecret = " kitesecret "\n")
2530 "")
2531 (if frontend
2532 (string-append "frontend = " frontend "\n")
2533 "defaults\n")
2534 (string-join (map (lambda (kite)
2535 (string-append "service_on = " kite))
2536 kites)
2537 "\n"
2538 'suffix))))
2539
2540(define (pagekite-shepherd-service config)
2541 (match-record config <pagekite-configuration>
2542 (package kitename kitesecret frontend kites extra-file)
2543 (let* ((config-file (pagekite-configuration-file config))
2544 (mappings (cons (file-system-mapping
2545 (source config-file)
2546 (target source))
2547 (if extra-file
2548 (list (file-system-mapping
2549 (source extra-file)
2550 (target source)))
2551 '())))
2552 (pagekite (least-authority-wrapper
2553 (file-append package "/bin/pagekite")
2554 #:name "pagekite"
2555 #:mappings mappings
2556 ;; 'pagekite' changes user IDs to it needs to run in the
2557 ;; global user namespace.
2558 #:namespaces (fold delq %namespaces '(net user)))))
2559 (shepherd-service
2560 (documentation "Run the PageKite service.")
2561 (provision '(pagekite))
2562 (requirement '(user-processes networking))
2563 (actions (list (shepherd-configuration-action config-file)))
2564 (start #~(make-forkexec-constructor
2565 (list #$pagekite
2566 "--clean"
2567 "--nullui"
2568 "--nocrashreport"
2569 "--runas=pagekite:pagekite"
2570 (string-append "--optfile=" #$config-file))
2571 #:log-file "/var/log/pagekite.log"))
2572 ;; SIGTERM doesn't always work for some reason.
2573 (stop #~(make-kill-destructor SIGINT))))))
2574
2575(define %pagekite-accounts
2576 (list (user-group (name "pagekite") (system? #t))
2577 (user-account
2578 (name "pagekite")
2579 (group "pagekite")
2580 (system? #t)
2581 (comment "PageKite user")
2582 (home-directory "/var/empty")
2583 (shell (file-append shadow "/sbin/nologin")))))
2584
2585(define pagekite-service-type
2586 (service-type
2587 (name 'pagekite)
2588 (default-value (pagekite-configuration))
2589 (extensions
2590 (list (service-extension shepherd-root-service-type
2591 (compose list pagekite-shepherd-service))
2592 (service-extension account-service-type
2593 (const %pagekite-accounts))))
2594 (description
2595 "Run @url{https://pagekite.net/,PageKite}, a tunneling solution to make
2596local servers publicly accessible on the web, even behind NATs and firewalls.")))
2597
2598
2599;;;
2600;;; Yggdrasil
2601;;;
2602
2603(define-record-type* <yggdrasil-configuration>
2604 yggdrasil-configuration
2605 make-yggdrasil-configuration
2606 yggdrasil-configuration?
2607 (package yggdrasil-configuration-package
2608 (default yggdrasil))
2609 (json-config yggdrasil-configuration-json-config
2610 (default '()))
2611 (config-file yggdrasil-config-file
2612 (default "/etc/yggdrasil-private.conf"))
2613 (autoconf? yggdrasil-configuration-autoconf?
2614 (default #f))
2615 (log-level yggdrasil-configuration-log-level
2616 (default 'info))
2617 (log-to yggdrasil-configuration-log-to
2618 (default 'stdout)))
2619
2620(define (yggdrasil-configuration-file config)
2621 (define (scm->yggdrasil-json x)
2622 (define key-value?
2623 dotted-list?)
2624 (define (param->camel str)
2625 (string-concatenate
2626 (map string-capitalize
2627 (string-split str (cut eqv? <> #\-)))))
2628 (cond
2629 ((key-value? x)
2630 (let ((k (car x))
2631 (v (cdr x)))
2632 (cons
2633 (if (symbol? k)
2634 (param->camel (symbol->string k))
2635 k)
2636 v)))
2637 ((list? x) (map scm->yggdrasil-json x))
2638 ((vector? x) (vector-map scm->yggdrasil-json x))
2639 (else x)))
2640 (computed-file
2641 "yggdrasil.conf"
2642 #~(call-with-output-file #$output
2643 (lambda (port)
2644 ;; it's HJSON, so comments are a-okay
2645 (display "# Generated by yggdrasil-service\n" port)
2646 (display #$(scm->json-string
2647 (scm->yggdrasil-json
2648 (yggdrasil-configuration-json-config config)))
2649 port)))))
2650
2651(define (yggdrasil-shepherd-service config)
2652 "Return a <shepherd-service> for yggdrasil with CONFIG."
2653 (define yggdrasil-command
2654 #~(append
2655 (list (string-append
2656 #$(yggdrasil-configuration-package config)
2657 "/bin/yggdrasil")
2658 "-useconffile"
2659 #$(yggdrasil-configuration-file config))
2660 (if #$(yggdrasil-configuration-autoconf? config)
2661 '("-autoconf")
2662 '())
2663 (let ((extraconf #$(yggdrasil-config-file config)))
2664 (if extraconf
2665 (list "-extraconffile" extraconf)
2666 '()))
2667 (list "-loglevel"
2668 #$(symbol->string (yggdrasil-configuration-log-level config))
2669 "-logto"
2670 #$(symbol->string (yggdrasil-configuration-log-to config)))))
2671 (list (shepherd-service
2672 (documentation "Connect to the Yggdrasil mesh network")
2673 (provision '(yggdrasil))
2674 (requirement '(networking))
2675 (start #~(make-forkexec-constructor
2676 #$yggdrasil-command
2677 #:log-file "/var/log/yggdrasil.log"
2678 #:group "yggdrasil"))
2679 (stop #~(make-kill-destructor)))))
2680
2681(define %yggdrasil-accounts
2682 (list (user-group (name "yggdrasil") (system? #t))))
2683
2684(define yggdrasil-service-type
2685 (service-type
2686 (name 'yggdrasil)
2687 (description
2688 "Connect to the Yggdrasil mesh network.
2689See @command{yggdrasil -genconf} for config options.")
2690 (extensions
2691 (list (service-extension shepherd-root-service-type
2692 yggdrasil-shepherd-service)
2693 (service-extension account-service-type
2694 (const %yggdrasil-accounts))
2695 (service-extension profile-service-type
2696 (compose list yggdrasil-configuration-package))))
2697 (default-value (yggdrasil-configuration))))
2698
2699
2700;;;
2701;;; IPFS
2702;;;
2703
2704(define-record-type* <ipfs-configuration>
2705 ipfs-configuration
2706 make-ipfs-configuration
2707 ipfs-configuration?
2708 (package ipfs-configuration-package
2709 (default kubo))
2710 (gateway ipfs-configuration-gateway
2711 (default "/ip4/127.0.0.1/tcp/8082"))
2712 (api ipfs-configuration-api
2713 (default "/ip4/127.0.0.1/tcp/5001")))
2714
2715(define %ipfs-home "/var/lib/ipfs")
2716
2717(define %ipfs-accounts
2718 (list (user-account
2719 (name "ipfs")
2720 (group "ipfs")
2721 (system? #t)
2722 (comment "IPFS daemon user")
2723 (home-directory "/var/lib/ipfs")
2724 (shell (file-append shadow "/sbin/nologin")))
2725 (user-group
2726 (name "ipfs")
2727 (system? #t))))
2728
2729(define (ipfs-binary config)
2730 (define command
2731 (file-append (ipfs-configuration-package config) "/bin/ipfs"))
2732
2733 (least-authority-wrapper
2734 command
2735 #:name "ipfs"
2736 #:mappings (list %ipfs-home-mapping)
2737 #:namespaces (delq 'net %namespaces)))
2738
2739(define %ipfs-home-mapping
2740 (file-system-mapping
2741 (source %ipfs-home)
2742 (target %ipfs-home)
2743 (writable? #t)))
2744
2745(define %ipfs-environment
2746 #~(list #$(string-append "HOME=" %ipfs-home)))
2747
2748(define (ipfs-shepherd-service config)
2749 "Return a <shepherd-service> for IPFS with CONFIG."
2750 (define ipfs-daemon-command
2751 #~(list #$(ipfs-binary config) "daemon"))
2752
2753 (list (shepherd-service
2754 (provision '(ipfs))
2755 ;; While IPFS is most useful when the machine is connected
2756 ;; to the network, only loopback is required for starting
2757 ;; the service.
2758 (requirement '(user-processes loopback))
2759 (documentation "Connect to the IPFS network")
2760 (start #~(make-forkexec-constructor
2761 #$ipfs-daemon-command
2762 #:log-file "/var/log/ipfs.log"
2763 #:user "ipfs" #:group "ipfs"
2764 #:environment-variables #$%ipfs-environment))
2765 (stop #~(make-kill-destructor)))))
2766
2767(define (%ipfs-activation config)
2768 "Return an activation gexp for IPFS with CONFIG"
2769 (define (exec-command . args)
2770 ;; Exec the given ifps command with the right authority.
2771 #~(let ((pid (primitive-fork)))
2772 (if (zero? pid)
2773 (dynamic-wind
2774 (const #t)
2775 (lambda ()
2776 ;; Run ipfs init and ipfs config from a container,
2777 ;; in case the IPFS daemon was compromised at some point
2778 ;; and ~/.ipfs is now a symlink to somewhere outside
2779 ;; %ipfs-home.
2780 (let ((pw (getpwnam "ipfs")))
2781 (setgroups '#())
2782 (setgid (passwd:gid pw))
2783 (setuid (passwd:uid pw))
2784 (environ #$%ipfs-environment)
2785 (execl #$(ipfs-binary config) #$@args)))
2786 (lambda ()
2787 (primitive-exit 127)))
2788 (waitpid pid))))
2789
2790 (define settings
2791 `(("Addresses.API" ,(ipfs-configuration-api config))
2792 ("Addresses.Gateway" ,(ipfs-configuration-gateway config))))
2793
2794 (define inner-gexp
2795 #~(begin
2796 (umask #o077)
2797 ;; Create $HOME/.ipfs structure
2798 #$(exec-command "ipfs" "init")
2799 ;; Apply settings
2800 #$@(map (match-lambda
2801 ((setting value)
2802 (exec-command "ipfs" "config" setting value)))
2803 settings)))
2804
2805 (define inner-script
2806 (program-file "ipfs-activation-inner" inner-gexp))
2807
2808 ;; The activation may happen from the initrd, which uses
2809 ;; a statically-linked guile, while the guix container
2810 ;; procedures require a working dynamic-link.
2811 #~(system* #$inner-script))
2812
2813(define ipfs-service-type
2814 (service-type
2815 (name 'ipfs)
2816 (extensions
2817 (list (service-extension account-service-type
2818 (const %ipfs-accounts))
2819 (service-extension activation-service-type
2820 %ipfs-activation)
2821 (service-extension shepherd-root-service-type
2822 ipfs-shepherd-service)))
2823 (default-value (ipfs-configuration))
2824 (description
2825 "Run @command{ipfs daemon}, the reference implementation
2826of the IPFS peer-to-peer storage network.")))
2827
2828
2829;;;
2830;;; Keepalived
2831;;;
2832
2833(define-record-type* <keepalived-configuration>
2834 keepalived-configuration make-keepalived-configuration
2835 keepalived-configuration?
2836 (keepalived keepalived-configuration-keepalived ;file-like
2837 (default keepalived))
2838 (config-file keepalived-configuration-config-file ;file-like
2839 (default #f))
2840 (shepherd-requirement keepalived-configuration-shepherd-requirement
2841 (default '(networking user-processes))))
2842
2843(define (keepalived-shepherd-service config)
2844 (match-record config <keepalived-configuration>
2845 (keepalived config-file shepherd-requirement)
2846 (list (shepherd-service
2847 (provision '(keepalived))
2848 (documentation "Run keepalived.")
2849 (requirement shepherd-requirement)
2850 (start #~(make-forkexec-constructor
2851 (list (string-append #$keepalived "/sbin/keepalived")
2852 "--dont-fork" "--log-console" "--log-detail"
2853 "--pid=/var/run/keepalived.pid"
2854 (string-append "--use-file=" #$config-file))
2855 #:pid-file "/var/run/keepalived.pid"
2856 #:log-file "/var/log/keepalived.log"))
2857 (respawn? #f)
2858 (stop #~(make-kill-destructor))))))
2859
2860(define keepalived-service-type
2861 (service-type (name 'keepalived)
2862 (extensions (list (service-extension shepherd-root-service-type
2863 keepalived-shepherd-service)))
2864 (description
2865 "Run @uref{https://www.keepalived.org/, Keepalived}
2866routing software.")))
2867
2868;;; networking.scm ends here