In this tutorial, we'll develop a script that will get all the IP addresses blocked by
fail2ban
on the ssh
chain and then add them to an ipset
that will be automatically
blocked by iptables.
Talk about power traffic management!
One of the most frustrating parts about running a web hosting company is the exposure to spam and bad bot traffic. At my old hosting company, I often had to scrub through IP logs to determine what traffic was legitimate and what traffic should have been blocked outright. In fact, more web hosting companies could do this but they choose not to because more traffic = more money.
If you've read any of my other tutorials, you know I have a folder full of tools that
I developed to help manage my servers. One of them is an automatic bad bot and spam traffic
filter script, which I call scrub_fail2ban.sh
. This script will perform three primary functions:
-
Build a list of IPs to scrub based off of the IPs blocked by fail2ban -- specifically, this script will create a list of IPs added by fail2ban to the
fail2ban-ssh
chain. These are IPs that failed to login via SSH; since I don't allow SSH access to my clients, I know exactly what IPs should be accessing my boxes. -
Add the offending IPs to an
ipset
, which is a very fast, very efficient way of blocking tens of thousands of IP addresses at a time. -
Restart the fail2ban service so that the network is not bogged down by too many entries in the iptables' raw DROP chain.
Here's the code:
#!/bin/bash
# This script will spit out all of the IPs that have been blocked by fail2ban-ssh,
# then for each one, add it to our `ipset blacklist`. It will then restart fail2ban
# to flush the fail2ban-ssh drop chain.
# Build the ipset if it's not already built
ipset create blacklist hash:ip
# Build a list of IPs to scrub
iptables -L fail2ban-ssh -v -n | grep -E '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | awk '{print $8}' > blockthese.txt
# Read that list into an array
declare -a scrublist
readarray -t scrublist > blockthese.txt
# loop through each IP address in the array
for i in "${scrublist[@]}"
do
# Add that IP to the blacklist
echo -e "Adding $i to blacklist...\n"
ipset add blacklist $i
done
echo -e "All finished."
# Delete the temporary file we just made
rm blockthese.txt
# Just in case, we'll reissue the iptables rule to drop all from the blacklist set
iptables -I INPUT -m set --match-set blacklist src -p TCP --destination-port 80 -j DROP
# Now we'll restart fail2ban
sudo service fail2ban restart
# And that's it!
You'll notice that this code will attempt to build the ipset regardless of whether or not it exists. It does the same thing with the iptable DROP entry for the blacklist ipset. Both of these are failsafes and will not affect anything if they throw an error.
To make this run nightly, go to crontab (crontab -e [hit enter]
) and add an entry like this:
30 2 * * * /var/your_tools/scrub_fail2ban.sh
Good luck with your traffic management!
-Jesse