How to filter by geolocation in Fail2ban

In this article, we will take a look on how to exempt from banning visitors from a specific country using Fail2ban and geoip. It is assumed that Fail2ban is already installed and configured in your server.

Lets install first the geoip:

  
yum install geoip
  

Create Fail2ban action script:

  
vi /etc/fail2ban/action.d/geohostsdeny.conf
  

Copy the following script:

  
[Definition]

# Option:  actionstart
# Notes.:  command executed once at the start of Fail2Ban.
# Values:  CMD
#
actionstart = 

# Option:  actionstop
# Notes.:  command executed once at the end of Fail2Ban
# Values:  CMD
#
actionstop = 

# Option:  actioncheck
# Notes.:  command executed once before each actionban command
# Values:  CMD
#
actioncheck = 

# Option:  actionban
# Notes.:  command executed when banning an IP. Take care that the
#          command is executed with Fail2Ban user rights. 
#          Excludes PH|Philippines from banning.
# Tags:    See jail.conf(5) man page
# Values:  CMD
#
actionban = IP=<ip> &&
            COUNTRY=$(geoiplookup $IP | egrep "<country_list>") && [ "$COUNTRY" ] || 
            (printf %%b "<daemon_list>: $IP\n" >> <file>)

# 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 = IP=<ip> && sed -i.old /ALL:\ $IP/d <file>

[Init]

# Option:  country_list
# Notes.:  List of exempted countries separated by pipe "|"
# Values:  STR  Default:  
#
country_list = PH|Philippines

# Option:  file
# Notes.:  hosts.deny file path.
# Values:  STR  Default:  /etc/hosts.deny
#
file = /etc/hosts.deny

# Option:  daemon_list
# Notes:   The list of services that this action will deny. See the man page
#          for hosts.deny/hosts_access. Default is all services.
# Values:  STR  Default: ALL
daemon_list = ALL
  

The script above will exempt from banning the visitors from Philippines which defined in "country_list".

To enable our action script in Fail2Ban:

  
vi /etc/fail2ban/jail.local
  

... and add the following line in your jail.local file:

  
banaction = geohostsdeny
  

Restart Fail2Ban:

  
systemctl restart fail2ban
  

Comments

I've followed you instruction, however it's not banning from outside country list.

Can you please suggest any other configuration required or any other checklist.

This is my /etc/hosts.deny contents as of today:

  
#
# hosts.deny    This file contains access rules which are used to
#               deny connections to network services that either use
#               the tcp_wrappers library or that have been
#               started through a tcp_wrappers-enabled xinetd.
#
#               The rules in this file can also be set up in
#               /etc/hosts.allow with a 'deny' option instead.
#
#               See 'man 5 hosts_options' and 'man 5 hosts_access'
#               for information on rule syntax.
#               See 'man tcpd' for information on tcp_wrappers
#
ALL: 5.10.115.6
ALL: 158.85.169.152
ALL: 113.28.44.14
ALL: 175.126.103.65
ALL: 106.187.96.51
ALL: 175.45.48.218
ALL: 190.85.89.30
ALL: 223.105.0.129
ALL: 41.254.9.240
ALL: 41.254.9.60
ALL: 37.211.66.180
ALL: 202.3.77.44
ALL: 104.217.216.174
ALL: 104.223.6.154
ALL: 104.223.72.169
ALL: 107.6.166.234
ALL: 122.226.102.202
ALL: 123.176.36.2
ALL: 173.254.236.10
ALL: 180.97.215.154
ALL: 180.97.215.49
ALL: 192.240.106.50
ALL: 198.2.197.153
ALL: 204.151.201.20
ALL: 222.171.107.116
ALL: 222.186.130.243
ALL: 222.186.21.113
ALL: 222.186.21.35
ALL: 222.186.21.52
ALL: 222.186.51.61
ALL: 222.186.58.81
ALL: 222.187.222.35
ALL: 23.253.62.189
ALL: 37.49.226.124
ALL: 42.114.146.128
ALL: 45.32.26.28
ALL: 58.187.135.69
ALL: 58.215.79.87
ALL: 58.218.204.163
ALL: 58.64.155.107
ALL: 61.160.247.11
ALL: 85.125.187.98
  

If you will check each of the IP address, there is no IP address from Philippines banned in my server. This shows that the script in this article works just fine. It was tested for several times before I publish this article.

Make sure you have "filter" enabled in your "jail.local". E.g. in /etc/fail2ban/jail.local:

  
[DEFAULT]
ignoreip = 127.0.0.1/8
maxretry = 3
bantime  = 900
banaction = geohostsdeny
[sshd-ddos]
enabled = true
  

I enabled the filter ssh-ddos. All bad traffic that will be detected by fail2ban and falls under ssh-ddos rules 3 times, fail2ban will ban these IP addresses (except Philippine IP address) for 15 minutes.

fail2ban does not start again with this jail.local since no filter in filter.d is defined. Any suggestions? Moreover, I do not declare deohostdeny as a DEFAULT banaction. Therefore actions, banactions and filter need to set under - in this example - [sshd-ddos].

If I would not define the banaction under [DEFAULT] then I will define it under the specific filter, in my case [sshd-ddos]. Make sure sshd-ddos is enabled.
  
[DEFAULT]
ignoreip = 127.0.0.1/8
maxretry = 3
bantime  = 900
[sshd-ddos]
banaction = geohostsdeny
enabled = true
  

# cat /etc/GeoIP.conf
UserId 999999
LicenseKey 000000000000
ProductIds 506 517 533
Cron update
# cd /etc/cron.weekly/
# cat GeoIP-update.cron
/usr/bin/geoipupdate
# chmod 0755 GeoIP-update

Manual update
# /usr/bin/geoipupdate -v

geoipupdate 2.2.1
Opened License file /etc/GeoIP.conf
UserId 999999
LicenseKey 000000000000
Insert product_id 506
Insert product_id 517
Insert product_id 533
Read in license key /etc/GeoIP.conf
Number of product ids 3
url: https://updates.maxmind.com/app/update_getfilename?product_id=506
md5hex_digest: 1e43a1a5c531cc8e11fb4f83a1c0ec7a
url: https://updates.maxmind.com/app/update_getipaddr
Client IP address: xxx.yyy.zzz.qqq
md5hex_digest2: f2850ecb81886a81b8cb689829f0872a
url: https://updates.maxmind.com/app/update_secure?db_md5=1e43a1a5c531cc8e11fb4f83a1c0ec7a&challenge_md5=f2850ecb81886a81b8cb689829f0872a&user_id=999999&edition_id=506
No new updates available
url: https://updates.maxmind.com/app/update_getfilename?product_id=517
md5hex_digest: 0f1573e51b06f114cfd4f934e37ffd82
url: https://updates.maxmind.com/app/update_getipaddr
Client IP address: xxx.yyy.zzz.qqq
md5hex_digest2: f2850ecb81886a81b8cb689829f0872a
url: https://updates.maxmind.com/app/update_secure?db_md5=0f1573e51b06f114cfd4f934e37ffd82&challenge_md5=f2850ecb81886a81b8cb689829f0872a&user_id=999999&edition_id=517
No new updates available
url: https://updates.maxmind.com/app/update_getfilename?product_id=533
md5hex_digest: 0637ec47d9b4d8107d32e94c35f7f311
url: https://updates.maxmind.com/app/update_getipaddr
Client IP address: xxx.yyy.zzz.qqq
md5hex_digest2: f2850ecb81886a81b8cb689829f0872a
url: https://updates.maxmind.com/app/update_secure?db_md5=0637ec47d9b4d8107d32e94c35f7f311&challenge_md5=f2850ecb81886a81b8cb689829f0872a&user_id=999999&edition_id=533
No new updates available

I still seem to still be getting hits from Russia, but I'll take another look tomorrow. For now, it seems to be working fine. Didn't have to do any weird tricks. Using CentOS 6.9

Just implemented it on multiple Servers - and it's working like a charm! ;-)

Hey there,
thx for your Article - but maybe an approach using "ignorecommand" would be more lean ... ?
Implemented it with "ignorecommand" on multiple Servers and it's working like a charm ... ;-)
bye from Austria
Andreas Schnederle-Wagner

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.