I’ve recently had a flood of botnet-driven brute force attempts against my SMTP server. After struggling with some Fail2ban configuration issues, I’d gotten it working smoothly. However, this was a particularly persistent botnet, and as soon as the ban expired, I’d get more entry attempts. This is a problem; I want hackers to be thwarted, so I can’t set ban times too low; but I do not want to lock out my users if they legitimately forget a password. After putting up with my mailbox being flooded with Fail2ban reports, I decided to look into increasing times for subsequent bans. Fail2ban does not support this natively, so I had to look into other options.
The solution I came up with, after trying various complicated methods, is so simple that I feel stupid for not having done it in the first place. All I did was create a filter that parses Fail2ban’s own log, searching for bans. I then created a series of jails and set incrementing “maxretry” variables, with increased find and ban times.
The result of the following example is that, if a service on my server receives 5 failed password attempts in a day, the IP is banned for three hours. If this happens twice in a week, it is banned for a day. Thrice in a month, banned for a week, and so on. All of these values can be adjusted, and I’m still playing with them to find settings I like on my own server, but so far the system works brilliantly well.
First, create file: /etc/fail2ban/filter.d/f2b-loop.conf
# Fail2Ban configuration file for subsequent bans # [INCLUDES] before = common.conf [Definition] failregex = \]\s+Ban\s+<HOST> ignoreregex = \[f2b-loop.*\]\s+Ban\s+<HOST> # # Author: Walter Heitman Jr. http://blog.shanock.com
Now append/incorporate these entries into /etc/fail2ban/jail.local. Do not replace your existing file. Modify the values to your own preferences.
[DEFAULT] bantime = 10800 ;3 hours findtime = 86400 ;1 day maxretry = 5 [f2b-loop2] enabled = true filter = f2b-loop bantime = 86400 ;1 day findtime = 604800 ;1 week logpath = /var/log/fail2ban.log maxretry = 2 [f2b-loop3] enabled = true filter = f2b-loop bantime = 604800 ;1 week findtime = 2592000 ;1 month logpath = /var/log/fail2ban.log maxretry = 3 [f2b-loop4] enabled = true filter = f2b-loop bantime = 2592000 ;1 month findtime = 15552000 ;6 months logpath = /var/log/fail2ban.log maxretry = 6 [f2b-loop5] enabled = true filter = f2b-loop bantime = 15552000 ;6 months findtime = 31536000 ;1 year logpath = /var/log/fail2ban.log maxretry = 9
You may add or remove jails, but the naming scheme must be maintained. The reason is that the filter ignores entries from [f2b-loop*] in order to avoid unintended interactions with itself. This solution was developed under Gentoo Linux, running Fail2ban version 0.9.0-r1, and may require modification for other distros and versions*. I have also set dbpurgeage=31536000 in fail2ban.conf; I don’t know if this makes a difference.
* It has been brought to my attention that some distributions do not supply configuration files with a default “action=” parameter under “[default]”. You will need to add this, either to “[default]” or to each “[f2b-loop*]” jail.
Another reader pointed out that Fedora uses firewall-cmd instead of iptables to do its banning, but it is not capable of 1-year timeouts. The 5th loop in this example will have to be modified or removed. It may also be necessary to adjust the ignoreregex parameter.