From b639c8869cedd44e11196242bbdc3ff33dfb3ad3 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 25 Jan 2022 00:00:40 +0100 Subject: [PATCH] make several iptables actions more breakdown-safe: start wouldn't fail if chain or rule already exists (e. g. created by previous instance and doesn't get purged properly); ultimately closes gh-980 --- config/action.d/iptables-ipset.conf | 2 +- config/action.d/iptables.conf | 5 +-- fail2ban/tests/servertestcase.py | 68 +++++++++++++++++------------ 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/config/action.d/iptables-ipset.conf b/config/action.d/iptables-ipset.conf index 481fe753..74dfe6c3 100644 --- a/config/action.d/iptables-ipset.conf +++ b/config/action.d/iptables-ipset.conf @@ -25,7 +25,7 @@ before = iptables.conf # Values: CMD # actionstart = ipset -exist create hash:ip timeout - -I %(_ipt_chain_rule)s + { %(_ipt_check_rule)s >/dev/null 2>&1; } || { -I %(_ipt_chain_rule)s; } # Option: actionflush # Notes.: command executed once to flush IPS, by shutdown (resp. by stop of the jail or this action) diff --git a/config/action.d/iptables.conf b/config/action.d/iptables.conf index 7ca9c962..821a9ef1 100644 --- a/config/action.d/iptables.conf +++ b/config/action.d/iptables.conf @@ -22,9 +22,8 @@ actionflush = -F f2b- # Notes.: command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false). # Values: CMD # -actionstart = -N f2b- - -A f2b- -j - -I %(_ipt_chain_rule)s +actionstart = { -C f2b- -j >/dev/null 2>&1; } || { -N f2b- || true; -A f2b- -j ; } + { %(_ipt_check_rule)s >/dev/null 2>&1; } || { -I %(_ipt_chain_rule)s; } # Option: actionstop # Notes.: command executed at the stop of jail (or at the end of Fail2Ban) diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 54088e8f..8741893d 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -1506,14 +1506,16 @@ class ServerConfigReaderTests(LogCaptureTestCase): ('j-w-iptables-mp', 'iptables-multiport[name=%(__name__)s, bantime="10m", port="http,https", protocol="tcp", chain=""]', { 'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'), 'ip4-start': ( - "`iptables -w -N f2b-j-w-iptables-mp`", - "`iptables -w -A f2b-j-w-iptables-mp -j RETURN`", - "`iptables -w -I INPUT -p tcp -m multiport --dports http,https -j f2b-j-w-iptables-mp`", + "`{ iptables -w -C f2b-j-w-iptables-mp -j RETURN >/dev/null 2>&1; } || " + "{ iptables -w -N f2b-j-w-iptables-mp || true; iptables -w -A f2b-j-w-iptables-mp -j RETURN; }`", + "`{ iptables -w -C INPUT -p tcp -m multiport --dports http,https -j f2b-j-w-iptables-mp >/dev/null 2>&1; } || " + "{ iptables -w -I INPUT -p tcp -m multiport --dports http,https -j f2b-j-w-iptables-mp; }`", ), 'ip6-start': ( - "`ip6tables -w -N f2b-j-w-iptables-mp`", - "`ip6tables -w -A f2b-j-w-iptables-mp -j RETURN`", - "`ip6tables -w -I INPUT -p tcp -m multiport --dports http,https -j f2b-j-w-iptables-mp`", + "`{ ip6tables -w -C f2b-j-w-iptables-mp -j RETURN >/dev/null 2>&1; } || " + "{ ip6tables -w -N f2b-j-w-iptables-mp || true; ip6tables -w -A f2b-j-w-iptables-mp -j RETURN; }`", + "`{ ip6tables -w -C INPUT -p tcp -m multiport --dports http,https -j f2b-j-w-iptables-mp >/dev/null 2>&1; } || ", + "{ ip6tables -w -I INPUT -p tcp -m multiport --dports http,https -j f2b-j-w-iptables-mp; }`", ), 'flush': ( "`iptables -w -F f2b-j-w-iptables-mp`", @@ -1550,14 +1552,16 @@ class ServerConfigReaderTests(LogCaptureTestCase): ('j-w-iptables-ap', 'iptables-allports[name=%(__name__)s, bantime="10m", protocol="tcp", chain=""]', { 'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'), 'ip4-start': ( - "`iptables -w -N f2b-j-w-iptables-ap`", - "`iptables -w -A f2b-j-w-iptables-ap -j RETURN`", - "`iptables -w -I INPUT -p tcp -j f2b-j-w-iptables-ap`", + "`{ iptables -w -C f2b-j-w-iptables-ap -j RETURN >/dev/null 2>&1; } || " + "{ iptables -w -N f2b-j-w-iptables-ap || true; iptables -w -A f2b-j-w-iptables-ap -j RETURN; }`", + "`{ iptables -w -C INPUT -p tcp -j f2b-j-w-iptables-ap >/dev/null 2>&1; } || ", + "{ iptables -w -I INPUT -p tcp -j f2b-j-w-iptables-ap; }`", ), 'ip6-start': ( - "`ip6tables -w -N f2b-j-w-iptables-ap`", - "`ip6tables -w -A f2b-j-w-iptables-ap -j RETURN`", - "`ip6tables -w -I INPUT -p tcp -j f2b-j-w-iptables-ap`", + "`{ ip6tables -w -C f2b-j-w-iptables-ap -j RETURN >/dev/null 2>&1; } || " + "{ ip6tables -w -N f2b-j-w-iptables-ap || true; ip6tables -w -A f2b-j-w-iptables-ap -j RETURN; }`", + "`{ ip6tables -w -C INPUT -p tcp -j f2b-j-w-iptables-ap >/dev/null 2>&1; } || ", + "{ ip6tables -w -I INPUT -p tcp -j f2b-j-w-iptables-ap; }`", ), 'flush': ( "`iptables -w -F f2b-j-w-iptables-ap`", @@ -1595,11 +1599,13 @@ class ServerConfigReaderTests(LogCaptureTestCase): 'ip4': (' f2b-j-w-iptables-ipset ',), 'ip6': (' f2b-j-w-iptables-ipset6 ',), 'ip4-start': ( "`ipset -exist create f2b-j-w-iptables-ipset hash:ip timeout 0 `", - "`iptables -w -I INPUT -p tcp -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset src -j REJECT --reject-with icmp-port-unreachable`", + "`{ iptables -w -C INPUT -p tcp -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset src -j REJECT --reject-with icmp-port-unreachable >/dev/null 2>&1; } || " + "{ iptables -w -I INPUT -p tcp -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset src -j REJECT --reject-with icmp-port-unreachable; }`", ), 'ip6-start': ( "`ipset -exist create f2b-j-w-iptables-ipset6 hash:ip timeout 0 family inet6`", - "`ip6tables -w -I INPUT -p tcp -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset6 src -j REJECT --reject-with icmp6-port-unreachable`", + "`{ ip6tables -w -C INPUT -p tcp -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset6 src -j REJECT --reject-with icmp6-port-unreachable >/dev/null 2>&1; } || " + "{ ip6tables -w -I INPUT -p tcp -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset6 src -j REJECT --reject-with icmp6-port-unreachable; }`", ), 'flush': ( "`ipset flush f2b-j-w-iptables-ipset`", @@ -1637,11 +1643,13 @@ class ServerConfigReaderTests(LogCaptureTestCase): 'ip4': (' f2b-j-w-iptables-ipset-ap ',), 'ip6': (' f2b-j-w-iptables-ipset-ap6 ',), 'ip4-start': ( "`ipset -exist create f2b-j-w-iptables-ipset-ap hash:ip timeout 0 `", - "`iptables -w -I INPUT -p tcp -m set --match-set f2b-j-w-iptables-ipset-ap src -j REJECT --reject-with icmp-port-unreachable`", + "`{ iptables -w -C INPUT -p tcp -m set --match-set f2b-j-w-iptables-ipset-ap src -j REJECT --reject-with icmp-port-unreachable >/dev/null 2>&1; } || " + "{ iptables -w -I INPUT -p tcp -m set --match-set f2b-j-w-iptables-ipset-ap src -j REJECT --reject-with icmp-port-unreachable; }", ), 'ip6-start': ( "`ipset -exist create f2b-j-w-iptables-ipset-ap6 hash:ip timeout 0 family inet6`", - "`ip6tables -w -I INPUT -p tcp -m set --match-set f2b-j-w-iptables-ipset-ap6 src -j REJECT --reject-with icmp6-port-unreachable`", + "`{ ip6tables -w -C INPUT -p tcp -m set --match-set f2b-j-w-iptables-ipset-ap6 src -j REJECT --reject-with icmp6-port-unreachable >/dev/null 2>&1; } || " + "{ ip6tables -w -I INPUT -p tcp -m set --match-set f2b-j-w-iptables-ipset-ap6 src -j REJECT --reject-with icmp6-port-unreachable; }", ), 'flush': ( "`ipset flush f2b-j-w-iptables-ipset-ap`", @@ -1678,14 +1686,16 @@ class ServerConfigReaderTests(LogCaptureTestCase): ('j-w-iptables', 'iptables[name=%(__name__)s, bantime="10m", port="http", protocol="tcp", chain=""]', { 'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'), 'ip4-start': ( - "`iptables -w -N f2b-j-w-iptables`", - "`iptables -w -A f2b-j-w-iptables -j RETURN`", - "`iptables -w -I INPUT -p tcp --dport http -j f2b-j-w-iptables`", + "`{ iptables -w -C f2b-j-w-iptables -j RETURN >/dev/null 2>&1; } || " + "{ iptables -w -N f2b-j-w-iptables || true; iptables -w -A f2b-j-w-iptables -j RETURN; }", + "`{ iptables -w -C INPUT -p tcp --dport http -j f2b-j-w-iptables >/dev/null 2>&1; } || " + "{ iptables -w -I INPUT -p tcp --dport http -j f2b-j-w-iptables; }`", ), 'ip6-start': ( - "`ip6tables -w -N f2b-j-w-iptables`", - "`ip6tables -w -A f2b-j-w-iptables -j RETURN`", - "`ip6tables -w -I INPUT -p tcp --dport http -j f2b-j-w-iptables`", + "`{ ip6tables -w -C f2b-j-w-iptables -j RETURN >/dev/null 2>&1; } || " + "{ ip6tables -w -N f2b-j-w-iptables || true; ip6tables -w -A f2b-j-w-iptables -j RETURN; }", + "`{ ip6tables -w -C INPUT -p tcp --dport http -j f2b-j-w-iptables >/dev/null 2>&1; } || " + "{ ip6tables -w -I INPUT -p tcp --dport http -j f2b-j-w-iptables; }`", ), 'flush': ( "`iptables -w -F f2b-j-w-iptables`", @@ -1722,14 +1732,16 @@ class ServerConfigReaderTests(LogCaptureTestCase): ('j-w-iptables-new', 'iptables-new[name=%(__name__)s, bantime="10m", port="http", protocol="tcp", chain=""]', { 'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'), 'ip4-start': ( - "`iptables -w -N f2b-j-w-iptables-new`", - "`iptables -w -A f2b-j-w-iptables-new -j RETURN`", - "`iptables -w -I INPUT -m state --state NEW -p tcp --dport http -j f2b-j-w-iptables-new`", + "`{ iptables -w -C f2b-j-w-iptables-new -j RETURN >/dev/null 2>&1; } || " + "{ iptables -w -N f2b-j-w-iptables-new || true; iptables -w -A f2b-j-w-iptables-new -j RETURN; }`", + "`{ iptables -w -C INPUT -m state --state NEW -p tcp --dport http -j f2b-j-w-iptables-new >/dev/null 2>&1; } || " + "{ iptables -w -I INPUT -m state --state NEW -p tcp --dport http -j f2b-j-w-iptables-new; }`", ), 'ip6-start': ( - "`ip6tables -w -N f2b-j-w-iptables-new`", - "`ip6tables -w -A f2b-j-w-iptables-new -j RETURN`", - "`ip6tables -w -I INPUT -m state --state NEW -p tcp --dport http -j f2b-j-w-iptables-new`", + "`{ ip6tables -w -C f2b-j-w-iptables-new -j RETURN >/dev/null 2>&1; } || " + "{ ip6tables -w -N f2b-j-w-iptables-new || true; ip6tables -w -A f2b-j-w-iptables-new -j RETURN; }`", + "`{ ip6tables -w -C INPUT -m state --state NEW -p tcp --dport http -j f2b-j-w-iptables-new >/dev/null 2>&1; } || " + "{ ip6tables -w -I INPUT -m state --state NEW -p tcp --dport http -j f2b-j-w-iptables-new; }`", ), 'flush': ( "`iptables -w -F f2b-j-w-iptables-new`",