After googling around a bit it looks like the `filter*` and `COMMIT` commands in iptables configurations do in fact form a transactional block that would allow us to accept additional plain-files via extensions and just concatenate them, it's that's a road we want to go down On Fri, Nov 4, 2022 at 12:26 AM antlers wrote: > From: antlers > > * gnu/services/networking.scm (simple-firewall-service): Add. > (iptables-service): Allow a crude sort of service extension. > > I tried out a keyword-based syntax: > ``` > (simple-firewall-configuration > (allow-forwarding? #t) > (allowed-ports '(#:both 51234 > #:tcp 80 443 > #:udp 4444)) > ``` > But kept the more verbose tcp and udp fields because I don't want > people to have to use quasiquotes to splice in evaluated port-numbers > after the keywords. > > I like the suggestion that there should be a field for redirecting > packets, whether to loopback or another box, as it took me a while to > learn about eg. masquerading last time I needed to set something like > that up. Not sure what command would be equivalent to the NAT > suggestion? > > I guess nftables has superseded iptables, but I'm not as familiar with > it? Perhaps I can add it as a second back-end in the future. My > primary concern right now is a pure Scheme interface for networking > configuration; most notably via service inheritance! Simple-firewall > now lets you open ports via extensions in other services; in order for > this option to be widely available, perhaps it's the > {nf,ip}tables-services that should be extensible? It's a tricky > problem atm because we don't really want services that need ports > depending on a specific backend, there are existing API's, they use > plain-file's over structs or strings, and rule orders need to be > really specific/coordinated. Idk, maybe that isn't something we really > want in the first place, but it sure feels good from a configuration / > organizational point-of-view. Happy to tweak this again if anyone has > ideas. > --- > gnu/services/networking.scm | 79 ++++++++++++++++++++++++++++++++++++- > 1 file changed, 77 insertions(+), 2 deletions(-) > > diff --git a/gnu/services/networking.scm b/gnu/services/networking.scm > index 19aba8c266..0866c10b34 100644 > --- a/gnu/services/networking.scm > +++ b/gnu/services/networking.scm > @@ -18,6 +18,8 @@ > ;;; Copyright © 2021 Christine Lemmer-Webber > ;;; Copyright © 2021 Maxime Devos > ;;; Copyright © 2021 Guillaume Le Vaillant > +;;; Copyright © 2021 Solene Rapenne > +;;; Copyright © 2022 antlers > ;;; > ;;; This file is part of GNU Guix. > ;;; > @@ -225,7 +227,11 @@ (define-module (gnu services networking) > > keepalived-configuration > keepalived-configuration? > - keepalived-service-type)) > + keepalived-service-type > + > + simple-firewall-service-type > + simple-firewall-configuration > + simple-firewall-configuration?)) > > ;;; Commentary: > ;;; > @@ -1721,7 +1727,13 @@ (define iptables-service-type > "Run @command{iptables-restore}, setting up the specified rules.") > (extensions > (list (service-extension shepherd-root-service-type > - (compose list iptables-shepherd-service)))))) > + (compose list iptables-shepherd-service)))) > + ;; Some services extend iptables, but such services are mutually > exclusive, > + ;; and should be either extended directly or superseded entirely > depending > + ;; the complexity of your desired configuration. > + (compose identity) > + (extend (lambda (config entries) > + (last entries))))) > > ;;; > ;;; nftables > @@ -2186,4 +2198,67 @@ (define keepalived-service-type > "Run @uref{https://www.keepalived.org/, Keepalived} > routing software."))) > > + > +;;; > +;;; Simple Firewall > +;;; > + > +(define-record-type* > + simple-firewall-configuration make-simple-firewall-configuration > + simple-firewall-configuration? > + (allow-icmp? simple-firewall-configuration-allow-icmp? > + (default #f)) > + (allow-forwarding? simple-firewall-configuration-allow-forwarding? > + (default #f)) > + > + (open-tcp-ports simple-firewall-configuration-open-tcp-ports > + (default '())) > + (open-udp-ports simple-firewall-configuration-open-udp-ports > + (default '()))) > + > +(define simple-firewall-configuration->iptables-rules > + (match-lambda > + (($ > + allow-icmp? allow-forwarding? > + open-tcp-ports open-udp-ports) > + (string-join > + `("*filter" > + ":INPUT DROP" > + ,(string-append ":FORWARD " (if allow-forwarding? "ACCEPT" > "DROP")) > + ":OUTPUT ACCEPT" > + "-A INPUT -i lo -j ACCEPT" > + "-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT" > + ,@(unless allow-icmp? '("-A INPUT -p icmp -j DROP" > + "-A INPUT -p icmpv6 -j DROP")) > + ,@(map (cut string-append "-A INPUT -p tcp --dport " <> " -j > ACCEPT") (map number->string open-tcp-ports)) > + ,@(map (cut string-append "-A INPUT -p udp --dport " <> " -j > ACCEPT") (map number->string open-udp-ports)) > + "-A INPUT -j REJECT --reject-with icmp-port-unreachable" > + "COMMIT") > + "\n" 'suffix)))) > + > +(define (simple-firewall-configuration->iptables-configuration config) > + (let ((rules (simple-firewall-configuration->iptables-rules config))) > + (iptables-configuration > + (ipv4-rules (plain-file "iptables.rules" rules)) > + (ipv6-rules (plain-file "ip6tables.rules" rules))))) > + > +(define simple-firewall-service-type > + (service-type > + (name 'simple-firewall) > + (description > + "Run @command{iptables-restore}, setting up the specified rules.") > + (extensions > + (list (service-extension iptables-service-type > + > simple-firewall-configuration->iptables-configuration))) > + (compose concatenate) > + (extend (lambda (config entries) > + (simple-firewall-configuration > + (inherit config) > + (open-tcp-ports > + (concatenate (map > simple-firewall-configuration-open-tcp-ports > + (cons config entries)))) > + (open-udp-ports > + (concatenate (map > simple-firewall-configuration-open-udp-ports > + (cons config entries))))))))) > + > ;;; networking.scm ends here > -- > 2.38.0 > >