From 2b4dad02d371b7fbdeaa82b5fce82b5cecc2ce48 Mon Sep 17 00:00:00 2001
From: ale <ale@incal.net>
Date: Thu, 7 May 2020 08:40:09 +0100
Subject: [PATCH] Rename the script to update-firewall, and add update-ipset

Moves the ipset file-based configuration to a directory hierarchy
below /etc/firewall/blocked, with "type" (ip/net) and "proto"
(ipv4/ipv6) nested subdirectories and a run-parts-style multi-file
setup.

Allows users to update ipsets without having to necessarily reload
all the other firewall rules.
---
 Makefile                    |  3 ++-
 README.md                   |  5 +++++
 conf-dist/filter.d/02ipset  | 36 ++-----------------------------
 debian/firewall.service     |  2 +-
 firewall => update-firewall |  0
 update-ipset                | 42 +++++++++++++++++++++++++++++++++++++
 6 files changed, 52 insertions(+), 36 deletions(-)
 rename firewall => update-firewall (100%)
 create mode 100644 update-ipset

diff --git a/Makefile b/Makefile
index 5db5c90..709fefa 100644
--- a/Makefile
+++ b/Makefile
@@ -15,7 +15,8 @@ install:
 	$(INSTALL) -d $(DESTDIR)$(sbindir)
 	$(INSTALL) -d $(DESTDIR)$(sharedir)
 	$(INSTALL) -d $(DESTDIR)$(fwconfdir)
-	$(INSTALL) -m 755 firewall $(DESTDIR)$(sbindir)/firewall
+	$(INSTALL) -m 755 update-firewall $(DESTDIR)$(sbindir)/update-firewall
+	$(INSTALL) -m 755 update-ipset $(DESTDIR)$(sbindir)/update-ipset
 	(for t in $(TABLES); do \
 	  $(INSTALL) -d $(DESTDIR)$(fwconfdir)/$$t.d ; \
 	  $(INSTALL) -d $(DESTDIR)$(sharedir)/$$t.d ; \
diff --git a/README.md b/README.md
index c0c5c9b..8ae1bd5 100644
--- a/README.md
+++ b/README.md
@@ -67,6 +67,11 @@ iptables options (the default is simply `-j ALLOW`).
 Allow incoming traffic to the specified ports. *PORT_SPEC*
 should be a comma-separated list of destination ports.
 
+# Usage
+
+Run *update-firewall* to set up iptables whenever the rules below
+/etc/firewall change.
+
 # Notes
 
 The firewall script will always attempt to setup IPv6 rules, even if
diff --git a/conf-dist/filter.d/02ipset b/conf-dist/filter.d/02ipset
index 35f4c75..704db90 100644
--- a/conf-dist/filter.d/02ipset
+++ b/conf-dist/filter.d/02ipset
@@ -2,41 +2,9 @@
 # Scales easily with large number of blocked entries.
 #
 # Reads the blacklists from:
-# /etc/firewall/blocked_{ips,nets}.{ipv4,ipv6}
+# /etc/firewall/blocked/{ip,net}/{ipv4,ipv6}/*
 
-d=${CONFIG_DIR:-/etc/firewall}
-
-ipset_add_file() {
-    local proto="$1"
-    local set_type="$2"
-    local set_name="block_${set_type}"
-    local family=
-    case "${proto}" in
-        ipv4)
-            family=inet
-            ;;
-        ipv6)
-            family=inet6
-            set_name="${set_name}6"
-            ;;
-    esac            
-    local source_file="${d}/blocked_${set_type}s.${proto}"
-
-    echo "create ${set_name} hash:${set_type} family ${family} hashsize 1024 maxelem 65536"
-    echo "flush ${set_name}"
-    if [ -e ${source_file} ]; then
-        grep -v '^#' ${source_file} \
-            | grep -v '^$' \
-            | sed -e "s/^\\(.*\\)\$/add ${set_name} \\1/"
-    fi
-}
-
-(
-    ipset_add_file ipv4 ip
-    ipset_add_file ipv6 ip
-    ipset_add_file ipv4 net
-    ipset_add_file ipv6 net
-) | ipset restore -exist
+update-ipset
 
 add_rule4 -A pre-input -m set --match-set block_ip src -j DROP
 add_rule6 -A pre-input -m set --match-set block_ip6 src -j DROP
diff --git a/debian/firewall.service b/debian/firewall.service
index c16f2e1..54a6478 100644
--- a/debian/firewall.service
+++ b/debian/firewall.service
@@ -4,7 +4,7 @@ Description=Set up firewall
 [Service]
 Type=oneshot
 EnvironmentFile=-/etc/default/firewall
-ExecStart=/usr/sbin/firewall
+ExecStart=/usr/sbin/update-firewall
 
 [Install]
 WantedBy=multi-user.target
diff --git a/firewall b/update-firewall
similarity index 100%
rename from firewall
rename to update-firewall
diff --git a/update-ipset b/update-ipset
new file mode 100644
index 0000000..d8da43c
--- /dev/null
+++ b/update-ipset
@@ -0,0 +1,42 @@
+#!/bin/sh
+#
+# Create or reload ipset tables using data from /etc/firewall/blocked/
+#
+
+basedir=${CONFIG_DIR:-/etc/firewall/blocked}
+
+gen_set() {
+    local proto="$1"
+    local set_type="$2"
+    local set_name="block_${set_type}"
+    local family=
+    case "${proto}" in
+        ipv4)
+            family=inet
+            ;;
+        ipv6)
+            family=inet6
+            set_name="${set_name}6"
+            ;;
+    esac
+
+    echo "create ${set_name} hash:${set_type} family ${family} hashsize 1024 maxelem 65536"
+    echo "flush ${set_name}"
+
+    local source_dir="${basedir}/${set_type}/${proto}"
+    if [ -d "${source_dir}" ]; then
+        cat $(run-parts --list "${source_dir}") \
+            | grep -v '^#' ${source_file} \
+            | grep -v '^$' \
+            | sed -e "s/^\\(.*\\)\$/add ${set_name} \\1/"
+    fi
+}
+
+set -o pipefail
+
+(
+    gen_set ipv4 ip
+    gen_set ipv6 ip
+    gen_set ipv4 net
+    gen_set ipv6 net
+) | ipset restore -exist
-- 
GitLab