diff options
| -rw-r--r-- | doc/guix.texi | 89 | ||||
| -rw-r--r-- | gnu/services/networking.scm | 161 | ||||
| -rw-r--r-- | gnu/tests/networking.scm | 106 |
3 files changed, 356 insertions, 0 deletions
diff --git a/doc/guix.texi b/doc/guix.texi index 6844470ce2f..6529865c090 100644 --- a/doc/guix.texi +++ b/doc/guix.texi | |||
| @@ -21594,6 +21594,95 @@ which provides the @code{networking} Shepherd service. | |||
| 21594 | @end table | 21594 | @end table |
| 21595 | @end deftp | 21595 | @end deftp |
| 21596 | 21596 | ||
| 21597 | @cindex DHCPCD, networking service | ||
| 21598 | |||
| 21599 | @defvar dhcpcd-service-type | ||
| 21600 | This the type for a service running @command{dhcpcd}, a @acronym{DHCP, | ||
| 21601 | Dynamic Host Configuration Protocol} client that can be used as a | ||
| 21602 | replacement for the historical ISC client supported by | ||
| 21603 | @code{dhcp-client-service-type}. | ||
| 21604 | |||
| 21605 | Its value must be a @code{dhcpcd-configuration} record, as described | ||
| 21606 | below. As an example, consider the following setup which runs | ||
| 21607 | @command{dhcpcd} with a local @acronym{DNS, Domain Name System} | ||
| 21608 | resolver: | ||
| 21609 | |||
| 21610 | @lisp | ||
| 21611 | (service dhcpcd-service-type | ||
| 21612 | (dhcpcd-configuration | ||
| 21613 | (option '("rapid_commit" "interface_mtu")) | ||
| 21614 | (no-option '("nd_rdnss" | ||
| 21615 | "dhcp6_name_servers" | ||
| 21616 | "domain_name_servers" | ||
| 21617 | "domain_name" | ||
| 21618 | "domain_search")) | ||
| 21619 | (static '("domain_name_servers=127.0.0.1")) | ||
| 21620 | (no-hook '("hostname"))))) | ||
| 21621 | @end lisp | ||
| 21622 | @end defvar | ||
| 21623 | |||
| 21624 | @deftp {Data Type} dhcpcd-configuration | ||
| 21625 | Available @code{dhcpcd-configuration} fields are: | ||
| 21626 | |||
| 21627 | @table @asis | ||
| 21628 | @item @code{interfaces} (default: @code{()}) (type: list) | ||
| 21629 | List of networking interfaces---e.g., @code{"eth0"}---to start a DHCP | ||
| 21630 | client for. If no interface is specified (i.e., the list is empty) then | ||
| 21631 | @command{dhcpcd} discovers available Ethernet interfaces, that can be | ||
| 21632 | configured, automatically. | ||
| 21633 | |||
| 21634 | @item @code{command-arguments} (default: @code{("-q" "-q")}) (type: list) | ||
| 21635 | List of additional command-line options. | ||
| 21636 | |||
| 21637 | @item @code{host-name} (default: @code{""}) (type: maybe-string) | ||
| 21638 | Host name to send via DHCP, defaults to the current system host name. | ||
| 21639 | |||
| 21640 | @item @code{duid} (default: @code{""}) (type: maybe-string) | ||
| 21641 | DHCPv4 clients require a unique client identifier, this option uses the | ||
| 21642 | DHCPv6 Unique Identifier as a DHCPv4 client identifier as well. For | ||
| 21643 | more information, refer to @uref{https://www.rfc-editor.org/rfc/rfc4361, RFC 4361} | ||
| 21644 | and @code{dhcpcd.conf(5)}. | ||
| 21645 | |||
| 21646 | @item @code{persistent?} (default: @code{#t}) (type: boolean) | ||
| 21647 | When true, automatically de-configure the interface when @command{dhcpcd} | ||
| 21648 | exits. | ||
| 21649 | |||
| 21650 | @item @code{option} (default: @code{("rapid_commit" "domain_name_servers" "domain_name" "domain_search" "host_name" "classless_static_routes" "interface_mtu")}) (type: list-of-strings) | ||
| 21651 | List of options to request from the server. | ||
| 21652 | |||
| 21653 | @item @code{require} (default: @code{("dhcp_server_identifier")}) (type: list-of-strings) | ||
| 21654 | List of options to require in responses. | ||
| 21655 | |||
| 21656 | @item @code{slaac} (default: @code{"private"}) (type: maybe-string) | ||
| 21657 | Interface identifier used for SLAAC generated IPv6 addresses. | ||
| 21658 | |||
| 21659 | @item @code{no-option} (default: @code{()}) (type: list-of-strings) | ||
| 21660 | List of options to remove from the message before it's processed. | ||
| 21661 | |||
| 21662 | @item @code{no-hook} (default: @code{()}) (type: list-of-strings) | ||
| 21663 | List of hook script which should not be invoked. | ||
| 21664 | |||
| 21665 | @item @code{static} (default: @code{()}) (type: list-of-strings) | ||
| 21666 | DHCP client can request different options from a DHCP server, through | ||
| 21667 | @code{static} it is possible to configure static values for selected | ||
| 21668 | options. For example, @code{"domain_name_servers=127.0.0.1"}. | ||
| 21669 | |||
| 21670 | @item @code{vendor-class-id} (type: maybe-string) | ||
| 21671 | Set the DHCP Vendor Class (e.g., @code{MSFT}). For more information, | ||
| 21672 | refer to @uref{https://www.rfc-editor.org/rfc/rfc2132#section-9.13,RFC | ||
| 21673 | 2132}. | ||
| 21674 | |||
| 21675 | @item @code{client-id} (type: maybe-string) | ||
| 21676 | Use the interface hardware address or the given string as a client | ||
| 21677 | identifier, this is matually exclusive with the @code{duid} option. | ||
| 21678 | |||
| 21679 | @item @code{extra-content} (type: maybe-string) | ||
| 21680 | Extra content to append to the configuration as-is. | ||
| 21681 | |||
| 21682 | @end table | ||
| 21683 | @end deftp | ||
| 21684 | |||
| 21685 | |||
| 21597 | @cindex NetworkManager | 21686 | @cindex NetworkManager |
| 21598 | 21687 | ||
| 21599 | @defvar network-manager-service-type | 21688 | @defvar network-manager-service-type |
diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm index 53840c27642..85ad5287f26 100644 --- a/gnu/services/networking.scm +++ b/gnu/services/networking.scm | |||
| @@ -109,6 +109,24 @@ | |||
| 109 | dhcpd-configuration-pid-file | 109 | dhcpd-configuration-pid-file |
| 110 | dhcpd-configuration-interfaces | 110 | dhcpd-configuration-interfaces |
| 111 | 111 | ||
| 112 | dhcpcd-service-type | ||
| 113 | dhcpcd-configuration | ||
| 114 | dhcpcd-configuration? | ||
| 115 | dhcpcd-configuration-interfaces | ||
| 116 | dhcpcd-configuration-command-arguments | ||
| 117 | dhcpcd-configuration-host-name | ||
| 118 | dhcpcd-configuration-duid | ||
| 119 | dhcpcd-configuration-persistent? | ||
| 120 | dhcpcd-configuration-option | ||
| 121 | dhcpcd-configuration-require | ||
| 122 | dhcpcd-configuration-slaac | ||
| 123 | dhcpcd-configuration-no-option | ||
| 124 | dhcpcd-configuration-no-hook | ||
| 125 | dhcpcd-configuration-static | ||
| 126 | dhcpcd-configuration-vendor-class-id | ||
| 127 | dhcpcd-configuration-client-id | ||
| 128 | dhcpcd-configuration-extra-content | ||
| 129 | |||
| 112 | ntp-configuration | 130 | ntp-configuration |
| 113 | ntp-configuration? | 131 | ntp-configuration? |
| 114 | ntp-configuration-ntp | 132 | ntp-configuration-ntp |
| @@ -493,6 +511,149 @@ Protocol (DHCP) client, on all the non-loopback network interfaces."))) | |||
| 493 | daemon is responsible for allocating IP addresses to its client."))) | 511 | daemon is responsible for allocating IP addresses to its client."))) |
| 494 | 512 | ||
| 495 | 513 | ||
| 514 | ;; | ||
| 515 | ;; DHCPCD. | ||
| 516 | ;; | ||
| 517 | |||
| 518 | (define (serialize-field-name field-name) | ||
| 519 | (let ((str (symbol->string field-name))) | ||
| 520 | (string-replace-substring | ||
| 521 | (if (string-suffix? "?" str) | ||
| 522 | (string-drop-right str 1) | ||
| 523 | str) | ||
| 524 | "-" ""))) | ||
| 525 | |||
| 526 | (define (dhcpcd-serialize-string field-name value) | ||
| 527 | (if (equal? field-name 'extra-content) | ||
| 528 | #~(string-append #$value "\n") | ||
| 529 | #~(format #f "~a ~a~%" #$(serialize-field-name field-name) #$value))) | ||
| 530 | |||
| 531 | (define (dhcpcd-serialize-boolean field-name value) | ||
| 532 | (if value | ||
| 533 | #~(format #f "~a~%" #$(serialize-field-name field-name)) | ||
| 534 | "")) | ||
| 535 | |||
| 536 | (define (dhcpcd-serialize-list-of-strings field-name value) | ||
| 537 | #~(string-append #$@(map (cut dhcpcd-serialize-string field-name <>) value))) | ||
| 538 | |||
| 539 | ;; Some fields (e.g. host-name) can be specified with an empty string argument. | ||
| 540 | ;; Therefore, we need a maybe type to differentiate disabled/empty-string. | ||
| 541 | (define-maybe string (prefix dhcpcd-)) | ||
| 542 | |||
| 543 | (define-configuration dhcpcd-configuration | ||
| 544 | (interfaces | ||
| 545 | (list '()) | ||
| 546 | "List of networking interfaces---e.g., @code{\"eth0\"}---to start a DHCP client | ||
| 547 | for. If no interface is specified (i.e., the list is empty) then @command{dhcpcd} | ||
| 548 | discovers available Ethernet interfaces, that can be configured, automatically." | ||
| 549 | empty-serializer) | ||
| 550 | (command-arguments | ||
| 551 | (list '("-q" "-q")) | ||
| 552 | "List of additional command-line options." | ||
| 553 | empty-serializer) | ||
| 554 | |||
| 555 | ;; The following defaults replicate the default dhcpcd configuration file. | ||
| 556 | ;; | ||
| 557 | ;; See https://github.com/NetworkConfiguration/dhcpcd/tree/v10.0.10#configuration | ||
| 558 | (host-name | ||
| 559 | (maybe-string "") | ||
| 560 | "Host name to send via DHCP, defaults to the current system host name.") | ||
| 561 | (duid | ||
| 562 | (maybe-string "") | ||
| 563 | "DHCPv4 clients require a unique client identifier, this option uses the DHCPv6 | ||
| 564 | Unique Identifier as a DHCPv4 client identifier as well. For more information, refer | ||
| 565 | to @uref{https://www.rfc-editor.org/rfc/rfc4361, RFC 4361} and @code{dhcpcd.conf(5)}.") | ||
| 566 | (persistent? | ||
| 567 | (boolean #t) | ||
| 568 | "When true, automatically de-configure the interface when @command{dhcpcd} exits.") | ||
| 569 | (option | ||
| 570 | (list-of-strings | ||
| 571 | '("rapid_commit" | ||
| 572 | "domain_name_servers" | ||
| 573 | "domain_name" | ||
| 574 | "domain_search" | ||
| 575 | "host_name" | ||
| 576 | "classless_static_routes" | ||
| 577 | "interface_mtu")) | ||
| 578 | "List of options to request from the server.") | ||
| 579 | (require | ||
| 580 | (list-of-strings '("dhcp_server_identifier")) | ||
| 581 | "List of options to require in responses.") | ||
| 582 | (slaac | ||
| 583 | (maybe-string "private") | ||
| 584 | "Interface identifier used for SLAAC generated IPv6 addresses.") | ||
| 585 | |||
| 586 | ;; Common options not set in the default configuration file. | ||
| 587 | (no-option | ||
| 588 | (list-of-strings '()) | ||
| 589 | "List of options to remove from the message before it's processed.") | ||
| 590 | (no-hook | ||
| 591 | (list-of-strings '()) | ||
| 592 | "List of hook script which should not be invoked.") | ||
| 593 | (static | ||
| 594 | (list-of-strings '()) | ||
| 595 | "DHCP client can request different options from a DHCP server, through | ||
| 596 | @code{static} it is possible to configure static values for selected options. For | ||
| 597 | example, @code{\"domain_name_servers=127.0.0.1\"}.") | ||
| 598 | (vendor-class-id | ||
| 599 | maybe-string | ||
| 600 | "Set the DHCP Vendor Class (e.g., @code{MSFT}). For more information, refer | ||
| 601 | to @uref{https://www.rfc-editor.org/rfc/rfc2132#section-9.13,RFC 2132}.") | ||
| 602 | (client-id | ||
| 603 | maybe-string | ||
| 604 | "Use the interface hardware address or the given string as a client identifier, | ||
| 605 | this is matually exclusive with the @code{duid} option.") | ||
| 606 | |||
| 607 | ;; Escape hatch for the generated configuration file. | ||
| 608 | (extra-content | ||
| 609 | maybe-string | ||
| 610 | "Extra content to append to the configuration as-is.") | ||
| 611 | |||
| 612 | (prefix dhcpcd-)) | ||
| 613 | |||
| 614 | (define (dhcpcd-config-file config) | ||
| 615 | (mixed-text-file "dhcpcd.conf" | ||
| 616 | (serialize-configuration | ||
| 617 | config | ||
| 618 | dhcpcd-configuration-fields))) | ||
| 619 | |||
| 620 | (define dhcpcd-account-service | ||
| 621 | (list (user-group (name "dhcpcd") (system? #t)) | ||
| 622 | (user-account | ||
| 623 | (name "dhcpcd") | ||
| 624 | (group "dhcpcd") | ||
| 625 | (system? #t) | ||
| 626 | (comment "dhcpcd daemon user") | ||
| 627 | (home-directory "/var/empty") | ||
| 628 | (shell (file-append shadow "/sbin/nologin"))))) | ||
| 629 | |||
| 630 | (define (dhcpcd-shepherd-service config) | ||
| 631 | (let* ((config-file (dhcpcd-config-file config)) | ||
| 632 | (command-args (dhcpcd-configuration-command-arguments config)) | ||
| 633 | (ifaces (dhcpcd-configuration-interfaces config))) | ||
| 634 | (list (shepherd-service | ||
| 635 | (documentation "dhcpcd daemon.") | ||
| 636 | (provision '(networking)) | ||
| 637 | (requirement '(user-processes udev)) | ||
| 638 | (actions (list (shepherd-configuration-action config-file))) | ||
| 639 | (start | ||
| 640 | #~(make-forkexec-constructor | ||
| 641 | (list (string-append #$dhcpcd "/sbin/dhcpcd") | ||
| 642 | #$@command-args "-B" "-f" #$config-file #$@ifaces))) | ||
| 643 | (stop #~(make-kill-destructor)))))) | ||
| 644 | |||
| 645 | (define dhcpcd-service-type | ||
| 646 | (service-type (name 'dhcpcd) | ||
| 647 | (description "Run the dhcpcd daemon.") | ||
| 648 | (extensions | ||
| 649 | (list (service-extension account-service-type | ||
| 650 | (const dhcpcd-account-service)) | ||
| 651 | (service-extension shepherd-root-service-type | ||
| 652 | dhcpcd-shepherd-service))) | ||
| 653 | (compose concatenate) | ||
| 654 | (default-value (dhcpcd-configuration)))) | ||
| 655 | |||
| 656 | |||
| 496 | ;;; | 657 | ;;; |
| 497 | ;;; NTP. | 658 | ;;; NTP. |
| 498 | ;;; | 659 | ;;; |
diff --git a/gnu/tests/networking.scm b/gnu/tests/networking.scm index e7c02b9e009..7d54ebba50e 100644 --- a/gnu/tests/networking.scm +++ b/gnu/tests/networking.scm | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | #:use-module (guix store) | 32 | #:use-module (guix store) |
| 33 | #:use-module (guix monads) | 33 | #:use-module (guix monads) |
| 34 | #:use-module (guix modules) | 34 | #:use-module (guix modules) |
| 35 | #:use-module (gnu packages admin) | ||
| 35 | #:use-module (gnu packages bash) | 36 | #:use-module (gnu packages bash) |
| 36 | #:use-module (gnu packages linux) | 37 | #:use-module (gnu packages linux) |
| 37 | #:use-module (gnu packages networking) | 38 | #:use-module (gnu packages networking) |
| @@ -44,6 +45,7 @@ | |||
| 44 | %test-inetd | 45 | %test-inetd |
| 45 | %test-openvswitch | 46 | %test-openvswitch |
| 46 | %test-dhcpd | 47 | %test-dhcpd |
| 48 | %test-dhcpcd | ||
| 47 | %test-tor | 49 | %test-tor |
| 48 | %test-iptables | 50 | %test-iptables |
| 49 | %test-ipfs)) | 51 | %test-ipfs)) |
| @@ -675,6 +677,110 @@ subnet 192.168.1.0 netmask 255.255.255.0 { | |||
| 675 | 677 | ||
| 676 | 678 | ||
| 677 | ;;; | 679 | ;;; |
| 680 | ;;; DHCPCD Daemon | ||
| 681 | ;;; | ||
| 682 | |||
| 683 | (define %dhcpcd-os | ||
| 684 | (let ((base-os | ||
| 685 | (simple-operating-system | ||
| 686 | (service dhcpcd-service-type | ||
| 687 | (dhcpcd-configuration | ||
| 688 | (command-arguments '("--debug" "--logfile" "/dev/console")) | ||
| 689 | (interfaces '("ens3"))))))) | ||
| 690 | (operating-system | ||
| 691 | (inherit base-os) | ||
| 692 | (packages | ||
| 693 | (append (list dhcpcd iproute) | ||
| 694 | (operating-system-packages base-os)))))) | ||
| 695 | |||
| 696 | (define (run-dhcpcd-test) | ||
| 697 | "Run tests in %dhcpcd-os with a running dhcpcd daemon on localhost." | ||
| 698 | (define os | ||
| 699 | (marionette-operating-system | ||
| 700 | %dhcpcd-os | ||
| 701 | #:imported-modules '((gnu services herd)))) | ||
| 702 | |||
| 703 | (define vm | ||
| 704 | (virtual-machine os)) | ||
| 705 | |||
| 706 | (define test | ||
| 707 | (with-imported-modules '((gnu build marionette)) | ||
| 708 | #~(begin | ||
| 709 | (use-modules (srfi srfi-64) | ||
| 710 | (gnu build marionette)) | ||
| 711 | (define marionette | ||
| 712 | (make-marionette (list #$vm))) | ||
| 713 | |||
| 714 | (define (wait-for-lease) | ||
| 715 | (marionette-eval | ||
| 716 | '(begin | ||
| 717 | (use-modules (ice-9 popen) (ice-9 rdelim)) | ||
| 718 | |||
| 719 | (let loop ((i 15)) | ||
| 720 | (if (> i 0) | ||
| 721 | (let* ((port (open-input-pipe "dhcpcd --dumplease ens3")) | ||
| 722 | (output (read-string port))) | ||
| 723 | (close-port port) | ||
| 724 | (unless (string-contains output "reason=BOUND") | ||
| 725 | (sleep 1) | ||
| 726 | (loop (- i 1)))) | ||
| 727 | (error "failed to obtain a DHCP lease")))) | ||
| 728 | marionette)) | ||
| 729 | |||
| 730 | (test-runner-current (system-test-runner #$output)) | ||
| 731 | (test-begin "dhcpcd") | ||
| 732 | |||
| 733 | (test-assert "service is running" | ||
| 734 | (marionette-eval | ||
| 735 | '(begin | ||
| 736 | (use-modules (gnu services herd)) | ||
| 737 | |||
| 738 | ;; Make sure the 'dhcpcd' command is found. | ||
| 739 | (setenv "PATH" "/run/current-system/profile/sbin") | ||
| 740 | |||
| 741 | (wait-for-service 'networking)) | ||
| 742 | marionette)) | ||
| 743 | |||
| 744 | (test-assert "IPC socket exists" | ||
| 745 | (marionette-eval | ||
| 746 | '(file-exists? "/var/run/dhcpcd/ens3.sock") | ||
| 747 | marionette)) | ||
| 748 | |||
| 749 | (test-equal "IPC is functional" | ||
| 750 | 0 | ||
| 751 | (marionette-eval | ||
| 752 | '(status:exit-val | ||
| 753 | (system* "dhcpcd" "--dumplease" "ens3")) | ||
| 754 | marionette)) | ||
| 755 | |||
| 756 | (test-equal "aquires IPv4 address via DHCP" | ||
| 757 | 1 | ||
| 758 | (and | ||
| 759 | (wait-for-lease) | ||
| 760 | (marionette-eval | ||
| 761 | '(begin | ||
| 762 | (use-modules (ice-9 popen) (ice-9 rdelim)) | ||
| 763 | |||
| 764 | (let* ((port (open-input-pipe "ip -4 address show dev ens3")) | ||
| 765 | (lines (string-split (read-string port) #\newline))) | ||
| 766 | (close-port port) | ||
| 767 | (length | ||
| 768 | (filter (lambda (line) | ||
| 769 | (string-contains line "scope global dynamic")) | ||
| 770 | lines)))) | ||
| 771 | marionette))) | ||
| 772 | |||
| 773 | (test-end)))) | ||
| 774 | (gexp->derivation "dhcpcd-test" test)) | ||
| 775 | |||
| 776 | (define %test-dhcpcd | ||
| 777 | (system-test | ||
| 778 | (name "dhcpcd") | ||
| 779 | (description "Test that the dhcpcd obtains IP DHCP leases.") | ||
| 780 | (value (run-dhcpcd-test)))) | ||
| 781 | |||
| 782 | |||
| 783 | ;;; | ||
| 678 | ;;; Services related to Tor | 784 | ;;; Services related to Tor |
| 679 | ;;; | 785 | ;;; |
| 680 | 786 | ||
