How to resolve "No chain/target/match by that name" when using iptables-multiport and Fail2Ban

This issue isn't specifically related to Fail2Ban but is a common way for it to present itself.

The Fail2Ban log output will show something similar to:

2020-06-22 16:18:09,356 fail2ban.actions        [17988]: ERROR   Failed to execute ban jail 'sasl' action 'iptables-multiport' info 'ActionInfo({'ip': '1.2.3.4', 'fid': <function <lambda> at 0x7f1a0381aa28>, 'family': 'inet4', 'raw-ticket': <function <lambda> at 0x7f1a0381aed8>})': Error starting action Jail('sasl')/iptables-multiport: 'Script error'
2020-06-22 16:18:09,357 fail2ban.actions        [17988]: NOTICE  [sasl] Ban 1.2.3.4
2020-06-22 16:18:09,376 fail2ban.utils          [17988]: ERROR   7f1a0377d3f0 -- exec: iptables -w -N f2b-sasl
iptables -w -A f2b-sasl -j RETURN
iptables -w -I INPUT -p tcp -m multiport --dports 25,587 -j f2b-sasl
2020-06-22 16:18:09,376 fail2ban.utils          [17988]: ERROR   7f1a0377d3f0 -- stderr: 'iptables: Chain already exists.'
2020-06-22 16:18:09,376 fail2ban.utils          [17988]: ERROR   7f1a0377d3f0 -- stderr: 'iptables: No chain/target/match by that name.'
2020-06-22 16:18:09,377 fail2ban.utils          [17988]: ERROR   7f1a0377d3f0 -- returned 1

The issue is likely caused by using iptables-multiport on a server which doesn't (currently) support it.

Firstly check the command manually to confirm it still errors:

# iptables -w -I INPUT -p tcp -m multiport --dports 25,587 -j f2b-sasl
iptables: No chain/target/match by that name.

Check to see if the iptables-multiport module is loaded:

# cat /proc/net/ip_tables_matches
state
icmp
udplite
udp
tcp

If it's not there, attempt to load it, if available:

# modprobe -v xt_multiport
insmod /lib/modules/2.6.32-754.27.1.el6.x86_64/kernel/net/netfilter/xt_multiport.ko
# cat /proc/net/ip_tables_matches
multiport
multiport
state
icmp
udplite
udp
tcp

If it's now listed, you should be able to add IPTables rules as expected and Fail2Ban should work. If not, and a reboot doesn't help, you'll need to modify Fail2Ban to not use multiport.

One way to do this is to add a custom iptables action and split the ports manually. Create actions.d/iptables-custom-multi.conf with the following content:

# Fail2Ban configuration file for legacy IPTables multiport support
#
# Author: James Lawrie <james@silvermouse.net>
#
#

[INCLUDES]

before = iptables-common.conf

[Definition]

# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
#
actionstart = <iptables> -N f2b-<name>
              <iptables> -A f2b-<name> -j <returntype>
              echo <port> | sed -n 1'p' | tr ',' '\n' | while read port; do
                  <iptables> -I <chain> -p <protocol> --dport $port -j f2b-<name>
              done

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
#
actionstop = echo <port> | sed -n 1'p' | tr ',' '\n' | while read port; do
                 <iptables> -D <chain> -p <protocol> --dport $port -j f2b-<name>
             done
             <iptables> -F f2b-<name>
             <iptables> -X f2b-<name>

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck = <iptables> -n -L <chain> | grep -q 'f2b-<name>[ \t]'

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionban = <iptables> -I f2b-<name> 1 -s <ip> -j <blocktype>

# Option:  actionunban
# Notes.:  command executed when unbanning an IP. Take care that the
#          command is executed with Fail2Ban user rights.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionunban = <iptables> -D f2b-<name> -s <ip> -j <blocktype>

[Init]

And then in your jail.local file set the banaction to this new action:

[sasl]
enabled   = true
port      = 25,587
filter    = postfix-sasl
logpath   = /var/log/maillog
banaction = iptables-custom-multi
maxretry  = 10