bookends.m4: Much more intelligent initialization.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 23 Jul 2011 11:44:00 +0000 (12:44 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 23 Jul 2011 11:54:57 +0000 (12:54 +0100)
Rather than clobbering all of the chains, clear them out one at a time,
preserving some which are known to be maintained elsewhere.

bookends.m4
config.m4

index 7374cd3..b51f8ae 100644 (file)
@@ -28,14 +28,76 @@ m4_divert(30)m4_dnl
 ## The main chains: set policy to drop, and then clear the rules.  For a
 ## while, incoming packets will be silently dropped, but we should have got
 ## everything going before anyone actually hits a timeout.
-for t in mangle filter; do
-  for i in PREROUTING INPUT FORWARD OUTPUT POSTROUTING; do
-    run ip46tables -t $t -P $i DROP 2>/dev/null || :
-    run ip46tables -t $t -F $i 2>/dev/null || :
+##
+## We don't control some of the chains, so we should preserve them.  This
+## introduces a whole bunch of problems.
+
+## Chains we're meant to preserve
+preserve_chains="filter:fail2ban filter:fail2ban-* $preserve_chains"
+
+## Take the various IP versions in turn.
+unref=nil
+for ip in ip ip6; do
+  for table in $(cat /proc/net/${ip}_tables_names); do
+
+    ## Step 1: clear out the builtin chains.
+    ${ip}tables -nL -t $table |
+    sed -n '/^Chain \([^ ]\+\) (policy .*$/ s//\1/p ' |
+    while read chain; do
+      case $table in
+       nat) policy=ACCEPT ;;
+       *) policy=DROP ;;
+      esac
+      run ${ip}tables -t $table -P $chain $policy
+      run ${ip}tables -t $table -F $chain
+    done
+
+    ## Step 2: clear out user chains.  Unfortunately, we can only clear
+    ## chains which have no references to them, so work through picking off
+    ## unreferenced chains which aren't meant to be preserved until there are
+    ## none left.
+    while :; do
+      progress=nil
+      ${ip}tables -nL -t $table |
+      sed -n '/^Chain \([^ ]\+\) (0 references)$/ s//\1/p ' \
+       >/var/run/firewall-chains.tmp
+      while read chain; do
+       match=nil
+       for pat in $preserve_chains; do
+         case "$table:$chain" in $pat) match=t ;; esac
+       done
+       case $match in
+         nil)
+           run ${ip}tables -t $table -F $chain
+           run ${ip}tables -t $table -X $chain
+           progress=t
+           ;;
+       esac
+      done </var/run/firewall-chains.tmp
+      case $progress in nil) break ;; esac
+    done
+
+    ## Step 3: report on uncleared user chains.  This means that there's a
+    ## serious problem.
+    ${ip}tables -nL -t $table |
+    sed -n '/^Chain \([^ ]\+\) (\([1-9][0-9]*\) references)$/ s//\1 \2/p ' \
+      >/var/run/firewall-chains.tmp
+    while read chain refs; do
+      match=nil
+      for pat in $preserve_chains; do
+       case "$table:$chain" in $pat) match=t ;; esac
+      done
+      case $match in
+       nil)
+         echo >&2 "$0: can't clear referenced $ip chain \`$table:$chain'"
+         unref=t
+         ;;
+      esac
+    done </var/run/firewall-chains.tmp
   done
-  run ip46tables -t $t -F
-  run ip46tables -t $t -X
 done
+rm -f /var/run/firewall-chains.tmp
+case $unref in t) exit 1 ;; esac
 
 m4_divert(32)m4_dnl
 ###--------------------------------------------------------------------------
index 21c6712..6756452 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -36,6 +36,9 @@ defconf(firewall_failsafe, /etc/init.d/firewall.safe)
 defconf(open_port_min, 32000)
 defconf(open_port_max, 54999)
 
+## Which chains to preserve.
+defconf(preserve_chains, )
+
 ## Whether to permit forwarding.
 defconf(forward, 1)