Incremental banning with Fail2Ban

Fail2Ban is a useful tool to keep bad traffic away from your server or VPS. It scans log files for suspicious entries (like failed password entries for SSH logins) and can ban the IPs of these attackers automatically. Naturally if a bot from a certain IP continues to attempt to attack your server or VPS, you would like Fail2Ban to react more strongly over time. No reason such an IP should be banned for one hour (or whatever the “bantime” is set to), unbanned, then banned again for just one hour a moment later and for that to repeat itself endlessly.

Btw, I’m going to assume you’ve already installed and configured Fail2Ban in this article. If you want to know how to do that, just Google it: there are tons of tutorials on setting up Fail2Ban.

Some people got clever and tried to have Fail2Ban parse it’s own log file to implement incremental banning (increasing the ban time with each offense). However as of Fail2Ban v0.10 such hacks aren’t necessary anymore. This version should be available on all recent versions of major Linux server distributions. The recent Ubuntu 20.04 includes v0.11.1 for example.

Have a look at the following section in jail.conf:

[DEFAULT]
# "bantime.increment" allows to use database for searching of previously banned ip's to increase a
# default ban time using special formula, default it is banTime * 1, 2, 4, 8, 16, 32...
#bantime.increment = true

# "bantime.rndtime" is the max number of seconds using for mixing with random time
# to prevent "clever" botnets calculate exact time IP can be unbanned again:
#bantime.rndtime =

# "bantime.maxtime" is the max number of seconds using the ban time can reach (don't grows further)
#bantime.maxtime =

# "bantime.factor" is a coefficient to calculate exponent growing of the formula or common multiplier,
# default value of factor is 1 and with default value of formula, the ban time
# grows by 1, 2, 4, 8, 16 ...
#bantime.factor = 1

# "bantime.formula" used by default to calculate next value of ban time, default value bellow,
# the same ban time growing will be reached by multipliers 1, 2, 4, 8, 16, 32...
#bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor
#
# more aggressive example of formula has the same values only for factor "2.0 / 2.885385" :
#bantime.formula = ban.Time * math.exp(float(ban.Count+1)*banFactor)/math.exp(1*banFactor)

# "bantime.multipliers" used to calculate next value of ban time instead of formula, coresponding
# previously ban count and given "bantime.factor" (for multipliers default is 1);
# following example grows ban time by 1, 2, 4, 8, 16 ... and if last ban count greater as multipliers count,
# always used last multiplier (64 in example), for factor '1' and original ban time 600 - 10.6 hours
#bantime.multipliers = 1 2 4 8 16 32 64
# following example can be used for small initial ban time (bantime=60) - it grows more aggressive at begin,
# for bantime=60 the multipliers are minutes and equal: 1 min, 5 min, 30 min, 1 hour, 5 hour, 12 hour, 1 day, 2 day
#bantime.multipliers = 1 5 30 60 300 720 1440 2880

At first I thought these were defaults — they’re not. You have to declare them specifically if you want to have them enabled. Furthermore don’t just uncomment all lines (which you shouldn’t do anyway, copy them to jail.local instead), as there is duplicate functionality in them. As you can see the bantime.formula and bantime.multipliers settings are not only mentioned twice but the bantime.multipliers setting should be used instead of the bantime.formula setting, so don’t use both.

For example, a relatively simple way to enable incremental banning is to put this in the [DEFAULT] section of jail.local:

bantime.increment = true
bantime.factor = 1
bantime.formula = ban.Time * (1<<(ban.Count if ban.Count<20 else 20)) * banFactor

The first line enables incremental banning and the second one sets the “ban factor” (see explanation in comments above). Finally the third line sets the first of the two formulas that were in the commented out section. After implementing that change and reloading (or restarting) Fail2Ban, I checked the results… and they were very satisfying.

fail2ban.observer [689]: INFO [wordpress-hard] Found x.x.15.15, bad - 2020-05-15 03:10:51, 4 # -> 2, Ban
fail2ban.actions [689]: NOTICE [wordpress-hard] Ban x.x.15.15
fail2ban.observer [689]: INFO [wordpress-hard] IP x.x.15.15 is bad: 4 # last 2020-05-14 19:10:30 - incr 1:00:00 to 16:00:00
fail2ban.observer [689]: NOTICE [wordpress-hard] Increase Ban x.x.15.15 (5 # 16:00:00 -> 2020-05-15 19:10:51)

As you can see a certain offending IP is found for the 4th time, and Fail2Ban increased the bantime for this IP from 1 hour to 16 hours! Nice. If you wonder what the [wordpress-hard] filter is, it’s included in the WordPress plugin WP Fail2Ban Redux.

In conclusion if you already have Fail2Ban set up, you might want to enable incremental banning too. Don’t waste more CPU on bots than necessary.