From 1cda50ce05cc150af8d565301266e910b855959e Mon Sep 17 00:00:00 2001 From: Monson Shao Date: Fri, 3 Nov 2017 20:52:56 +0800 Subject: [PATCH 1/7] Rewrite nftables variables based on nftables' logic. Add an example for redirecting. --- config/action.d/nftables-allports.conf | 8 +- config/action.d/nftables-common.conf | 101 ++++++++++++++---------- config/action.d/nftables-multiport.conf | 8 +- 3 files changed, 66 insertions(+), 51 deletions(-) diff --git a/config/action.d/nftables-allports.conf b/config/action.d/nftables-allports.conf index 6c69da39..eb17287a 100644 --- a/config/action.d/nftables-allports.conf +++ b/config/action.d/nftables-allports.conf @@ -13,10 +13,10 @@ before = nftables-common.conf [Definition] -# Option: nftables_mode -# Notes.: additional expressions for nftables filter rule -# Values: nftables expressions +# Option: match +# Notes.: additional matches for nftables filter rule +# Values: nftables matches # -nftables_mode = meta l4proto +match = meta l4proto [Init] diff --git a/config/action.d/nftables-common.conf b/config/action.d/nftables-common.conf index 37045712..4ed78f2f 100644 --- a/config/action.d/nftables-common.conf +++ b/config/action.d/nftables-common.conf @@ -11,6 +11,14 @@ # used in all nftables based actions by default. # # The user can override the defaults in nftables-common.local +# Example: redirect flow to honeypot +# +# [Init] +# table_family = ip +# chain_type = nat +# chain_hook = prerouting +# chain_priority = -50 +# blocktype = counter redirect to 2222 [INCLUDES] @@ -18,35 +26,38 @@ after = nftables-common.local [Definition] -# Option: nftables_mode -# Notes.: additional expressions for nftables filter rule -# Values: nftables expressions +# Option: match +# Notes.: additional matches for nftables filter rule. +# leaving it empty will block all. (include udp and icmp) +# Values: nftables matches # -nftables_mode = dport \{ \} +match = dport \{ \} # 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). # Values: CMD # -actionstart = add set \{ type \; \} - insert rule %(nftables_mode)s saddr @ +actionstart = add table f2b-table + -- add chain f2b-table f2b-chain \{ type hook priority \; \} + add set f2b-table \{ type \; \} + add rule f2b-table f2b-chain %(match)s saddr @ -_nft_list = --handle --numeric list chain -_nft_get_handle_id = grep -m1 ' saddr @ # handle' | grep -oe ' handle [0-9]*' +_nft_list = -a list chain f2b-table f2b-chain +_nft_get_handle_id = grep -m1 '@ ' | grep -oe ' handle [0-9]*' # Option: actionstop # Notes.: command executed at the stop of jail (or at the end of Fail2Ban) # Values: CMD # actionstop = HANDLE_ID=$(%(_nft_list)s | %(_nft_get_handle_id)s) - delete rule $HANDLE_ID - delete set + delete rule f2b-table f2b-chain $HANDLE_ID + delete set f2b-table # Option: actioncheck # Notes.: command executed once before each actionban command # Values: CMD # -actioncheck = list chain | grep -q '@[ \t]' +actioncheck = list chain f2b-table f2b-chain | grep -q '@[ \t]' # Option: actionban # Notes.: command executed when banning an IP. Take care that the @@ -54,7 +65,7 @@ actioncheck = list chain | # Tags: See jail.conf(5) man page # Values: CMD # -actionban = add element \{ \} +actionban = add element f2b-table # Option: actionunban # Notes.: command executed when unbanning an IP. Take care that the @@ -62,33 +73,38 @@ actionban = add element # Tags: See jail.conf(5) man page # Values: CMD # -actionunban = delete element \{ \} +actionunban = delete element f2b-table [Init] -# Option: nftables_type +# Option: table_family +# Notes.: address family to work in +# Values: [ip | ip6 | inet] Default: inet +table_family = inet + +# Option: chain_type +# Notes.: refers to the kind of chain to be created +# Values: [filter | route | nat] Default: filter +# +chain_type = filter + +# Option: chain_hook +# Notes.: refers to the kind of chain to be created +# Values: [ prerouting | input | forward | output | postrouting ] Default: input +# +chain_hook = input + +# Option: chain_priority +# Notes.: priority in the chain. +# Values: NUMBER Default: -1 +# +chain_priority = -1 + +# Option: addr_type # Notes.: address type to work with # Values: [ipv4_addr | ipv6_addr] Default: ipv4_addr # -nftables_type = ipv4_addr - -# Option: nftables_family -# Notes.: address family to work in -# Values: [ip | ip6 | inet] Default: inet -# -nftables_family = inet - -# Option: nftables_table -# Notes.: table in the address family to work in -# Values: STRING Default: filter -# -nftables_table = filter - -# Option: chain -# Notes specifies the nftables chain to which the Fail2Ban rules should be -# added -# Values: STRING Default: input -chain = input +addr_type = ipv4_addr # Default name of the filtering set # @@ -108,8 +124,8 @@ protocol = tcp # Option: blocktype # Note: This is what the action does with rules. This can be any jump target -# as per the nftables man page (section 8). Common values are drop -# reject, reject with icmp type host-unreachable +# as per the nftables man page (section 8). Common values are drop, +# reject, reject with icmpx type host-unreachable, redirect to 2222 # Values: STRING blocktype = reject @@ -118,18 +134,17 @@ blocktype = reject # Values: STRING nftables = nft -# Option: set_name +# Option: addr_set # Notes.: The name of the nft set used to store banned addresses # Values: STRING -set_name = f2b- +addr_set = addr-set- -# Option: address_family +# Option: addr_family # Notes.: The family of the banned addresses # Values: [ ip | ip6 ] -address_family = ip +addr_family = ip [Init?family=inet6] - -nftables_type = ipv6_addr -set_name = f2b-6 -address_family = ip6 +addr_family = ip6 +addr_type = ipv6_addr +addr_set = addr6-set- diff --git a/config/action.d/nftables-multiport.conf b/config/action.d/nftables-multiport.conf index d1afafb3..6e3775ae 100644 --- a/config/action.d/nftables-multiport.conf +++ b/config/action.d/nftables-multiport.conf @@ -13,10 +13,10 @@ before = nftables-common.conf [Definition] -# Option: nftables_mode -# Notes.: additional expressions for nftables filter rule -# Values: nftables expressions +# Option: match +# Notes.: additional matches for nftables filter rule +# Values: nftables matches # -nftables_mode = dport \{ \} +match = dport \{ \} [Init] From dde51b46820a3cf66b79667cc75a00f8465353af Mon Sep 17 00:00:00 2001 From: Ririsoft Date: Sat, 6 Oct 2018 15:06:14 +0200 Subject: [PATCH 2/7] fix actionban/unban ip definition syntax --- config/action.d/nftables-common.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/action.d/nftables-common.conf b/config/action.d/nftables-common.conf index 4ed78f2f..6765fbb3 100644 --- a/config/action.d/nftables-common.conf +++ b/config/action.d/nftables-common.conf @@ -65,7 +65,7 @@ actioncheck = list chain f2b-table f2b-chain | grep -q # Tags: See jail.conf(5) man page # Values: CMD # -actionban = add element f2b-table +actionban = add element f2b-table { } # Option: actionunban # Notes.: command executed when unbanning an IP. Take care that the @@ -73,7 +73,7 @@ actionban = add element f2b-table # Tags: See jail.conf(5) man page # Values: CMD # -actionunban = delete element f2b-table +actionunban = delete element f2b-table { } [Init] From c59d49da225d415428847d97d86e853b79d7a884 Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 24 Sep 2019 18:46:41 +0200 Subject: [PATCH 3/7] nftables-allports: support multiple protocols in single rule; tests/servertestcase.py: added coverage for nftables actions --- config/action.d/nftables-allports.conf | 2 +- fail2ban/tests/servertestcase.py | 94 +++++++++++++++++++++++++- 2 files changed, 93 insertions(+), 3 deletions(-) diff --git a/config/action.d/nftables-allports.conf b/config/action.d/nftables-allports.conf index eb17287a..fad5273a 100644 --- a/config/action.d/nftables-allports.conf +++ b/config/action.d/nftables-allports.conf @@ -17,6 +17,6 @@ before = nftables-common.conf # Notes.: additional matches for nftables filter rule # Values: nftables matches # -match = meta l4proto +match = meta l4proto \{ \} [Init] diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 4d4362db..6375ea24 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -1256,6 +1256,96 @@ class ServerConfigReaderTests(LogCaptureTestCase): # 'start', 'stop' - should be found (logged) on action start/stop, # etc. testJailsActions = ( + # nftables-multiport -- + ('j-w-nft-mp', 'nftables-multiport[name=%(__name__)s, port="http,https", protocol="tcp"]', { + 'ip4': ('ip ', 'ipv4_addr', 'addr-'), 'ip6': ('ip6 ', 'ipv6_addr', 'addr6-'), + '*-start': ( + r"`nft add table inet f2b-table`", + r"`nft -- add chain inet f2b-table f2b-chain \{ type filter hook input priority -1 \; \}`", + ), + 'ip4-start': ( + r"`nft add set inet f2b-table addr-set-j-w-nft-mp \{ type ipv4_addr\; \}`", + r"`nft add rule inet f2b-table f2b-chain tcp dport \{ http,https \} ip saddr @addr-set-j-w-nft-mp reject`", + ), + 'ip6-start': ( + r"`nft add set inet f2b-table addr6-set-j-w-nft-mp \{ type ipv6_addr\; \}`", + r"`nft add rule inet f2b-table f2b-chain tcp dport \{ http,https \} ip6 saddr @addr6-set-j-w-nft-mp reject`", + ), + 'flush': ( + # todo + ), + 'stop': ( + "`HANDLE_ID=$(nft -a list chain inet f2b-table f2b-chain | grep -m1 '@addr-set-j-w-nft-mp ' | grep -oe ' handle [0-9]*')`", + "`nft delete rule inet f2b-table f2b-chain $HANDLE_ID`", + "`nft delete set inet f2b-table addr-set-j-w-nft-mp`", + "`HANDLE_ID=$(nft -a list chain inet f2b-table f2b-chain | grep -m1 '@addr6-set-j-w-nft-mp ' | grep -oe ' handle [0-9]*')`", + "`nft delete rule inet f2b-table f2b-chain $HANDLE_ID`", + "`nft delete set inet f2b-table addr6-set-j-w-nft-mp`", + ), + 'ip4-check': ( + r"`nft list chain inet f2b-table f2b-chain | grep -q '@addr-set-j-w-nft-mp[ \t]'`", + ), + 'ip6-check': ( + r"`nft list chain inet f2b-table f2b-chain | grep -q '@addr6-set-j-w-nft-mp[ \t]'`", + ), + 'ip4-ban': ( + r"`nft add element inet f2b-table addr-set-j-w-nft-mp { 192.0.2.1 }`", + ), + 'ip4-unban': ( + r"`nft delete element inet f2b-table addr-set-j-w-nft-mp { 192.0.2.1 }`", + ), + 'ip6-ban': ( + r"`nft add element inet f2b-table addr6-set-j-w-nft-mp { 2001:db8:: }`", + ), + 'ip6-unban': ( + r"`nft delete element inet f2b-table addr6-set-j-w-nft-mp { 2001:db8:: }`", + ), + }), + # nft-allports -- + ('j-w-nft-ap', 'nftables-allports[name=%(__name__)s, protocol="tcp,udp"]', { + 'ip4': ('ip ', 'ipv4_addr', 'addr-'), 'ip6': ('ip6 ', 'ipv6_addr', 'addr6-'), + '*-start': ( + r"`nft add table inet f2b-table`", + r"`nft -- add chain inet f2b-table f2b-chain \{ type filter hook input priority -1 \; \}`", + ), + 'ip4-start': ( + r"`nft add set inet f2b-table addr-set-j-w-nft-ap \{ type ipv4_addr\; \}`", + r"`nft add rule inet f2b-table f2b-chain meta l4proto \{ tcp,udp \} ip saddr @addr-set-j-w-nft-ap reject`", + ), + 'ip6-start': ( + r"`nft add set inet f2b-table addr6-set-j-w-nft-ap \{ type ipv6_addr\; \}`", + r"`nft add rule inet f2b-table f2b-chain meta l4proto \{ tcp,udp \} ip6 saddr @addr6-set-j-w-nft-ap reject`", + ), + 'flush': ( + # todo + ), + 'stop': ( + "`HANDLE_ID=$(nft -a list chain inet f2b-table f2b-chain | grep -m1 '@addr-set-j-w-nft-ap ' | grep -oe ' handle [0-9]*')`", + "`nft delete rule inet f2b-table f2b-chain $HANDLE_ID`", + "`nft delete set inet f2b-table addr-set-j-w-nft-ap`", + "`HANDLE_ID=$(nft -a list chain inet f2b-table f2b-chain | grep -m1 '@addr6-set-j-w-nft-ap ' | grep -oe ' handle [0-9]*')`", + "`nft delete rule inet f2b-table f2b-chain $HANDLE_ID`", + "`nft delete set inet f2b-table addr6-set-j-w-nft-ap`", + ), + 'ip4-check': ( + r"""`nft list chain inet f2b-table f2b-chain | grep -q '@addr-set-j-w-nft-ap[ \t]'`""", + ), + 'ip6-check': ( + r"""`nft list chain inet f2b-table f2b-chain | grep -q '@addr6-set-j-w-nft-ap[ \t]'`""", + ), + 'ip4-ban': ( + r"`nft add element inet f2b-table addr-set-j-w-nft-ap { 192.0.2.1 }`", + ), + 'ip4-unban': ( + r"`nft delete element inet f2b-table addr-set-j-w-nft-ap { 192.0.2.1 }`", + ), + 'ip6-ban': ( + r"`nft add element inet f2b-table addr6-set-j-w-nft-ap { 2001:db8:: }`", + ), + 'ip6-unban': ( + r"`nft delete element inet f2b-table addr6-set-j-w-nft-ap { 2001:db8:: }`", + ), + }), # dummy -- ('j-dummy', 'dummy[name=%(__name__)s, init="==", target="/tmp/fail2ban.dummy"]', { 'ip4': ('family: inet4',), 'ip6': ('family: inet6',), @@ -1847,7 +1937,7 @@ class ServerConfigReaderTests(LogCaptureTestCase): # test ban ip4 : self.pruneLog('# === ban-ipv4 ===') action.ban(ainfo['ip4']) - if tests.get('ip4-start'): self.assertLogged(*tests['ip4-start'], all=True) + if tests.get('ip4-start'): self.assertLogged(*tests.get('*-start', ())+tests['ip4-start'], all=True) if tests.get('ip6-start'): self.assertNotLogged(*tests['ip6-start'], all=True) self.assertLogged(*tests.get('ip4-check',())+tests['ip4-ban'], all=True) self.assertNotLogged(*tests['ip6'], all=True) @@ -1859,7 +1949,7 @@ class ServerConfigReaderTests(LogCaptureTestCase): # test ban ip6 : self.pruneLog('# === ban ipv6 ===') action.ban(ainfo['ip6']) - if tests.get('ip6-start'): self.assertLogged(*tests['ip6-start'], all=True) + if tests.get('ip6-start'): self.assertLogged(*tests.get('*-start', ())+tests['ip6-start'], all=True) if tests.get('ip4-start'): self.assertNotLogged(*tests['ip4-start'], all=True) self.assertLogged(*tests.get('ip6-check',())+tests['ip6-ban'], all=True) self.assertNotLogged(*tests['ip4'], all=True) From c753ffb11d8ad81c03a89398892b0e1870e8707f Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 24 Sep 2019 15:01:58 +0200 Subject: [PATCH 4/7] combine nftables actions to single action: - nftables-common is removed - nftables-allports is obsolete, replaced by nftables[type=allports] - nftables-multiport is obsolete, replaced by nftables[type=multiport] --- config/action.d/nftables-allports.conf | 11 +++------- config/action.d/nftables-multiport.conf | 11 +++------- .../{nftables-common.conf => nftables.conf} | 22 ++++++++++++++----- 3 files changed, 22 insertions(+), 22 deletions(-) rename config/action.d/{nftables-common.conf => nftables.conf} (89%) diff --git a/config/action.d/nftables-allports.conf b/config/action.d/nftables-allports.conf index fad5273a..908abe40 100644 --- a/config/action.d/nftables-allports.conf +++ b/config/action.d/nftables-allports.conf @@ -6,17 +6,12 @@ # Modified: Alexander Belykh # adapted for nftables # +# Obsolete: superseded by nftables[type=allports] [INCLUDES] -before = nftables-common.conf +before = nftables.conf [Definition] -# Option: match -# Notes.: additional matches for nftables filter rule -# Values: nftables matches -# -match = meta l4proto \{ \} - -[Init] +type = allports diff --git a/config/action.d/nftables-multiport.conf b/config/action.d/nftables-multiport.conf index 6e3775ae..ba3ec92c 100644 --- a/config/action.d/nftables-multiport.conf +++ b/config/action.d/nftables-multiport.conf @@ -6,17 +6,12 @@ # Modified: Alexander Belykh # adapted for nftables # +# Obsolete: superseded by nftables[type=multiport] [INCLUDES] -before = nftables-common.conf +before = nftables.conf [Definition] -# Option: match -# Notes.: additional matches for nftables filter rule -# Values: nftables matches -# -match = dport \{ \} - -[Init] +type = multiport \ No newline at end of file diff --git a/config/action.d/nftables-common.conf b/config/action.d/nftables.conf similarity index 89% rename from config/action.d/nftables-common.conf rename to config/action.d/nftables.conf index 6765fbb3..79efbde2 100644 --- a/config/action.d/nftables-common.conf +++ b/config/action.d/nftables.conf @@ -26,12 +26,22 @@ after = nftables-common.local [Definition] -# Option: match -# Notes.: additional matches for nftables filter rule. -# leaving it empty will block all. (include udp and icmp) -# Values: nftables matches +# Option: type +# Notes.: type of the action. +# Values: [ multiport | allports ] Default: multiport # -match = dport \{ \} +type = multiport + +rule_match-allports = meta l4proto \{ \} +rule_match-multiport = dport \{ \} +match = > + +# Option: rule_stat +# Notes.: statement for nftables filter rule. +# leaving it empty will block all (include udp and icmp) +# Values: nftables statement +# +rule_stat = %(match)s saddr @ # 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). @@ -40,7 +50,7 @@ match = dport \{ \} actionstart = add table f2b-table -- add chain f2b-table f2b-chain \{ type hook priority \; \} add set f2b-table \{ type \; \} - add rule f2b-table f2b-chain %(match)s saddr @ + add rule f2b-table f2b-chain %(rule_stat)s _nft_list = -a list chain f2b-table f2b-chain _nft_get_handle_id = grep -m1 '@ ' | grep -oe ' handle [0-9]*' From abc4d9fe3713035d31a1a0a169a708d36febb15e Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 24 Sep 2019 19:43:56 +0200 Subject: [PATCH 5/7] allow to use multiple protocols in multiport (single set with multiple rules in chain): `banaction = nftables[type=multiport]` with `protocol="tcp,udp,sctp"` in jail replace 3 separate actions. more robust if deleting multiple references to set (rules in chain) --- config/action.d/nftables.conf | 19 +++++++++++++++---- fail2ban/tests/servertestcase.py | 25 ++++++++++++++----------- 2 files changed, 29 insertions(+), 15 deletions(-) diff --git a/config/action.d/nftables.conf b/config/action.d/nftables.conf index 79efbde2..49e2e917 100644 --- a/config/action.d/nftables.conf +++ b/config/action.d/nftables.conf @@ -32,8 +32,9 @@ after = nftables-common.local # type = multiport +rule_match-custom = rule_match-allports = meta l4proto \{ \} -rule_match-multiport = dport \{ \} +rule_match-multiport = $proto dport \{ \} match = > # Option: rule_stat @@ -43,6 +44,14 @@ match = > # rule_stat = %(match)s saddr @ +# optional interator over protocol's: +_nft_for_proto-custom-iter = +_nft_for_proto-custom-done = +_nft_for_proto-allports-iter = +_nft_for_proto-allports-done = +_nft_for_proto-multiport-iter = for proto in $(echo '' | sed 's/,/ /g'); do +_nft_for_proto-multiport-done = 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). # Values: CMD @@ -50,17 +59,19 @@ rule_stat = %(match)s saddr @ actionstart = add table f2b-table -- add chain f2b-table f2b-chain \{ type hook priority \; \} add set f2b-table \{ type \; \} + <_nft_for_proto--iter> add rule f2b-table f2b-chain %(rule_stat)s + <_nft_for_proto--done> _nft_list = -a list chain f2b-table f2b-chain -_nft_get_handle_id = grep -m1 '@ ' | grep -oe ' handle [0-9]*' +_nft_get_handle_id = grep -oP '@ .* \Khandle (\d+)$' # Option: actionstop # Notes.: command executed at the stop of jail (or at the end of Fail2Ban) # Values: CMD # -actionstop = HANDLE_ID=$(%(_nft_list)s | %(_nft_get_handle_id)s) - delete rule f2b-table f2b-chain $HANDLE_ID +actionstop = $(%(_nft_list)s | %(_nft_get_handle_id)s) | while read -r hdl ; do + delete rule f2b-table f2b-chain $hdl; done delete set f2b-table # Option: actioncheck diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 6375ea24..aaa5c42c 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -1257,29 +1257,32 @@ class ServerConfigReaderTests(LogCaptureTestCase): # etc. testJailsActions = ( # nftables-multiport -- - ('j-w-nft-mp', 'nftables-multiport[name=%(__name__)s, port="http,https", protocol="tcp"]', { + ('j-w-nft-mp', 'nftables-multiport[name=%(__name__)s, port="http,https", protocol="tcp,udp,sctp"]', { 'ip4': ('ip ', 'ipv4_addr', 'addr-'), 'ip6': ('ip6 ', 'ipv6_addr', 'addr6-'), '*-start': ( r"`nft add table inet f2b-table`", r"`nft -- add chain inet f2b-table f2b-chain \{ type filter hook input priority -1 \; \}`", + # iterator over protocol is same for both families: + r"`for proto in $(echo 'tcp,udp,sctp' | sed 's/,/ /g'); do`", + r"`done`", ), 'ip4-start': ( r"`nft add set inet f2b-table addr-set-j-w-nft-mp \{ type ipv4_addr\; \}`", - r"`nft add rule inet f2b-table f2b-chain tcp dport \{ http,https \} ip saddr @addr-set-j-w-nft-mp reject`", + r"`nft add rule inet f2b-table f2b-chain $proto dport \{ http,https \} ip saddr @addr-set-j-w-nft-mp reject`", ), 'ip6-start': ( r"`nft add set inet f2b-table addr6-set-j-w-nft-mp \{ type ipv6_addr\; \}`", - r"`nft add rule inet f2b-table f2b-chain tcp dport \{ http,https \} ip6 saddr @addr6-set-j-w-nft-mp reject`", + r"`nft add rule inet f2b-table f2b-chain $proto dport \{ http,https \} ip6 saddr @addr6-set-j-w-nft-mp reject`", ), 'flush': ( # todo ), 'stop': ( - "`HANDLE_ID=$(nft -a list chain inet f2b-table f2b-chain | grep -m1 '@addr-set-j-w-nft-mp ' | grep -oe ' handle [0-9]*')`", - "`nft delete rule inet f2b-table f2b-chain $HANDLE_ID`", + "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr-set-j-w-nft-mp .* \Khandle (\d+)$') | while read -r hdl`", + "`nft delete rule inet f2b-table f2b-chain $hdl; done`", "`nft delete set inet f2b-table addr-set-j-w-nft-mp`", - "`HANDLE_ID=$(nft -a list chain inet f2b-table f2b-chain | grep -m1 '@addr6-set-j-w-nft-mp ' | grep -oe ' handle [0-9]*')`", - "`nft delete rule inet f2b-table f2b-chain $HANDLE_ID`", + "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr6-set-j-w-nft-mp .* \Khandle (\d+)$') | while read -r hdl`", + "`nft delete rule inet f2b-table f2b-chain $hdl; done`", "`nft delete set inet f2b-table addr6-set-j-w-nft-mp`", ), 'ip4-check': ( @@ -1320,11 +1323,11 @@ class ServerConfigReaderTests(LogCaptureTestCase): # todo ), 'stop': ( - "`HANDLE_ID=$(nft -a list chain inet f2b-table f2b-chain | grep -m1 '@addr-set-j-w-nft-ap ' | grep -oe ' handle [0-9]*')`", - "`nft delete rule inet f2b-table f2b-chain $HANDLE_ID`", + "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr-set-j-w-nft-ap .* \Khandle (\d+)$') | while read -r hdl`", + "`nft delete rule inet f2b-table f2b-chain $hdl; done`", "`nft delete set inet f2b-table addr-set-j-w-nft-ap`", - "`HANDLE_ID=$(nft -a list chain inet f2b-table f2b-chain | grep -m1 '@addr6-set-j-w-nft-ap ' | grep -oe ' handle [0-9]*')`", - "`nft delete rule inet f2b-table f2b-chain $HANDLE_ID`", + "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr6-set-j-w-nft-ap .* \Khandle (\d+)$') | while read -r hdl`", + "`nft delete rule inet f2b-table f2b-chain $hdl; done`", "`nft delete set inet f2b-table addr6-set-j-w-nft-ap`", ), 'ip4-check': ( From 492205d30e514d8a3f1e74c2096ae9cdfe1c63da Mon Sep 17 00:00:00 2001 From: sebres Date: Tue, 24 Sep 2019 20:00:29 +0200 Subject: [PATCH 6/7] action.d/nftables.conf: implemented `actionflush` (allows flushing nftables sets resp. fast unban of all jail tickets at all) --- config/action.d/nftables.conf | 31 ++++++++++++++++++++++--------- fail2ban/tests/servertestcase.py | 6 ++++-- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/config/action.d/nftables.conf b/config/action.d/nftables.conf index 49e2e917..9099f959 100644 --- a/config/action.d/nftables.conf +++ b/config/action.d/nftables.conf @@ -52,27 +52,40 @@ _nft_for_proto-allports-done = _nft_for_proto-multiport-iter = for proto in $(echo '' | sed 's/,/ /g'); do _nft_for_proto-multiport-done = done +_nft_list = -a list chain f2b-table f2b-chain +_nft_get_handle_id = grep -oP '@ .* \Khandle (\d+)$' + +_nft_add_set = add set f2b-table \{ type \; \} + <_nft_for_proto--iter> + add rule f2b-table f2b-chain %(rule_stat)s + <_nft_for_proto--done> +_nft_del_set = $(%(_nft_list)s | %(_nft_get_handle_id)s) | while read -r hdl ; do + delete rule f2b-table f2b-chain $hdl; done + delete set f2b-table + # 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). # Values: CMD # actionstart = add table f2b-table -- add chain f2b-table f2b-chain \{ type hook priority \; \} - add set f2b-table \{ type \; \} - <_nft_for_proto--iter> - add rule f2b-table f2b-chain %(rule_stat)s - <_nft_for_proto--done> + %(_nft_add_set)s -_nft_list = -a list chain f2b-table f2b-chain -_nft_get_handle_id = grep -oP '@ .* \Khandle (\d+)$' +# Option: actionflush +# Notes.: command executed once to flush IPS, by shutdown (resp. by stop of the jail or this action); +# uses `nft flush set ...` and as fallback (e. g. unsupported) recreates the set (with references) +# Values: CMD +# +actionflush = flush set f2b-table || ( + %(_nft_del_set)s + %(_nft_add_set)s + ) # Option: actionstop # Notes.: command executed at the stop of jail (or at the end of Fail2Ban) # Values: CMD # -actionstop = $(%(_nft_list)s | %(_nft_get_handle_id)s) | while read -r hdl ; do - delete rule f2b-table f2b-chain $hdl; done - delete set f2b-table +actionstop = %(_nft_del_set)s # Option: actioncheck # Notes.: command executed once before each actionban command diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index aaa5c42c..55ec75ad 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -1275,7 +1275,8 @@ class ServerConfigReaderTests(LogCaptureTestCase): r"`nft add rule inet f2b-table f2b-chain $proto dport \{ http,https \} ip6 saddr @addr6-set-j-w-nft-mp reject`", ), 'flush': ( - # todo + "`nft flush set inet f2b-table addr-set-j-w-nft-mp || ", + "`nft flush set inet f2b-table addr6-set-j-w-nft-mp || ", ), 'stop': ( "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr-set-j-w-nft-mp .* \Khandle (\d+)$') | while read -r hdl`", @@ -1320,7 +1321,8 @@ class ServerConfigReaderTests(LogCaptureTestCase): r"`nft add rule inet f2b-table f2b-chain meta l4proto \{ tcp,udp \} ip6 saddr @addr6-set-j-w-nft-ap reject`", ), 'flush': ( - # todo + "`nft flush set inet f2b-table addr-set-j-w-nft-ap || ", + "`nft flush set inet f2b-table addr6-set-j-w-nft-ap || ", ), 'stop': ( "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr-set-j-w-nft-ap .* \Khandle (\d+)$') | while read -r hdl`", From 8ea00c1d5db34366ef55ca9e6441b55e48d157c5 Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 25 Sep 2019 13:47:29 +0200 Subject: [PATCH 7/7] fixed mistake in config (semicolon after space as comment in configs?) and coverage, suppress errors by unsupported flush, better space handling in helper _nft_get_handle_id, etc --- config/action.d/nftables.conf | 6 +++--- fail2ban/tests/servertestcase.py | 16 ++++++++-------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/config/action.d/nftables.conf b/config/action.d/nftables.conf index 9099f959..e7186c47 100644 --- a/config/action.d/nftables.conf +++ b/config/action.d/nftables.conf @@ -53,13 +53,13 @@ _nft_for_proto-multiport-iter = for proto in $(echo '' | sed 's/,/ /g' _nft_for_proto-multiport-done = done _nft_list = -a list chain f2b-table f2b-chain -_nft_get_handle_id = grep -oP '@ .* \Khandle (\d+)$' +_nft_get_handle_id = grep -oP '@\s+.*\s+\Khandle\s+(\d+)$' _nft_add_set = add set f2b-table \{ type \; \} <_nft_for_proto--iter> add rule f2b-table f2b-chain %(rule_stat)s <_nft_for_proto--done> -_nft_del_set = $(%(_nft_list)s | %(_nft_get_handle_id)s) | while read -r hdl ; do +_nft_del_set = (%(_nft_list)s | %(_nft_get_handle_id)s) | while read -r hdl; do delete rule f2b-table f2b-chain $hdl; done delete set f2b-table @@ -76,7 +76,7 @@ actionstart = add table f2b-table # uses `nft flush set ...` and as fallback (e. g. unsupported) recreates the set (with references) # Values: CMD # -actionflush = flush set f2b-table || ( +actionflush = ( flush set f2b-table 2> /dev/null) || ( %(_nft_del_set)s %(_nft_add_set)s ) diff --git a/fail2ban/tests/servertestcase.py b/fail2ban/tests/servertestcase.py index 55ec75ad..901b7399 100644 --- a/fail2ban/tests/servertestcase.py +++ b/fail2ban/tests/servertestcase.py @@ -1275,14 +1275,14 @@ class ServerConfigReaderTests(LogCaptureTestCase): r"`nft add rule inet f2b-table f2b-chain $proto dport \{ http,https \} ip6 saddr @addr6-set-j-w-nft-mp reject`", ), 'flush': ( - "`nft flush set inet f2b-table addr-set-j-w-nft-mp || ", - "`nft flush set inet f2b-table addr6-set-j-w-nft-mp || ", + "`(nft flush set inet f2b-table addr-set-j-w-nft-mp 2> /dev/null) || ", + "`(nft flush set inet f2b-table addr6-set-j-w-nft-mp 2> /dev/null) || ", ), 'stop': ( - "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr-set-j-w-nft-mp .* \Khandle (\d+)$') | while read -r hdl`", + "`(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr-set-j-w-nft-mp\s+.*\s+\Khandle\s+(\d+)$') | while read -r hdl; do`", "`nft delete rule inet f2b-table f2b-chain $hdl; done`", "`nft delete set inet f2b-table addr-set-j-w-nft-mp`", - "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr6-set-j-w-nft-mp .* \Khandle (\d+)$') | while read -r hdl`", + "`(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr6-set-j-w-nft-mp\s+.*\s+\Khandle\s+(\d+)$') | while read -r hdl; do`", "`nft delete rule inet f2b-table f2b-chain $hdl; done`", "`nft delete set inet f2b-table addr6-set-j-w-nft-mp`", ), @@ -1321,14 +1321,14 @@ class ServerConfigReaderTests(LogCaptureTestCase): r"`nft add rule inet f2b-table f2b-chain meta l4proto \{ tcp,udp \} ip6 saddr @addr6-set-j-w-nft-ap reject`", ), 'flush': ( - "`nft flush set inet f2b-table addr-set-j-w-nft-ap || ", - "`nft flush set inet f2b-table addr6-set-j-w-nft-ap || ", + "`(nft flush set inet f2b-table addr-set-j-w-nft-ap 2> /dev/null) || ", + "`(nft flush set inet f2b-table addr6-set-j-w-nft-ap 2> /dev/null) || ", ), 'stop': ( - "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr-set-j-w-nft-ap .* \Khandle (\d+)$') | while read -r hdl`", + "`(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr-set-j-w-nft-ap\s+.*\s+\Khandle\s+(\d+)$') | while read -r hdl; do`", "`nft delete rule inet f2b-table f2b-chain $hdl; done`", "`nft delete set inet f2b-table addr-set-j-w-nft-ap`", - "`$(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr6-set-j-w-nft-ap .* \Khandle (\d+)$') | while read -r hdl`", + "`(nft -a list chain inet f2b-table f2b-chain | grep -oP '@addr6-set-j-w-nft-ap\s+.*\s+\Khandle\s+(\d+)$') | while read -r hdl; do`", "`nft delete rule inet f2b-table f2b-chain $hdl; done`", "`nft delete set inet f2b-table addr6-set-j-w-nft-ap`", ),