From 4574bcb6b8544ea509a707a760eb02986139b576 Mon Sep 17 00:00:00 2001 From: Vivien Kraus Date: Thu, 4 Jan 2024 18:53:45 +0100 Subject: Add the simple-firewall-service-type --- .guix-channel | 3 + guix/vkraus/services/simple-firewall.scm | 160 +++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 .guix-channel create mode 100644 guix/vkraus/services/simple-firewall.scm diff --git a/.guix-channel b/.guix-channel new file mode 100644 index 0000000..8cec433 --- /dev/null +++ b/.guix-channel @@ -0,0 +1,3 @@ +(channel + (version 0) + (directory "guix")) diff --git a/guix/vkraus/services/simple-firewall.scm b/guix/vkraus/services/simple-firewall.scm new file mode 100644 index 0000000..a5848c4 --- /dev/null +++ b/guix/vkraus/services/simple-firewall.scm @@ -0,0 +1,160 @@ +(define-module (vkraus services simple-firewall) + #:use-module ((gnu services) #:select (service-type service-extension)) + #:use-module ((gnu packages linux) #:select (nftables)) + #:use-module (gnu services shepherd) + #:use-module (guix gexp) + #:use-module (guix packages) + #:use-module (srfi srfi-9) + #:use-module (srfi srfi-9 gnu) + #:use-module (ice-9 match) + #:declarative? #t + #:export + ( + + simple-firewall-configuration + simple-firewall-configuration? + nftables-package opened-tcp-ports opened-udp-ports + set-nftables-package set-opened-tcp-ports set-opened-udp-ports + merge-firewall-configurations + simple-firewall-service-type + )) + +(define-immutable-record-type + (simple-firewall-configuration nft tcp-ports udp-ports) + simple-firewall-configuration? + (nft nftables-package set-nftables-package) + (tcp-ports opened-tcp-ports set-opened-tcp-ports) + (udp-ports opened-udp-ports set-opened-udp-ports)) + +(define (append-if-not-present item list) + (if (member item list) + list + `(,@list ,item))) + +(define (remove-duplicates all) + (let append ((lst all) + (unique '())) + (match lst + (() unique) + ((x lst ...) + (append lst (append-if-not-present x unique)))))) + +(define merge-firewall-configurations + (match-lambda* + (() (simple-firewall-configuration #f '() '())) + ((($ nft tcp udp) + cfg ...) + (match (apply merge-firewall-configurations cfg) + (($ nfts tcps udps) + (simple-firewall-configuration + (if (and nft nfts) + (error "The nftables package is overriden twice. Please choose.") + (or nft nfts)) + (remove-duplicates `(,@tcp ,@tcps)) + (remove-duplicates `(,@udp ,@udps)))))))) + +(define port->string + (match-lambda + ((? symbol? high-level-name) + (with-output-to-string + (lambda () (display high-level-name)))) + ((? integer? number) + (with-output-to-string + (lambda () (display number)))))) + +(define simple-firewall-shepherd-service + (match-lambda + (($ nft tcp udp) + (let ((config-file + (plain-file + "simple-firewall-configuration" + (format #f + "flush ruleset + +table inet firewall { + chain inbound { + # By default, drop all traffic unless it meets a filter + # criteria specified by the rules that follow below. + type filter hook input priority 0; policy drop; + + # Allow traffic from established and related packets. + ct state established,related accept + + # Drop invalid packets. + ct state invalid drop + + # Allow loopback traffic. + iifname lo accept + + # Allow all ICMP and IGMP traffic, but enforce a rate limit + # to help prevent some types of flood attacks. + ip protocol icmp limit rate 4/second accept + meta l4proto ipv6-icmp limit rate 4/second accept + ip protocol igmp limit rate 4/second accept + + # Allow DHCPv6 incoming replies + ip6 daddr fe80::/64 udp sport 547 udp dport 546 ct state { new, untracked } accept + + # Allow TCP ports + ~atcp dport { ~a } accept + + # Allow UDP ports + ~audp dport { ~a } accept + } + + chain forward { + # Drop everything (assumes this device is not a router) + type filter hook forward priority 0; policy drop; + + } + + chain outbound { + # Allow all outbound traffic + type filter hook output priority 0; policy accept; + } +} +" + (if (null? tcp) + "# " + "") + (string-join + (map port->string tcp) + ", ") + (if (null? udp) + "# " + "") + (string-join + (map port->string udp) + ", ")))) + (nft-package + (or nft nftables))) + (shepherd-service + (documentation + "Simple firewall that only allows inbound packets to specific ports") + (provision '(simple-firewall)) + (start + #~(lambda _ + (invoke #$(file-append nft-package "/sbin/nft") + "--file" #$config-file))) + (stop + #~(lambda _ + (invoke #$(file-append nft-package "/sbin/nft") + "flush" "ruleset")))))))) + +(define simple-firewall-service-type + (service-type + (name 'simple-firewall) + (extensions + (list + (service-extension + shepherd-root-service-type + (lambda (cfg) + `(,(simple-firewall-shepherd-service cfg)))))) + (compose + (lambda (extensions) + (apply append extensions))) + (extend + (lambda (a bs) + (apply merge-firewall-configurations a bs))) + (description + "A very simple firewall service with some ports opened."))) -- cgit v1.2.3