Blocking IP addresses with ipset

· klm's blog

Instead of using a vast number of iptable rules you can use ipset. This is way faster and easier to maintain.

Original post is here: eklausmeier.goip.de

In Chinese Hackers I mentioned that I block ssh attackers with the help of fail2ban. Unfortunately, fail2ban uses iptables to create firewall rules in "Chain f2b-SSH" for each individual IP address. For a modern processor this is no problem, even if you have thousands of these rules. While for a low powered ARM processer this can have a noticeable influence on network performance. In Using Odroid as IP Router I wrote:

Added 10-Jan-2019: I previously added ca. 3000 iptables rules for blocking IP address ranges which attacked me on port 22 (ssh). That many rules will deteriorate your network performance significantly. My download speed went down from 100 MBit/s to 20 MBit/s.

An alternate or additional approach to this slowdown due to iptables is to use ipset, Arch package ipset. This ipset maintains hash tables of IP addresses or networks. At the time when I still used the Odroid, then the main sshd-server copied the blocked IP addresses to the Odroid, which in turn populated the hash table with the IP addresses to be blocked.

Setting up ipset and populating the hash tables from fail2ban can be done as below.

1sqlite3 -csv /var/lib/fail2ban/fail2ban.sqlite3 "select distinct ip from bips order by ip" |    \
2        perl -e 'BEGIN {print "create reisTmp hash:ip family inet hashsize 65536 maxelem 65536\n"; }
3                print "add reisTmp $_" while (<>);'     \
4        > ~/tmp/reisTmp

The name reisTmp is arbitrary. This way we have a file which looks like this:

1create reisTmp hash:ip family inet hashsize 65536 maxelem 65536
2add reisTmp 1.186.57.150
3add reisTmp 1.193.76.18
4add reisTmp 1.2.206.30
5add reisTmp 1.202.77.210
6add reisTmp 1.214.156.164
7add reisTmp 1.214.245.27
8. . .

This file is transfered from the sshd/fail2ban-server to our router, if required, and is the input to be run through ipset:

1ipset restore -f ~klm/tmp/reisTmp
2ipset swap reisTmp reisbauer
3ipset destroy reisTmp

This assumes you have created a hash table in ipset called reisbauer. Again, this name is arbitrary. Above scenario assumes that populating this hash table takes some time, then just swap hash tables, which is almost instant.

To re-initiate the hash table after reboot, you use

1systemctl enable ipset
2systemctl start ipset

This basically does

1ipset -f /etc/ipset.conf restore

To activate your set for blocking you must tell iptables to check elements in your ipset:

1iptables -t raw -A PREROUTING -i eth0 -p tcp -m tcp --dport 22 -m set --match-set reisbauer src -j DROP