Commit | Line | Data |
---|---|---|
db4fdc04 | 1 | ;;; GNU Guix --- Functional package management for GNU |
e87f0591 | 2 | ;;; Copyright © 2013, 2014, 2015 Ludovic Courtès <ludo@gnu.org> |
b7d0c494 | 3 | ;;; Copyright © 2015 Mark H Weaver <mhw@netris.org> |
db4fdc04 LC |
4 | ;;; |
5 | ;;; This file is part of GNU Guix. | |
6 | ;;; | |
7 | ;;; GNU Guix is free software; you can redistribute it and/or modify it | |
8 | ;;; under the terms of the GNU General Public License as published by | |
9 | ;;; the Free Software Foundation; either version 3 of the License, or (at | |
10 | ;;; your option) any later version. | |
11 | ;;; | |
12 | ;;; GNU Guix is distributed in the hope that it will be useful, but | |
13 | ;;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | ;;; GNU General Public License for more details. | |
16 | ;;; | |
17 | ;;; You should have received a copy of the GNU General Public License | |
18 | ;;; along with GNU Guix. If not, see <http://www.gnu.org/licenses/>. | |
19 | ||
20 | (define-module (gnu services networking) | |
21 | #:use-module (gnu services) | |
0adfe95a LC |
22 | #:use-module (gnu services dmd) |
23 | #:use-module (gnu services dbus) | |
927097ef | 24 | #:use-module (gnu system shadow) |
6e828634 | 25 | #:use-module (gnu system pam) |
db4fdc04 LC |
26 | #:use-module (gnu packages admin) |
27 | #:use-module (gnu packages linux) | |
927097ef | 28 | #:use-module (gnu packages tor) |
4627a464 | 29 | #:use-module (gnu packages messaging) |
63854bcb | 30 | #:use-module (gnu packages ntp) |
b7d0c494 | 31 | #:use-module (gnu packages wicd) |
7234ad4f | 32 | #:use-module (gnu packages gnome) |
b5f4e686 | 33 | #:use-module (guix gexp) |
0adfe95a | 34 | #:use-module (guix records) |
63854bcb | 35 | #:use-module (srfi srfi-26) |
0adfe95a | 36 | #:use-module (ice-9 match) |
fa0c1d61 LC |
37 | #:export (%facebook-host-aliases |
38 | static-networking-service | |
a023cca8 | 39 | dhcp-client-service |
63854bcb LC |
40 | %ntp-servers |
41 | ntp-service | |
4627a464 | 42 | tor-service |
b7d0c494 | 43 | bitlbee-service |
7234ad4f SB |
44 | wicd-service |
45 | network-manager-service)) | |
db4fdc04 LC |
46 | |
47 | ;;; Commentary: | |
48 | ;;; | |
49 | ;;; Networking services. | |
50 | ;;; | |
51 | ;;; Code: | |
52 | ||
fa0c1d61 LC |
53 | (define %facebook-host-aliases |
54 | ;; This is the list of known Facebook hosts to be added to /etc/hosts if you | |
55 | ;; are to block it. | |
56 | "\ | |
57 | # Block Facebook IPv4. | |
58 | 127.0.0.1 www.facebook.com | |
59 | 127.0.0.1 facebook.com | |
60 | 127.0.0.1 login.facebook.com | |
61 | 127.0.0.1 www.login.facebook.com | |
62 | 127.0.0.1 fbcdn.net | |
63 | 127.0.0.1 www.fbcdn.net | |
64 | 127.0.0.1 fbcdn.com | |
65 | 127.0.0.1 www.fbcdn.com | |
66 | 127.0.0.1 static.ak.fbcdn.net | |
67 | 127.0.0.1 static.ak.connect.facebook.com | |
68 | 127.0.0.1 connect.facebook.net | |
69 | 127.0.0.1 www.connect.facebook.net | |
70 | 127.0.0.1 apps.facebook.com | |
71 | ||
72 | # Block Facebook IPv6. | |
73 | fe80::1%lo0 facebook.com | |
74 | fe80::1%lo0 login.facebook.com | |
75 | fe80::1%lo0 www.login.facebook.com | |
76 | fe80::1%lo0 fbcdn.net | |
77 | fe80::1%lo0 www.fbcdn.net | |
78 | fe80::1%lo0 fbcdn.com | |
79 | fe80::1%lo0 www.fbcdn.com | |
80 | fe80::1%lo0 static.ak.fbcdn.net | |
81 | fe80::1%lo0 static.ak.connect.facebook.com | |
82 | fe80::1%lo0 connect.facebook.net | |
83 | fe80::1%lo0 www.connect.facebook.net | |
84 | fe80::1%lo0 apps.facebook.com\n") | |
85 | ||
86 | ||
0adfe95a LC |
87 | (define-record-type* <static-networking> |
88 | static-networking make-static-networking | |
89 | static-networking? | |
90 | (interface static-networking-interface) | |
91 | (ip static-networking-ip) | |
92 | (gateway static-networking-gateway) | |
93 | (provision static-networking-provision) | |
94 | (name-servers static-networking-name-servers) | |
95 | (net-tools static-networking-net-tools)) | |
96 | ||
97 | (define static-networking-service-type | |
98 | (dmd-service-type | |
00184239 | 99 | 'static-networking |
0adfe95a LC |
100 | (match-lambda |
101 | (($ <static-networking> interface ip gateway provision | |
102 | name-servers net-tools) | |
103 | (let ((loopback? (memq 'loopback provision))) | |
104 | ||
105 | ;; TODO: Eventually replace 'route' with bindings for the appropriate | |
106 | ;; ioctls. | |
107 | (dmd-service | |
108 | ||
109 | ;; Unless we're providing the loopback interface, wait for udev to be up | |
110 | ;; and running so that INTERFACE is actually usable. | |
111 | (requirement (if loopback? '() '(udev))) | |
112 | ||
113 | (documentation | |
114 | "Bring up the networking interface using a static IP address.") | |
115 | (provision provision) | |
116 | (start #~(lambda _ | |
117 | ;; Return #t if successfully started. | |
118 | (let* ((addr (inet-pton AF_INET #$ip)) | |
119 | (sockaddr (make-socket-address AF_INET addr 0))) | |
120 | (configure-network-interface #$interface sockaddr | |
121 | (logior IFF_UP | |
122 | #$(if loopback? | |
123 | #~IFF_LOOPBACK | |
124 | 0)))) | |
125 | #$(if gateway | |
126 | #~(zero? (system* (string-append #$net-tools | |
127 | "/sbin/route") | |
128 | "add" "-net" "default" | |
129 | "gw" #$gateway)) | |
130 | #t) | |
131 | #$(if (pair? name-servers) | |
132 | #~(call-with-output-file "/etc/resolv.conf" | |
133 | (lambda (port) | |
134 | (display | |
135 | "# Generated by 'static-networking-service'.\n" | |
136 | port) | |
137 | (for-each (lambda (server) | |
138 | (format port "nameserver ~a~%" | |
139 | server)) | |
140 | '#$name-servers))) | |
141 | #t))) | |
142 | (stop #~(lambda _ | |
143 | ;; Return #f is successfully stopped. | |
144 | (let ((sock (socket AF_INET SOCK_STREAM 0))) | |
145 | (set-network-interface-flags sock #$interface 0) | |
146 | (close-port sock)) | |
147 | (not #$(if gateway | |
148 | #~(system* (string-append #$net-tools | |
149 | "/sbin/route") | |
150 | "del" "-net" "default") | |
151 | #t)))) | |
152 | (respawn? #f))))))) | |
153 | ||
db4fdc04 LC |
154 | (define* (static-networking-service interface ip |
155 | #:key | |
156 | gateway | |
4a3b3b07 | 157 | (provision '(networking)) |
db4fdc04 | 158 | (name-servers '()) |
db4fdc04 | 159 | (net-tools net-tools)) |
51da7ca0 LC |
160 | "Return a service that starts @var{interface} with address @var{ip}. If |
161 | @var{gateway} is true, it must be a string specifying the default network | |
162 | gateway." | |
0adfe95a LC |
163 | (service static-networking-service-type |
164 | (static-networking (interface interface) (ip ip) | |
165 | (gateway gateway) | |
166 | (provision provision) | |
167 | (name-servers name-servers) | |
168 | (net-tools net-tools)))) | |
169 | ||
170 | (define dhcp-client-service-type | |
171 | (dmd-service-type | |
00184239 | 172 | 'dhcp-client |
0adfe95a LC |
173 | (lambda (dhcp) |
174 | (define dhclient | |
175 | #~(string-append #$dhcp "/sbin/dhclient")) | |
176 | ||
177 | (define pid-file | |
178 | "/var/run/dhclient.pid") | |
179 | ||
180 | (dmd-service | |
181 | (documentation "Set up networking via DHCP.") | |
182 | (requirement '(user-processes udev)) | |
183 | ||
184 | ;; XXX: Running with '-nw' ("no wait") avoids blocking for a minute when | |
185 | ;; networking is unavailable, but also means that the interface is not up | |
186 | ;; yet when 'start' completes. To wait for the interface to be ready, one | |
187 | ;; should instead monitor udev events. | |
188 | (provision '(networking)) | |
189 | ||
190 | (start #~(lambda _ | |
191 | ;; When invoked without any arguments, 'dhclient' discovers all | |
192 | ;; non-loopback interfaces *that are up*. However, the relevant | |
193 | ;; interfaces are typically down at this point. Thus we perform | |
194 | ;; our own interface discovery here. | |
195 | (define valid? | |
196 | (negate loopback-network-interface?)) | |
197 | (define ifaces | |
198 | (filter valid? (all-network-interface-names))) | |
199 | ||
200 | ;; XXX: Make sure the interfaces are up so that 'dhclient' can | |
201 | ;; actually send/receive over them. | |
202 | (for-each set-network-interface-up ifaces) | |
203 | ||
204 | (false-if-exception (delete-file #$pid-file)) | |
205 | (let ((pid (fork+exec-command | |
206 | (cons* #$dhclient "-nw" | |
207 | "-pf" #$pid-file ifaces)))) | |
208 | (and (zero? (cdr (waitpid pid))) | |
209 | (let loop () | |
210 | (catch 'system-error | |
211 | (lambda () | |
212 | (call-with-input-file #$pid-file read)) | |
213 | (lambda args | |
214 | ;; 'dhclient' returned before PID-FILE was created, | |
215 | ;; so try again. | |
216 | (let ((errno (system-error-errno args))) | |
217 | (if (= ENOENT errno) | |
218 | (begin | |
219 | (sleep 1) | |
220 | (loop)) | |
221 | (apply throw args)))))))))) | |
222 | (stop #~(make-kill-destructor)))))) | |
db4fdc04 | 223 | |
a023cca8 LC |
224 | (define* (dhcp-client-service #:key (dhcp isc-dhcp)) |
225 | "Return a service that runs @var{dhcp}, a Dynamic Host Configuration | |
226 | Protocol (DHCP) client, on all the non-loopback network interfaces." | |
0adfe95a | 227 | (service dhcp-client-service-type dhcp)) |
a023cca8 | 228 | |
63854bcb LC |
229 | (define %ntp-servers |
230 | ;; Default set of NTP servers. | |
231 | '("0.pool.ntp.org" | |
232 | "1.pool.ntp.org" | |
233 | "2.pool.ntp.org")) | |
234 | ||
0adfe95a LC |
235 | \f |
236 | ;;; | |
237 | ;;; NTP. | |
238 | ;;; | |
239 | ||
240 | ;; TODO: Export. | |
241 | (define-record-type* <ntp-configuration> | |
242 | ntp-configuration make-ntp-configuration | |
243 | ntp-configuration? | |
244 | (ntp ntp-configuration-ntp | |
245 | (default ntp)) | |
246 | (servers ntp-configuration-servers)) | |
247 | ||
248 | (define ntp-dmd-service | |
249 | (match-lambda | |
250 | (($ <ntp-configuration> ntp servers) | |
251 | (let () | |
252 | ;; TODO: Add authentication support. | |
253 | (define config | |
254 | (string-append "driftfile /var/run/ntp.drift\n" | |
255 | (string-join (map (cut string-append "server " <>) | |
256 | servers) | |
257 | "\n") | |
258 | " | |
63854bcb LC |
259 | # Disable status queries as a workaround for CVE-2013-5211: |
260 | # <http://support.ntp.org/bin/view/Main/SecurityNotice#DRDoS_Amplification_Attack_using>. | |
261 | restrict default kod nomodify notrap nopeer noquery | |
262 | restrict -6 default kod nomodify notrap nopeer noquery | |
263 | ||
264 | # Yet, allow use of the local 'ntpq'. | |
265 | restrict 127.0.0.1 | |
266 | restrict -6 ::1\n")) | |
267 | ||
0adfe95a LC |
268 | (define ntpd.conf |
269 | (plain-file "ntpd.conf" config)) | |
270 | ||
271 | (list (dmd-service | |
272 | (provision '(ntpd)) | |
273 | (documentation "Run the Network Time Protocol (NTP) daemon.") | |
274 | (requirement '(user-processes networking)) | |
275 | (start #~(make-forkexec-constructor | |
276 | (list (string-append #$ntp "/bin/ntpd") "-n" | |
277 | "-c" #$ntpd.conf "-u" "ntpd"))) | |
278 | (stop #~(make-kill-destructor)))))))) | |
279 | ||
280 | (define %ntp-accounts | |
281 | (list (user-account | |
282 | (name "ntpd") | |
283 | (group "nogroup") | |
284 | (system? #t) | |
285 | (comment "NTP daemon user") | |
286 | (home-directory "/var/empty") | |
287 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | |
288 | ||
289 | (define ntp-service-type | |
290 | (service-type (name 'ntp) | |
291 | (extensions | |
292 | (list (service-extension dmd-root-service-type | |
293 | ntp-dmd-service) | |
294 | (service-extension account-service-type | |
295 | (const %ntp-accounts)))))) | |
296 | ||
297 | (define* (ntp-service #:key (ntp ntp) | |
298 | (servers %ntp-servers)) | |
299 | "Return a service that runs the daemon from @var{ntp}, the | |
300 | @uref{http://www.ntp.org, Network Time Protocol package}. The daemon will | |
301 | keep the system clock synchronized with that of @var{servers}." | |
302 | (service ntp-service-type | |
303 | (ntp-configuration (ntp ntp) (servers servers)))) | |
304 | ||
305 | \f | |
306 | ;;; | |
307 | ;;; Tor. | |
308 | ;;; | |
309 | ||
310 | (define %tor-accounts | |
311 | ;; User account and groups for Tor. | |
312 | (list (user-group (name "tor") (system? #t)) | |
313 | (user-account | |
314 | (name "tor") | |
315 | (group "tor") | |
316 | (system? #t) | |
317 | (comment "Tor daemon user") | |
318 | (home-directory "/var/empty") | |
319 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | |
320 | ||
375c6108 | 321 | (define (tor-dmd-service config) |
0adfe95a | 322 | "Return a <dmd-service> running TOR." |
375c6108 LC |
323 | (match config |
324 | ((tor config-file) | |
325 | (let ((torrc (computed-file "torrc" | |
326 | #~(begin | |
327 | (use-modules (guix build utils)) | |
328 | (call-with-output-file #$output | |
329 | (lambda (port) | |
330 | (display "\ | |
331 | User tor # automatically added\n" port) | |
332 | (call-with-input-file #$config-file | |
333 | (lambda (input) | |
334 | (dump-port input port))) | |
335 | #t))) | |
336 | #:modules '((guix build utils))))) | |
337 | (list (dmd-service | |
338 | (provision '(tor)) | |
0adfe95a | 339 | |
375c6108 LC |
340 | ;; Tor needs at least one network interface to be up, hence the |
341 | ;; dependency on 'loopback'. | |
342 | (requirement '(user-processes loopback)) | |
0adfe95a | 343 | |
375c6108 LC |
344 | (start #~(make-forkexec-constructor |
345 | (list (string-append #$tor "/bin/tor") "-f" #$torrc))) | |
346 | (stop #~(make-kill-destructor)) | |
347 | (documentation "Run the Tor anonymous network overlay."))))))) | |
0adfe95a LC |
348 | |
349 | (define tor-service-type | |
350 | (service-type (name 'tor) | |
351 | (extensions | |
352 | (list (service-extension dmd-root-service-type | |
353 | tor-dmd-service) | |
354 | (service-extension account-service-type | |
355 | (const %tor-accounts)))))) | |
63854bcb | 356 | |
375c6108 LC |
357 | (define* (tor-service #:optional |
358 | (config-file (plain-file "empty" "")) | |
359 | #:key (tor tor)) | |
360 | "Return a service to run the @uref{https://torproject.org, Tor} anonymous | |
361 | networking daemon. | |
927097ef | 362 | |
375c6108 LC |
363 | The daemon runs as the @code{tor} unprivileged user. It is passed |
364 | @var{config-file}, a file-like object, with an additional @code{User tor} | |
365 | line. Run @command{man tor} for information about the configuration file." | |
366 | (service tor-service-type (list tor config-file))) | |
0adfe95a LC |
367 | |
368 | \f | |
369 | ;;; | |
370 | ;;; BitlBee. | |
371 | ;;; | |
372 | ||
373 | (define-record-type* <bitlbee-configuration> | |
374 | bitlbee-configuration make-bitlbee-configuration | |
375 | bitlbee-configuration? | |
376 | (bitlbee bitlbee-configuration-bitlbee | |
377 | (default bitlbee)) | |
378 | (interface bitlbee-configuration-interface) | |
379 | (port bitlbee-configuration-port) | |
380 | (extra-settings bitlbee-configuration-extra-settings)) | |
381 | ||
382 | (define bitlbee-dmd-service | |
383 | (match-lambda | |
384 | (($ <bitlbee-configuration> bitlbee interface port extra-settings) | |
385 | (let ((conf (plain-file "bitlbee.conf" | |
386 | (string-append " | |
387 | [settings] | |
388 | User = bitlbee | |
389 | ConfigDir = /var/lib/bitlbee | |
390 | DaemonInterface = " interface " | |
391 | DaemonPort = " (number->string port) " | |
392 | " extra-settings)))) | |
393 | ||
394 | (list (dmd-service | |
395 | (provision '(bitlbee)) | |
396 | (requirement '(user-processes loopback)) | |
397 | (start #~(make-forkexec-constructor | |
398 | (list (string-append #$bitlbee "/sbin/bitlbee") | |
399 | "-n" "-F" "-u" "bitlbee" "-c" #$conf))) | |
400 | (stop #~(make-kill-destructor)))))))) | |
401 | ||
402 | (define %bitlbee-accounts | |
403 | ;; User group and account to run BitlBee. | |
404 | (list (user-group (name "bitlbee") (system? #t)) | |
405 | (user-account | |
406 | (name "bitlbee") | |
407 | (group "bitlbee") | |
408 | (system? #t) | |
409 | (comment "BitlBee daemon user") | |
410 | (home-directory "/var/empty") | |
411 | (shell #~(string-append #$shadow "/sbin/nologin"))))) | |
412 | ||
413 | (define %bitlbee-activation | |
414 | ;; Activation gexp for BitlBee. | |
415 | #~(begin | |
416 | (use-modules (guix build utils)) | |
417 | ||
418 | ;; This directory is used to store OTR data. | |
419 | (mkdir-p "/var/lib/bitlbee") | |
420 | (let ((user (getpwnam "bitlbee"))) | |
421 | (chown "/var/lib/bitlbee" | |
422 | (passwd:uid user) (passwd:gid user))))) | |
423 | ||
424 | (define bitlbee-service-type | |
425 | (service-type (name 'bitlbee) | |
426 | (extensions | |
427 | (list (service-extension dmd-root-service-type | |
428 | bitlbee-dmd-service) | |
429 | (service-extension account-service-type | |
430 | (const %bitlbee-accounts)) | |
431 | (service-extension activation-service-type | |
432 | (const %bitlbee-activation)))))) | |
927097ef | 433 | |
4627a464 LC |
434 | (define* (bitlbee-service #:key (bitlbee bitlbee) |
435 | (interface "127.0.0.1") (port 6667) | |
436 | (extra-settings "")) | |
437 | "Return a service that runs @url{http://bitlbee.org,BitlBee}, a daemon that | |
438 | acts as a gateway between IRC and chat networks. | |
439 | ||
440 | The daemon will listen to the interface corresponding to the IP address | |
441 | specified in @var{interface}, on @var{port}. @code{127.0.0.1} means that only | |
442 | local clients can connect, whereas @code{0.0.0.0} means that connections can | |
443 | come from any networking interface. | |
444 | ||
445 | In addition, @var{extra-settings} specifies a string to append to the | |
446 | configuration file." | |
0adfe95a LC |
447 | (service bitlbee-service-type |
448 | (bitlbee-configuration | |
449 | (bitlbee bitlbee) | |
450 | (interface interface) (port port) | |
451 | (extra-settings extra-settings)))) | |
452 | ||
453 | \f | |
454 | ;;; | |
455 | ;;; Wicd. | |
456 | ;;; | |
457 | ||
458 | (define %wicd-activation | |
459 | ;; Activation gexp for Wicd. | |
460 | #~(begin | |
461 | (use-modules (guix build utils)) | |
462 | ||
463 | (mkdir-p "/etc/wicd") | |
464 | (let ((file-name "/etc/wicd/dhclient.conf.template.default")) | |
465 | (unless (file-exists? file-name) | |
466 | (copy-file (string-append #$wicd file-name) | |
467 | file-name))))) | |
468 | ||
469 | (define (wicd-dmd-service wicd) | |
470 | "Return a dmd service for WICD." | |
471 | (list (dmd-service | |
472 | (documentation "Run the Wicd network manager.") | |
473 | (provision '(networking)) | |
474 | (requirement '(user-processes dbus-system loopback)) | |
475 | (start #~(make-forkexec-constructor | |
476 | (list (string-append #$wicd "/sbin/wicd") | |
477 | "--no-daemon"))) | |
478 | (stop #~(make-kill-destructor))))) | |
479 | ||
480 | (define wicd-service-type | |
481 | (service-type (name 'wicd) | |
482 | (extensions | |
483 | (list (service-extension dmd-root-service-type | |
484 | wicd-dmd-service) | |
485 | (service-extension dbus-root-service-type | |
486 | list) | |
487 | (service-extension activation-service-type | |
87f40011 LC |
488 | (const %wicd-activation)) |
489 | ||
490 | ;; Add Wicd to the global profile. | |
491 | (service-extension profile-service-type list))))) | |
4627a464 | 492 | |
b7d0c494 MW |
493 | (define* (wicd-service #:key (wicd wicd)) |
494 | "Return a service that runs @url{https://launchpad.net/wicd,Wicd}, a network | |
87f40011 LC |
495 | management daemon that aims to simplify wired and wireless networking. |
496 | ||
497 | This service adds the @var{wicd} package to the global profile, providing | |
498 | several commands to interact with the daemon and configure networking: | |
499 | @command{wicd-client}, a graphical user interface, and the @command{wicd-cli} | |
500 | and @command{wicd-curses} user interfaces." | |
0adfe95a | 501 | (service wicd-service-type wicd)) |
b7d0c494 | 502 | |
7234ad4f SB |
503 | \f |
504 | ;;; | |
505 | ;;; NetworkManager | |
506 | ;;; | |
507 | ||
508 | (define %network-manager-activation | |
509 | ;; Activation gexp for NetworkManager. | |
510 | #~(begin | |
511 | (use-modules (guix build utils)) | |
512 | (mkdir-p "/etc/NetworkManager/system-connections"))) | |
513 | ||
514 | (define (network-manager-dmd-service network-manager) | |
515 | "Return a dmd service for NETWORK-MANAGER." | |
516 | (list (dmd-service | |
517 | (documentation "Run the NetworkManager.") | |
518 | (provision '(networking)) | |
519 | (requirement '(user-processes dbus-system loopback)) | |
520 | (start #~(make-forkexec-constructor | |
521 | (list (string-append #$network-manager | |
522 | "/sbin/NetworkManager") | |
523 | "--no-daemon"))) | |
524 | (stop #~(make-kill-destructor))))) | |
525 | ||
526 | (define network-manager-service-type | |
527 | (service-type (name 'network-manager) | |
528 | (extensions | |
529 | (list (service-extension dmd-root-service-type | |
530 | network-manager-dmd-service) | |
531 | (service-extension dbus-root-service-type list) | |
532 | (service-extension activation-service-type | |
533 | (const %network-manager-activation)) | |
534 | ;; Add network-manager to the system profile. | |
535 | (service-extension profile-service-type list))))) | |
536 | ||
537 | (define* (network-manager-service #:key (network-manager network-manager)) | |
538 | "Return a service that runs NetworkManager, a network connection manager | |
539 | that attempting to keep active network connectivity when available." | |
540 | (service network-manager-service-type network-manager)) | |
541 | ||
db4fdc04 | 542 | ;;; networking.scm ends here |