From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mp10.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by ms5.migadu.com with LMTPS id CBN+DMgdDWMb2AAAbAwnHQ (envelope-from ) for ; Mon, 29 Aug 2022 22:12:56 +0200 Received: from aspmx1.migadu.com ([2001:41d0:8:6d80::]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)) by mp10.migadu.com with LMTPS id uJugC8gdDWPFbgEAG6o9tA (envelope-from ) for ; Mon, 29 Aug 2022 22:12:56 +0200 Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by aspmx1.migadu.com (Postfix) with ESMTPS id A738927333 for ; Mon, 29 Aug 2022 22:12:55 +0200 (CEST) Received: from localhost ([::1]:33408 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1oSl7u-0002z4-HW for larch@yhetil.org; Mon, 29 Aug 2022 16:12:54 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:57880) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oSl7M-0002yt-Mz for help-guix@gnu.org; Mon, 29 Aug 2022 16:12:20 -0400 Received: from mout02.posteo.de ([185.67.36.66]:48419) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1oSl7I-00062v-PH for help-guix@gnu.org; Mon, 29 Aug 2022 16:12:20 -0400 Received: from submission (posteo.de [185.67.36.169]) by mout02.posteo.de (Postfix) with ESMTPS id 7FDF1240105 for ; Mon, 29 Aug 2022 22:12:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=posteo.net; s=2017; t=1661803931; bh=ZrrAA6uMrOLMuk+C+SIvnn9/VnFJQuxZewA0TSeo2T4=; h=Date:From:To:Cc:Subject:From; b=PfTO36G/dy91Rw4/0+XbtqPEZEwrxG2Ihk7id/VKgKhXOW+3LFwmVQ6c4EEpzVsjg 3B7CaIHfCT7sORL6Q5b2V9AEy6p8X5HYJKvYjEqiP9N9Uh+7JdfVOlEGnE07tDvcsf z89zzAIm6/pfgccjOXMxzVMudHllCZGOxXvBwhkerkl+IYXzQuDSzuuAGYYWWCaGPs 71XMINuuQIwiksFO39+TeI6YfDhAe/m0Fb60vlmu0R9RQPoON1H7nejYq2mUxoPp6Q DJdZpn/lXase4TEwIMrJGFXy3MfFzsojED4vEwqZ1D+xssa5mkwlxB5rITcnhbnUNl MXzsBFBJhG10A== Received: from customer (localhost [127.0.0.1]) by submission (posteo.de) with ESMTPSA id 4MGhRt3x9Qz6tmG; Mon, 29 Aug 2022 22:12:10 +0200 (CEST) Date: Mon, 29 Aug 2022 20:12:08 +0000 From: Niklas Schmidt To: Peter Polidoro Cc: help-guix@gnu.org Subject: Re: Guix Network Router? Message-ID: <20220829201208.bibzb4254v3e2bh7@posteo.de> References: <868rndd3xx.fsf@polidoro.io> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8; format=flowed Content-Disposition: inline In-Reply-To: <868rndd3xx.fsf@polidoro.io> Received-SPF: pass client-ip=185.67.36.66; envelope-from=snlabs@posteo.net; helo=mout02.posteo.de X-Spam_score_int: -43 X-Spam_score: -4.4 X-Spam_bar: ---- X-Spam_report: (-4.4 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: help-guix@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-guix-bounces+larch=yhetil.org@gnu.org Sender: "Help-Guix" X-Migadu-Flow: FLOW_IN X-Migadu-To: larch@yhetil.org X-Migadu-Country: US ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=yhetil.org; s=key1; t=1661803976; h=from:from:sender:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type:in-reply-to:in-reply-to: references:references:list-id:list-help:list-unsubscribe: list-subscribe:list-post:dkim-signature; bh=MWOC+eqKLMY7V6PbN/r0HyUNrExJjgiLI01U1ZSdSDU=; b=auHDxs/sOtj42fLQK0hpv8wpi8773HXIlkLjC6WzEdClz4WzUY5YhigFfzPKILZCUnufY0 pcBvlqCXrOvVgrMgTRPZEDzdSNtOrbLCAcKq6SsPSIDqLBL9LorSA8R1NR6Ig940T+XxpV YtpgoTAXjImocr45uvqw0H1pv7z7TJEz0zIvMrEkIADb5Olqgdk8nCnpKjGCnHY99u3KIc 9j6CSqMOM39eurYAPhhet3Jdp7p6HQ0BVdgKeo8rMQU79wXiqsDKd8bzU0SjUCvZbTbtQd 7NYwmqBpTIl3cJQ/c3tA9k6+FLeVdbYgxIYDzOOA6iOnjnvtOQNY9q3Gv0LL5A== ARC-Seal: i=1; s=key1; d=yhetil.org; t=1661803976; a=rsa-sha256; cv=none; b=quDbGr/Q7vODHXM9b79NKw3lTXafVHSXbEbYxupJ7IQg0/2tyerYVd5wek0nxBoMWfFbHx paizfWhaKCTBi6jTvf1PfcQChsy3XiCdkPc9QaaSUNAaEPLxdxmLZ5L+xEu1ZDuOkuZYMK pK12wo1HJfZJtQLydYCHWnhvD2PC7n2BKG5bx2PI3/CoGNuz/ib3MxCIap3surxl/BE9Um 2AOnNzxmpD3mrlnC0rj+vOrlhjRnT45n6yWjvamwRmSGwvRJAoqyidHUZDHMsoF5lr40hH wTM91dOOl+5x6cuje6+doo07KnCUjBsa0DBHMU1AlnpWNh3p9FRyic2mdwTf0w== ARC-Authentication-Results: i=1; aspmx1.migadu.com; dkim=pass header.d=posteo.net header.s=2017 header.b="PfTO36G/"; dmarc=pass (policy=none) header.from=posteo.net; spf=pass (aspmx1.migadu.com: domain of "help-guix-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="help-guix-bounces+larch=yhetil.org@gnu.org" X-Migadu-Spam-Score: -6.30 Authentication-Results: aspmx1.migadu.com; dkim=pass header.d=posteo.net header.s=2017 header.b="PfTO36G/"; dmarc=pass (policy=none) header.from=posteo.net; spf=pass (aspmx1.migadu.com: domain of "help-guix-bounces+larch=yhetil.org@gnu.org" designates 209.51.188.17 as permitted sender) smtp.mailfrom="help-guix-bounces+larch=yhetil.org@gnu.org" X-Migadu-Queue-Id: A738927333 X-Spam-Score: -6.30 X-Migadu-Scanner: scn0.migadu.com X-TUID: 3uO8ICKbwdR2 Hello Peter. On Wed, Aug 24, 2022 at 11:27:33 -0400, Peter Polidoro wrote: >Does anyone have any examples of using Guix System as a network >router? Below I attach a system configuration that works for me. It doesn't necessarily adhere to Guix's best practices in every regard. >I would prefer, though, not to need custom packages or channels, if >possible. The question is what exactly the router is supposed to do, i.e. which network services it shall provide. The below example does the following: - Set custom meaningful names to the three network interfaces based on their MAC addresses. - Set up static IPv4-only networking. - Route traffic between the different subnets, restricted by Nftables rules. - Provide DNS and DHCP to some subnets, using Dnsmasq. - Use the serial console for bootloader and kernel consoles. (I run this router on a QEMU-KVM virtual machine with no graphics.) I found Dnsmasq to be sufficient as a combined DNS/DHCP server for a small network. For larger deployments one might use separate software packages for DNS and DHCP. I removed some unrelated services from the configuration. The code is thus not tested and might need adjustment. To run without error, the code requires nftables to be installed as it is used to check the rules. Feel free to ask if questions arise. 'Hope that provides some inspiration. Greetings Niklas (use-modules (gnu)) (use-service-modules networking shepherd ssh sysctl) (use-package-modules admin bash dns linux) (use-modules (ice-9 popen)) (use-modules (guix records)) (define-record-type* if-rename make-if-rename if-rename? this-if-rename (name if-rename-name) (mac if-rename-mac)) (define (if-renames->udev-rule if-renames) (udev-rule "70-netifnames.rules" (string-join (map (lambda (iface) (format #f "SUBSYSTEM==\"net\", ACTION==\"add\", ATTR{address}==~s, NAME=~s" (if-rename-mac iface) (if-rename-name iface))) if-renames) "\n" 'suffix))) (define (acpi-daemon-service) (simple-service 'acpi-daemon shepherd-root-service-type (list (shepherd-service (provision '(acpi-daemon)) (start #~(make-forkexec-constructor (list #$(file-append acpid "/sbin/acpid") "-f" "-l" "--confdir" #$(file-union "etc-acpi-events" `(("power" ,(plain-file "power" "event=button/power\naction=/run/current-system/profile/sbin/shutdown")) ("reboot" ,(plain-file "reboot" "event=button/reboot\naction=/run/current-system/profile/sbin/reboot"))))))) (stop #~(make-kill-destructor)))))) (define %my-nftables-ruleset (plain-file "nftables.conf" " flush ruleset define NET_LAB = 192.168.10.0/24 define NET_LAN = 192.168.3.0/24 table ip global { chain inbound_wan { # accept ping icmp type echo-request accept # accept ICMP Fragmentation Needed packets, for Path MTU Discovery icmp code frag-needed accept icmp type destination-unreachable accept } chain inbound_private { # accept ping icmp type echo-request limit rate 5/second accept # accept SSH, DNS, DHCP ip protocol . th dport vmap { \\ tcp . 22 : accept, \\ udp . 53 : accept, \\ tcp . 53 : accept, \\ udp . 67 : accept \\ } } chain inbound { type filter hook input priority 0; policy drop; ct state established,related accept iifname vmap { \\ lo : accept, \\ wan : jump inbound_wan, \\ lab : jump inbound_private, \\ lan : jump inbound_private \\ } } chain forward { type filter hook forward priority 0; policy drop; ct state established,related accept # allow from lab, lan to wan iifname { lab, lan } oifname wan accept } chain postrouting { type nat hook postrouting priority 100; policy accept; # masquerade private IP addresses ip saddr { $NET_LAB, $NET_LAN } oifname wan masquerade } } ")) (let ((port (open-output-pipe "nft -c -f -"))) (display (plain-file-content %my-nftables-ruleset) port) (if (not (eqv? 0 (status:exit-val (close-pipe port)))) (error "Nftables rules don't pass check"))) (define %my-dnsmasq-config (plain-file "dnsmasq.conf" " dhcp-authoritative domain-needed localise-queries expand-hosts domain=lan server=/lan/ server=/lab/ # RFC6761: domains that should not be forwarded to Internet name servers server=/bind/ server=/invalid/ server=/local/ server=/localhost/ server=/onion/ server=/test/ dhcp-leasefile=/tmp/dhcp.leases stop-dns-rebind rebind-localhost-ok dhcp-broadcast=tag:needs-broadcast user=nobody group=nogroup cache-size=1500 #bind-dynamic #interface=lan,lab #listen-address=192.168.3.3,192.168.10.3 bogus-priv #conf-file=/usr/share/dnsmasq/rfc6761.conf dhcp-range=set:lan,192.168.3.100,192.168.3.249,255.255.255.0,12h no-dhcp-interface=wan dhcp-range=set:lab,192.168.10.100,192.168.10.249,255.255.255.0,12h # in response to CERT VU#598349 # An attacker may add a device with the name 'wpad` to the network, # which may produce a collision with a standardized WPAD DNS name. dhcp-ignore-names=tag:dhcp_bogus_hostname dhcp-name-match=set:dhcp_bogus_hostname,localhost dhcp-name-match=set:dhcp_bogus_hostname,wpad ")) (define (dnsmasq-service) (simple-service 'mydnsmasq shepherd-root-service-type (list (shepherd-service (provision '(mydnsmasq)) (start #~(make-forkexec-constructor (list #$(file-append dnsmasq "/sbin/dnsmasq") "-k" "-C" #$%my-dnsmasq-config))) (stop #~(make-kill-destructor)) (respawn? #f))))) (operating-system (locale "en_GB.utf8") (timezone "Europe/Berlin") (keyboard-layout (keyboard-layout "de")) (host-name "gw") (users (cons* (user-account (name "nschmidt") (comment "Nschmidt") (group "users") (home-directory "/home/nschmidt") (supplementary-groups '("wheel" "netdev"))) %base-user-accounts)) (packages (cons* (list (specification->package "bind") "utils") (append (map specification->package '("emacs-no-x" "htop" "net-tools" "nss-certs" "tmux" "wireguard-tools")) %base-packages))) (hosts-file (plain-file "hosts" (string-append (local-host-aliases host-name) " 192.168.3.2 server.lan 192.168.10.3 gw.lab "))) (services (append (list ;; Handle the power and restart ACPI buttons. ;; Alternatively use Elogind. (acpi-daemon-service) (dnsmasq-service) (service openssh-service-type (openssh-configuration (password-authentication? #f))) (service static-networking-service-type (list (static-networking (addresses (list (network-address (device "wan") (value "192.168.1.4/24")) (network-address (device "lab") (value "192.168.10.3/24")) (network-address (device "lan") (value "192.168.3.3/24")))) (routes (list (network-route (destination "default") (gateway "192.168.1.1")))) (name-servers '("192.168.1.1"))))) (service nftables-service-type (nftables-configuration (ruleset %my-nftables-ruleset)))) (modify-services %base-services (udev-service-type config => (udev-configuration (inherit config) (rules (cons* (if-renames->udev-rule (list (if-rename (mac "52:54:00:7e:7c:41") (name "lab")) (if-rename (mac "52:54:00:77:38:d2") (name "wan")) (if-rename (mac "52:54:00:5e:20:94") (name "lan")))) (udev-configuration-rules config))))) (sysctl-service-type config => (sysctl-configuration (settings (append '(("net.ipv4.ip_forward" . "1")) %default-sysctl-settings)))) ;; The machine has no graphics card, so VTs are not used (delete console-font-service-type) (delete mingetty-service-type) (delete virtual-terminal-service-type)))) (kernel-arguments '("quiet" "ipv6.disable=1" ;; Use serial console ;; Linux uses the last console= argument as /dev/console "console=tty0" "console=ttyS0,115200")) (bootloader (bootloader-configuration (bootloader grub-bootloader) (targets '("/dev/sda")) (terminal-inputs '(console serial)) (terminal-outputs '(gfxterm serial)) (serial-unit 0) (serial-speed 115200) (keyboard-layout keyboard-layout))) (swap-devices (list (swap-space (target (uuid "7472d01e-0d42-4a04-8f90-8b8e0f08a957"))))) (file-systems (cons* (file-system (mount-point "/") (device (uuid "b9dc4762-73b0-46d6-b4e9-33a530522a16" 'ext4)) (type "ext4")) %base-file-systems)))