From 139151ec8178dbbefcbaf42ea8694b50c10573d5 Mon Sep 17 00:00:00 2001 From: Arnaud Date: Fri, 27 Dec 2024 11:34:59 +0100 Subject: [PATCH 1/5] Update iptables.conf - allow bans to be efective on multiple chains at the same time This patch allows the ban to be applied on the INPUT and the FORWARD chain at the time. May be useful at least on routing devices and on docker hosting machines. --- config/action.d/iptables.conf | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/config/action.d/iptables.conf b/config/action.d/iptables.conf index c8314b9d..462e3ce4 100644 --- a/config/action.d/iptables.conf +++ b/config/action.d/iptables.conf @@ -65,22 +65,30 @@ rule-jump = -j <_ipt_rule_target> # Several capabilities used internally: _ipt_for_proto-iter = for proto in $(echo '' | sed 's/,/ /g'); do +_ipt_for_chain-iter = for chain in $(echo '' | sed 's/,/ /g'); do +_ipt_for_chain-done = done; _ipt_for_proto-done = done _ipt_add_rules = <_ipt_for_proto-iter> - { %(_ipt_check_rule)s >/dev/null 2>&1; } || { -I %(_ipt_chain_rule)s; } + <_ipt_for_chain-iter> + { %(_ipt_check_rule)s >/dev/null 2>&1; } || { -I $chain %(_ipt_chain_rule)s; } + <_ipt_for_chain-done> <_ipt_for_proto-done> _ipt_del_rules = <_ipt_for_proto-iter> - -D %(_ipt_chain_rule)s + <_ipt_for_chain-iter> + -D $chain %(_ipt_chain_rule)s + <_ipt_for_chain-done> <_ipt_for_proto-done> _ipt_check_rules = <_ipt_for_proto-iter> + <_ipt_for_chain-iter> %(_ipt_check_rule)s + <_ipt_for_chain-done> <_ipt_for_proto-done> _ipt_chain_rule = /_chain_rule> -_ipt_check_rule = -C %(_ipt_chain_rule)s +_ipt_check_rule = -C $chain %(_ipt_chain_rule)s _ipt_rule_target = f2b- [ipt_oneport] @@ -98,11 +106,12 @@ _chain_rule = -p $proto [Init] -# Option: chain -# Notes specifies the iptables chain to which the Fail2Ban rules should be -# added +# Option: chains +# Notes specifies the iptables chains to which the Fail2Ban rules should be +# added. May be a sigle chain (eg. INPUT) or a comma separated list +# (eg. INPUT, FORWARD) # Values: STRING Default: INPUT -chain = INPUT +chains = INPUT # Default name of the chain # From 37f72f88ef27e646f4cc8bdc95781ef370dd3b69 Mon Sep 17 00:00:00 2001 From: Arnaud Date: Fri, 27 Dec 2024 23:21:25 +0100 Subject: [PATCH 2/5] Reverting chains to chain in order to preserve backward compatibilityu backing to the option named "chain", using "iteredchain" a new variable to iterate over. --- config/action.d/iptables.conf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/config/action.d/iptables.conf b/config/action.d/iptables.conf index 462e3ce4..f13222bd 100644 --- a/config/action.d/iptables.conf +++ b/config/action.d/iptables.conf @@ -65,19 +65,19 @@ rule-jump = -j <_ipt_rule_target> # Several capabilities used internally: _ipt_for_proto-iter = for proto in $(echo '' | sed 's/,/ /g'); do -_ipt_for_chain-iter = for chain in $(echo '' | sed 's/,/ /g'); do +_ipt_for_chain-iter = for iteredchain in $(echo '' | sed 's/,/ /g'); do _ipt_for_chain-done = done; _ipt_for_proto-done = done _ipt_add_rules = <_ipt_for_proto-iter> <_ipt_for_chain-iter> - { %(_ipt_check_rule)s >/dev/null 2>&1; } || { -I $chain %(_ipt_chain_rule)s; } + { %(_ipt_check_rule)s >/dev/null 2>&1; } || { -I $iteredchain %(_ipt_chain_rule)s; } <_ipt_for_chain-done> <_ipt_for_proto-done> _ipt_del_rules = <_ipt_for_proto-iter> <_ipt_for_chain-iter> - -D $chain %(_ipt_chain_rule)s + -D $iteredchain %(_ipt_chain_rule)s <_ipt_for_chain-done> <_ipt_for_proto-done> @@ -88,7 +88,7 @@ _ipt_check_rules = <_ipt_for_proto-iter> <_ipt_for_proto-done> _ipt_chain_rule = /_chain_rule> -_ipt_check_rule = -C $chain %(_ipt_chain_rule)s +_ipt_check_rule = -C $iteredchain %(_ipt_chain_rule)s _ipt_rule_target = f2b- [ipt_oneport] @@ -106,12 +106,12 @@ _chain_rule = -p $proto [Init] -# Option: chains +# Option: chain # Notes specifies the iptables chains to which the Fail2Ban rules should be # added. May be a sigle chain (eg. INPUT) or a comma separated list # (eg. INPUT, FORWARD) # Values: STRING Default: INPUT -chains = INPUT +chain = INPUT # Default name of the chain # From cbe14c70c5c6330daab362b6d098dcfa9fda1d26 Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 16 Apr 2025 16:56:46 +0200 Subject: [PATCH 3/5] iptables.conf rewritten to affect all derivative actions (multiple chains are also supported by `iptables-ipset` etc); iptables-xt_recent-echo.conf adjusted to be compatible to new syntax of inherited iptables.conf; test coverage fixed to new handling --- config/action.d/iptables-xt_recent-echo.conf | 7 +- config/action.d/iptables.conf | 30 ++--- fail2ban/tests/servertestcase.py | 124 +++++++++---------- 3 files changed, 77 insertions(+), 84 deletions(-) diff --git a/config/action.d/iptables-xt_recent-echo.conf b/config/action.d/iptables-xt_recent-echo.conf index c3c175b3..eba3e4c0 100644 --- a/config/action.d/iptables-xt_recent-echo.conf +++ b/config/action.d/iptables-xt_recent-echo.conf @@ -12,8 +12,9 @@ before = iptables.conf [Definition] _ipt_chain_rule = -m recent --update --seconds 3600 --name -j -_ipt_for_proto-iter = -_ipt_for_proto-done = +_ipt_check_rule = -C %(_ipt_chain_rule)s +_ipt-iter = +_ipt-done = # Option: actionstart # Notes.: command executed on demand at the first ban (or at the start of Fail2Ban if actionstart_on_demand is set to false). @@ -60,7 +61,7 @@ actionstop = echo / > /proc/net/xt_recent/ # Notes.: command executed as invariant check (error by ban) # Values: CMD # -actioncheck = { -C %(_ipt_chain_rule)s; } && test -e /proc/net/xt_recent/ +actioncheck = { %(_ipt_check_rule)s >/dev/null 2>&1; } && test -e /proc/net/xt_recent/ # Option: actionban # Notes.: command executed when banning an IP. Take care that the diff --git a/config/action.d/iptables.conf b/config/action.d/iptables.conf index f13222bd..9511785f 100644 --- a/config/action.d/iptables.conf +++ b/config/action.d/iptables.conf @@ -64,31 +64,23 @@ rule-jump = -j <_ipt_rule_target> # Several capabilities used internally: -_ipt_for_proto-iter = for proto in $(echo '' | sed 's/,/ /g'); do -_ipt_for_chain-iter = for iteredchain in $(echo '' | sed 's/,/ /g'); do -_ipt_for_chain-done = done; -_ipt_for_proto-done = done +_ipt-iter = for chain in $(echo '' | sed 's/,/ /g'); do for proto in $(echo '' | sed 's/,/ /g'); do +_ipt-done = done; done -_ipt_add_rules = <_ipt_for_proto-iter> - <_ipt_for_chain-iter> - { %(_ipt_check_rule)s >/dev/null 2>&1; } || { -I $iteredchain %(_ipt_chain_rule)s; } - <_ipt_for_chain-done> - <_ipt_for_proto-done> +_ipt_add_rules = <_ipt-iter> + { %(_ipt_check_rule)s >/dev/null 2>&1; } || { -I $chain %(_ipt_chain_rule)s; } + <_ipt-done> -_ipt_del_rules = <_ipt_for_proto-iter> - <_ipt_for_chain-iter> - -D $iteredchain %(_ipt_chain_rule)s - <_ipt_for_chain-done> - <_ipt_for_proto-done> +_ipt_del_rules = <_ipt-iter> + -D $chain %(_ipt_chain_rule)s + <_ipt-done> -_ipt_check_rules = <_ipt_for_proto-iter> - <_ipt_for_chain-iter> +_ipt_check_rules = <_ipt-iter> %(_ipt_check_rule)s - <_ipt_for_chain-done> - <_ipt_for_proto-done> + <_ipt-done> _ipt_chain_rule = /_chain_rule> -_ipt_check_rule = -C $iteredchain %(_ipt_chain_rule)s +_ipt_check_rule = -C $chain %(_ipt_chain_rule)s _ipt_rule_target = f2b- [ipt_oneport] diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 6524ea26..347ab9e5 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -1474,38 +1474,38 @@ class ServerConfigReaderTests(LogCaptureTestCase): 'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'), '*-start-stop-check': ( # iterator over protocol is same for both families: - r"`for proto in $(echo 'tcp,udp,sctp' | sed 's/,/ /g'); do`", - r"`done`", + r"`for chain in $(echo 'INPUT' | sed 's/,/ /g'); do for proto in $(echo 'tcp,udp,sctp' | sed 's/,/ /g'); do`", + r"`done; done`", ), 'ip4-start': ( "`{ 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 $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp >/dev/null 2>&1; } || " - "{ iptables -w -I INPUT -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp; }`", + "`{ iptables -w -C $chain -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp >/dev/null 2>&1; } || " + "{ iptables -w -I $chain -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp; }`", ), 'ip6-start': ( "`{ 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 $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp >/dev/null 2>&1; } || ", - "{ ip6tables -w -I INPUT -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp; }`", + "`{ ip6tables -w -C $chain -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp >/dev/null 2>&1; } || ", + "{ ip6tables -w -I $chain -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp; }`", ), 'flush': ( "`iptables -w -F f2b-j-w-iptables-mp`", "`ip6tables -w -F f2b-j-w-iptables-mp`", ), 'stop': ( - "`iptables -w -D INPUT -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp`", + "`iptables -w -D $chain -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp`", "`iptables -w -F f2b-j-w-iptables-mp`", "`iptables -w -X f2b-j-w-iptables-mp`", - "`ip6tables -w -D INPUT -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp`", + "`ip6tables -w -D $chain -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp`", "`ip6tables -w -F f2b-j-w-iptables-mp`", "`ip6tables -w -X f2b-j-w-iptables-mp`", ), 'ip4-check': ( - r"""`iptables -w -C INPUT -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp`""", + r"""`iptables -w -C $chain -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp`""", ), 'ip6-check': ( - r"""`ip6tables -w -C INPUT -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp`""", + r"""`ip6tables -w -C $chain -p $proto -m multiport --dports http,https -j f2b-j-w-iptables-mp`""", ), 'ip4-ban': ( r"`iptables -w -I f2b-j-w-iptables-mp 1 -s 192.0.2.1 -j REJECT --reject-with icmp-port-unreachable`", @@ -1525,38 +1525,38 @@ class ServerConfigReaderTests(LogCaptureTestCase): 'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'), '*-start-stop-check': ( # iterator over protocol is same for both families: - r"`for proto in $(echo 'tcp,udp,sctp' | sed 's/,/ /g'); do`", - r"`done`", + r"`for chain in $(echo 'INPUT' | sed 's/,/ /g'); do for proto in $(echo 'tcp,udp,sctp' | sed 's/,/ /g'); do`", + r"`done; done`", ), 'ip4-start': ( "`{ 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 $proto -j f2b-j-w-iptables-ap >/dev/null 2>&1; } || ", - "{ iptables -w -I INPUT -p $proto -j f2b-j-w-iptables-ap; }`", + "`{ iptables -w -C $chain -p $proto -j f2b-j-w-iptables-ap >/dev/null 2>&1; } || ", + "{ iptables -w -I $chain -p $proto -j f2b-j-w-iptables-ap; }`", ), 'ip6-start': ( "`{ 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 $proto -j f2b-j-w-iptables-ap >/dev/null 2>&1; } || ", - "{ ip6tables -w -I INPUT -p $proto -j f2b-j-w-iptables-ap; }`", + "`{ ip6tables -w -C $chain -p $proto -j f2b-j-w-iptables-ap >/dev/null 2>&1; } || ", + "{ ip6tables -w -I $chain -p $proto -j f2b-j-w-iptables-ap; }`", ), 'flush': ( "`iptables -w -F f2b-j-w-iptables-ap`", "`ip6tables -w -F f2b-j-w-iptables-ap`", ), 'stop': ( - "`iptables -w -D INPUT -p $proto -j f2b-j-w-iptables-ap`", + "`iptables -w -D $chain -p $proto -j f2b-j-w-iptables-ap`", "`iptables -w -F f2b-j-w-iptables-ap`", "`iptables -w -X f2b-j-w-iptables-ap`", - "`ip6tables -w -D INPUT -p $proto -j f2b-j-w-iptables-ap`", + "`ip6tables -w -D $chain -p $proto -j f2b-j-w-iptables-ap`", "`ip6tables -w -F f2b-j-w-iptables-ap`", "`ip6tables -w -X f2b-j-w-iptables-ap`", ), 'ip4-check': ( - r"""`iptables -w -C INPUT -p $proto -j f2b-j-w-iptables-ap`""", + r"""`iptables -w -C $chain -p $proto -j f2b-j-w-iptables-ap`""", ), 'ip6-check': ( - r"""`ip6tables -w -C INPUT -p $proto -j f2b-j-w-iptables-ap`""", + r"""`ip6tables -w -C $chain -p $proto -j f2b-j-w-iptables-ap`""", ), 'ip4-ban': ( r"`iptables -w -I f2b-j-w-iptables-ap 1 -s 192.0.2.1 -j REJECT --reject-with icmp-port-unreachable`", @@ -1576,36 +1576,36 @@ class ServerConfigReaderTests(LogCaptureTestCase): 'ip4': (' f2b-j-w-iptables-ipset ',), 'ip6': (' f2b-j-w-iptables-ipset6 ',), '*-start-stop-check': ( # iterator over protocol is same for both families: - "`for proto in $(echo 'tcp' | sed 's/,/ /g'); do`", - "`done`", + "`for chain in $(echo 'INPUT' | sed 's/,/ /g'); do for proto in $(echo 'tcp' | sed 's/,/ /g'); do`", + "`done; done`", ), 'ip4-start': ( "`ipset -exist create f2b-j-w-iptables-ipset hash:ip timeout 0 maxelem 65536 `", - "`{ iptables -w -C INPUT -p $proto -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 $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset src -j REJECT --reject-with icmp-port-unreachable; }`", + "`{ iptables -w -C $chain -p $proto -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 $chain -p $proto -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 maxelem 65536 family inet6`", - "`{ ip6tables -w -C INPUT -p $proto -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 $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset6 src -j REJECT --reject-with icmp6-port-unreachable; }`", + "`{ ip6tables -w -C $chain -p $proto -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 $chain -p $proto -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`", "`ipset flush f2b-j-w-iptables-ipset6`", ), 'stop': ( - "`iptables -w -D INPUT -p $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset src -j REJECT --reject-with icmp-port-unreachable`", + "`iptables -w -D $chain -p $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset src -j REJECT --reject-with icmp-port-unreachable`", "`ipset flush f2b-j-w-iptables-ipset`", "`ipset destroy f2b-j-w-iptables-ipset 2>/dev/null || { sleep 1; ipset destroy f2b-j-w-iptables-ipset; }`", - "`ip6tables -w -D INPUT -p $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset6 src -j REJECT --reject-with icmp6-port-unreachable`", + "`ip6tables -w -D $chain -p $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset6 src -j REJECT --reject-with icmp6-port-unreachable`", "`ipset flush f2b-j-w-iptables-ipset6`", "`ipset destroy f2b-j-w-iptables-ipset6 2>/dev/null || { sleep 1; ipset destroy f2b-j-w-iptables-ipset6; }`", ), 'ip4-check': ( - r"""`iptables -w -C INPUT -p $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset src -j REJECT --reject-with icmp-port-unreachable`""", + r"""`iptables -w -C $chain -p $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset src -j REJECT --reject-with icmp-port-unreachable`""", ), 'ip6-check': ( - r"""`ip6tables -w -C INPUT -p $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset6 src -j REJECT --reject-with icmp6-port-unreachable`""", + r"""`ip6tables -w -C $chain -p $proto -m multiport --dports http -m set --match-set f2b-j-w-iptables-ipset6 src -j REJECT --reject-with icmp6-port-unreachable`""", ), 'ip4-ban': ( r"`ipset -exist add f2b-j-w-iptables-ipset 192.0.2.1 timeout 0`", @@ -1625,36 +1625,36 @@ class ServerConfigReaderTests(LogCaptureTestCase): 'ip4': (' f2b-j-w-iptables-ipset-ap ',), 'ip6': (' f2b-j-w-iptables-ipset-ap6 ',), '*-start-stop-check': ( # iterator over protocol is same for both families: - "`for proto in $(echo 'tcp' | sed 's/,/ /g'); do`", - "`done`", + "`for chain in $(echo 'INPUT' | sed 's/,/ /g'); do for proto in $(echo 'tcp' | sed 's/,/ /g'); do`", + "`done; done`", ), 'ip4-start': ( "`ipset -exist create f2b-j-w-iptables-ipset-ap hash:ip timeout 0 maxelem 65536 `", - "`{ iptables -w -C INPUT -p $proto -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 $proto -m set --match-set f2b-j-w-iptables-ipset-ap src -j REJECT --reject-with icmp-port-unreachable; }", + "`{ iptables -w -C $chain -p $proto -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 $chain -p $proto -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 maxelem 65536 family inet6`", - "`{ ip6tables -w -C INPUT -p $proto -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 $proto -m set --match-set f2b-j-w-iptables-ipset-ap6 src -j REJECT --reject-with icmp6-port-unreachable; }", + "`{ ip6tables -w -C $chain -p $proto -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 $chain -p $proto -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`", "`ipset flush f2b-j-w-iptables-ipset-ap6`", ), 'stop': ( - "`iptables -w -D INPUT -p $proto -m set --match-set f2b-j-w-iptables-ipset-ap src -j REJECT --reject-with icmp-port-unreachable`", + "`iptables -w -D $chain -p $proto -m set --match-set f2b-j-w-iptables-ipset-ap src -j REJECT --reject-with icmp-port-unreachable`", "`ipset flush f2b-j-w-iptables-ipset-ap`", "`ipset destroy f2b-j-w-iptables-ipset-ap 2>/dev/null || { sleep 1; ipset destroy f2b-j-w-iptables-ipset-ap; }`", - "`ip6tables -w -D INPUT -p $proto -m set --match-set f2b-j-w-iptables-ipset-ap6 src -j REJECT --reject-with icmp6-port-unreachable`", + "`ip6tables -w -D $chain -p $proto -m set --match-set f2b-j-w-iptables-ipset-ap6 src -j REJECT --reject-with icmp6-port-unreachable`", "`ipset flush f2b-j-w-iptables-ipset-ap6`", "`ipset destroy f2b-j-w-iptables-ipset-ap6 2>/dev/null || { sleep 1; ipset destroy f2b-j-w-iptables-ipset-ap6; }`", ), 'ip4-check': ( - r"""`iptables -w -C INPUT -p $proto -m set --match-set f2b-j-w-iptables-ipset-ap src -j REJECT --reject-with icmp-port-unreachable`""", + r"""`iptables -w -C $chain -p $proto -m set --match-set f2b-j-w-iptables-ipset-ap src -j REJECT --reject-with icmp-port-unreachable`""", ), 'ip6-check': ( - r"""`ip6tables -w -C INPUT -p $proto -m set --match-set f2b-j-w-iptables-ipset-ap6 src -j REJECT --reject-with icmp6-port-unreachable`""", + r"""`ip6tables -w -C $chain -p $proto -m set --match-set f2b-j-w-iptables-ipset-ap6 src -j REJECT --reject-with icmp6-port-unreachable`""", ), 'ip4-ban': ( r"`ipset -exist add f2b-j-w-iptables-ipset-ap 192.0.2.1 timeout 0`", @@ -1674,38 +1674,38 @@ class ServerConfigReaderTests(LogCaptureTestCase): 'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'), '*-start-stop-check': ( # iterator over protocol is same for both families: - "`for proto in $(echo 'tcp' | sed 's/,/ /g'); do`", - "`done`", + "`for chain in $(echo 'INPUT' | sed 's/,/ /g'); do for proto in $(echo 'tcp' | sed 's/,/ /g'); do`", + "`done; done`", ), 'ip4-start': ( "`{ 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 $proto --dport http -j f2b-j-w-iptables >/dev/null 2>&1; } || " - "{ iptables -w -I INPUT -p $proto --dport http -j f2b-j-w-iptables; }`", + "`{ iptables -w -C $chain -p $proto --dport http -j f2b-j-w-iptables >/dev/null 2>&1; } || " + "{ iptables -w -I $chain -p $proto --dport http -j f2b-j-w-iptables; }`", ), 'ip6-start': ( "`{ 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 $proto --dport http -j f2b-j-w-iptables >/dev/null 2>&1; } || " - "{ ip6tables -w -I INPUT -p $proto --dport http -j f2b-j-w-iptables; }`", + "`{ ip6tables -w -C $chain -p $proto --dport http -j f2b-j-w-iptables >/dev/null 2>&1; } || " + "{ ip6tables -w -I $chain -p $proto --dport http -j f2b-j-w-iptables; }`", ), 'flush': ( "`iptables -w -F f2b-j-w-iptables`", "`ip6tables -w -F f2b-j-w-iptables`", ), 'stop': ( - "`iptables -w -D INPUT -p $proto --dport http -j f2b-j-w-iptables`", + "`iptables -w -D $chain -p $proto --dport http -j f2b-j-w-iptables`", "`iptables -w -F f2b-j-w-iptables`", "`iptables -w -X f2b-j-w-iptables`", - "`ip6tables -w -D INPUT -p $proto --dport http -j f2b-j-w-iptables`", + "`ip6tables -w -D $chain -p $proto --dport http -j f2b-j-w-iptables`", "`ip6tables -w -F f2b-j-w-iptables`", "`ip6tables -w -X f2b-j-w-iptables`", ), 'ip4-check': ( - r"""`iptables -w -C INPUT -p $proto --dport http -j f2b-j-w-iptables`""", + r"""`iptables -w -C $chain -p $proto --dport http -j f2b-j-w-iptables`""", ), 'ip6-check': ( - r"""`ip6tables -w -C INPUT -p $proto --dport http -j f2b-j-w-iptables`""", + r"""`ip6tables -w -C $chain -p $proto --dport http -j f2b-j-w-iptables`""", ), 'ip4-ban': ( r"`iptables -w -I f2b-j-w-iptables 1 -s 192.0.2.1 -j REJECT --reject-with icmp-port-unreachable`", @@ -1725,38 +1725,38 @@ class ServerConfigReaderTests(LogCaptureTestCase): 'ip4': ('`iptables ', 'icmp-port-unreachable'), 'ip6': ('`ip6tables ', 'icmp6-port-unreachable'), '*-start-stop-check': ( # iterator over protocol is same for both families: - "`for proto in $(echo 'tcp' | sed 's/,/ /g'); do`", - "`done`", + "`for chain in $(echo 'INPUT' | sed 's/,/ /g'); do for proto in $(echo 'tcp' | sed 's/,/ /g'); do`", + "`done; done`", ), 'ip4-start': ( "`{ 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 $proto --dport http -j f2b-j-w-iptables-new >/dev/null 2>&1; } || " - "{ iptables -w -I INPUT -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new; }`", + "`{ iptables -w -C $chain -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new >/dev/null 2>&1; } || " + "{ iptables -w -I $chain -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new; }`", ), 'ip6-start': ( "`{ 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 $proto --dport http -j f2b-j-w-iptables-new >/dev/null 2>&1; } || " - "{ ip6tables -w -I INPUT -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new; }`", + "`{ ip6tables -w -C $chain -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new >/dev/null 2>&1; } || " + "{ ip6tables -w -I $chain -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new; }`", ), 'flush': ( "`iptables -w -F f2b-j-w-iptables-new`", "`ip6tables -w -F f2b-j-w-iptables-new`", ), 'stop': ( - "`iptables -w -D INPUT -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new`", + "`iptables -w -D $chain -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new`", "`iptables -w -F f2b-j-w-iptables-new`", "`iptables -w -X f2b-j-w-iptables-new`", - "`ip6tables -w -D INPUT -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new`", + "`ip6tables -w -D $chain -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new`", "`ip6tables -w -F f2b-j-w-iptables-new`", "`ip6tables -w -X f2b-j-w-iptables-new`", ), 'ip4-check': ( - r"""`iptables -w -C INPUT -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new`""", + r"""`iptables -w -C $chain -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new`""", ), 'ip6-check': ( - r"""`ip6tables -w -C INPUT -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new`""", + r"""`ip6tables -w -C $chain -m state --state NEW -p $proto --dport http -j f2b-j-w-iptables-new`""", ), 'ip4-ban': ( r"`iptables -w -I f2b-j-w-iptables-new 1 -s 192.0.2.1 -j REJECT --reject-with icmp-port-unreachable`", @@ -1791,10 +1791,10 @@ class ServerConfigReaderTests(LogCaptureTestCase): "`fi`", ), 'ip4-check': ( - r"`{ iptables -w -C INPUT -m recent --update --seconds 3600 --name f2b-j-w-iptables-xtre -j REJECT --reject-with icmp-port-unreachable; } && test -e /proc/net/xt_recent/f2b-j-w-iptables-xtre`", + r"`{ iptables -w -C INPUT -m recent --update --seconds 3600 --name f2b-j-w-iptables-xtre -j REJECT --reject-with icmp-port-unreachable >/dev/null 2>&1; } && test -e /proc/net/xt_recent/f2b-j-w-iptables-xtre`", ), 'ip6-check': ( - r"`{ ip6tables -w -C INPUT -m recent --update --seconds 3600 --name f2b-j-w-iptables-xtre6 -j REJECT --reject-with icmp6-port-unreachable; } && test -e /proc/net/xt_recent/f2b-j-w-iptables-xtre6`", + r"`{ ip6tables -w -C INPUT -m recent --update --seconds 3600 --name f2b-j-w-iptables-xtre6 -j REJECT --reject-with icmp6-port-unreachable >/dev/null 2>&1; } && test -e /proc/net/xt_recent/f2b-j-w-iptables-xtre6`", ), 'ip4-ban': ( r"`echo +192.0.2.1 > /proc/net/xt_recent/f2b-j-w-iptables-xtre`", From 0d4a92602980df3e277b73f2f17f607ce954b194 Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 16 Apr 2025 17:13:58 +0200 Subject: [PATCH 4/5] ChangeLog (enhancement and compat entries) --- ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index 47bbc62a..a5a51830 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,9 @@ ver. 1.1.1-dev-1 (20??/??/??) - development nightly edition ----------- ### Compatibility +* `action.d/iptables.conf` rewritten due to support of multiple chains (gh-3909), therefore user-level derivations + (action including iptables-based action) may become incompatible, e. g. some tags if used need to be replaced, + e. g. `` with `$chain` or `<_ipt_for_proto-iter>` with `<_ipt-iter>`; * `filter.d/exim.conf` - several rules of mode `normal` moved to new mode `more`, because of too risky handling (see [gh-3940](https://github.com/fail2ban/fail2ban/pull/3940)), to use it as before set `mode = more` for exim jail, but be aware of the consequences. @@ -74,6 +77,8 @@ ver. 1.1.1-dev-1 (20??/??/??) - development nightly edition `#` or `;` after space or newline would be ignored up to next newline) * `action.d/*-ipset.conf`: - parameter `ipsettype` to set type of ipset, e. g. hash:ip, hash:net, etc (gh-3760) +* `action.d/iptables.conf` - action and few derivatives of it extended to handle multiple chains, + e. g. would also accept `chain = INPUT,FORWARD` (gh-3909) * `action.d/firewallcmd-rich-*.conf` - fixed incorrect quoting, disabling port variable expansion by substitution of rich rule (gh-3815) * `filter.d/proxmox.conf` - add support to Proxmox Web GUI (gh-2966) From 52d239483d193a949b97e72b3ea001aae267528e Mon Sep 17 00:00:00 2001 From: "Sergey G. Brester" Date: Wed, 16 Apr 2025 17:18:36 +0200 Subject: [PATCH 5/5] typo --- config/action.d/iptables.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/action.d/iptables.conf b/config/action.d/iptables.conf index 9511785f..86ac736d 100644 --- a/config/action.d/iptables.conf +++ b/config/action.d/iptables.conf @@ -100,8 +100,8 @@ _chain_rule = -p $proto # Option: chain # Notes specifies the iptables chains to which the Fail2Ban rules should be -# added. May be a sigle chain (eg. INPUT) or a comma separated list -# (eg. INPUT, FORWARD) +# added. May be a single chain (e.g. INPUT) or a comma separated list +# (e.g. INPUT, FORWARD) # Values: STRING Default: INPUT chain = INPUT