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
  

For the opposite (which is to ban), please check the article here.

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

Hi
noob here
I have a moodle site on a gcloud instance
I just setup fail2ban and also I followed the instructions on this article
the only thing I changed was country_list = CO|Colombia|CA|Canada
as I want only users from Colombia and Canada to be able to use my moodle instance.
but when I try to test going to my site from a webproxy sourced in Germany, it still allows the moodle site to show?
am I missing something?
Thank you

Check if your geoiplookup is working. Try to execute:

  
geoiplookup 8.8.8.8 | egrep "US|United States"
  

... the output should be:

  
GeoIP Country Edition: US, United States
  

Try to change the 8.8.8.8 above with IP of the country you want and change "US|United States" as well in egrep.

Hi arpeggio

Thank you for your reply

geoiplookup seems to be working
I got this:
[franciscojaviercortes@centos6 ~]$ geoiplookup 8.8.8.8 | egrep "US|United States"
GeoIP Country Edition: US, United States
GeoIP City Edition, Rev 1: US, N/A, N/A, N/A, N/A, 37.750999, -97.821999, 0, 0
[franciscojaviercortes@centos6 ~]$
---
my jail.local file has this:
[DEFAULT]
#
#default time a user is banned after maxretry login attempts
bantime = 3600
#
[sshd]
enabled = true
#
[sshd-ddos]
banaction = geohostsdeny
enabled = true
# See jail.conf(5) man page for more information
---
and my geohostsdeny.conf file shows this
[Init]

# Option: country_list
# Notes.: List of exempted countries separated by pipe "|"
# Values: STR Default:
#
country_list = CO|Colombia|CA|Canada
...
bad even after restarting fail2ban (which restarts ok), when I try to access my site from a country that is not either Colombia or Canada the site still comes up as you can see here:
https://prnt.sc/o45snk

is there anything else that I'm missing?

Hi arpeggio

I'm sorry, I'm not sure how to create a filter

I see that there's a filter.d folder that have all the configuraiton files used on the jail.conf's params but I though all that was needed to do was to create the action file with the script provided and have this added in the banaction parameter within one of the jails being enabled in our jail.local
what I did try was to create a brand new jail.local that only contains the following:
-sof---
[DEFAULT]
enable = true
filter = DEFAULT
logpath = /var/log/secure
maxretry = 5
bantime = 3600
banaction = geohostsdeny
######################
[sshd]
enabled = true
filter = sshd
action = iptables[name=SSH, port=ssh, protocol=tcp]
logpath = /var/log/secure
findtime = 600
maxretry = 6
bantime = 86400
banaction = geohostsdeny
-eof--
and the action file was created with the same name you indicated within the filter.d folder
[fcortes@centos6 fail2ban]$ ls -l /etc/fail2ban/action.d/ | grep geo*
-rw-r--r--. 1 root root 1582 Jun 19 02:52 geohostsdeny.conf

but after I restart fail to ban and try to access the site from germany with hide-my-ass webproxy, the site still comes up.

if I need to create a filter .conf file within filter.d for what I'm trying to do, is there any guide on how to do so? I guess I could make a copy of the drupal file that it's already there and tweak it for my moodle but tbh I'm not even sure how I would go about doing that.

I thank you so much for your patience and guidance.

Hi Arpeggio

I don't have anything logged in my hosts.deny but fail2ban does show some ip's banned. does that make sense?

franciscojaviercortes@centos6 ~]$ cat /etc/hosts.deny
#
# 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
#
[franciscojaviercortes@centos6 ~]$ sudo fail2ban-client status
Status
|- Number of jail: 1
`- Jail list: sshd
[franciscojaviercortes@centos6 ~]$ sudo fail2ban-client status sshd
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 56
| `- File list: /var/log/secure
`- Actions
|- Currently banned: 13
|- Total banned: 13
`- Banned IP list: 104.248.81.157 128.199.55.17 134.209.10.41 134.209.82.3 134.209.84.42 159.65.148.178 36.92.
21.50 68.183.80.186 68.183.80.232 68.183.95.97 142.93.221.103 142.93.211.234 221.2.158.154

I'm looking to discontinue this vm in the next few months so once I restart elsewhere I will give it another shot, I hope to have better luck at that time
It does appear like something is certainly off with my instance but I can't figure out exactly what that is. That's what prompted me to start looking into fail2ban and other security strategies (I know I should've done that a while ago but well I'm a noob so I guess I gotta bleed before I learn my lesson)
I do thank you again for getting back to me
cheers :)

How would you change the code for checking up geoiplookup6?

I don't understand, my jail.local is full of stuff. And currently, the default is set to banaction = iptables-multiport. How can I add multiple banaction? So I can set like banaction = iptables-multiport, geohostsdeny. Does this work?

If you have multiple countries you want to block, how do I do?

In your /etc/fail2ban/action.d/geohostsdeny.conf, you can do this:

  
country_list = PH|Philippines|SG|Singapore|AU|Australia
  

Excellent article.
In the case of the jail Postfix-sasl, what would it be like?

thank you very much!

Thanks for the article, in my case I only want to block 3 countries.

The procedure describes how to allow countries through: country_list = PH|Philippines , etc.

How can I allow all countries except 2 or 3? So, how can I block only 1 country, for example Singapore?

Yes, Fail2Ban allows you to automate the process of blocking brute-force attacks by limiting the number of failed authentication attempts a user can make before being blocked. You will need to use service specific filter, a log filter. Fail2Ban uses regular expressions to monitor log files for patterns corresponding to authentication failures, seeking for exploits, and other entries that can be considered suspicious.

Thanks for the article. I have read your comment 435: https://www.webfoobar.com/comment/435#comment-435

That is about blocking multiple countries, while I would like to allow specific countries and ban the rest, for any and all ports.

How would I modify the script to allow India and United States; and ban the rest.

jail.local


ignorecache = key="", max-count=100, max-time=5m
ignorecommand = COUNTRY=$(geoiplookup "" | egrep ""); [ "$COUNTRY" ] && exit 0 || exit 1

Debian 11, everything seems to work, the ip not belonging to the geolocation Italy (in my case) are banned. The ip address is successfully added to the /etc/hosts.deny file but connection after the ban is still allowed. I'm using UFW to close affected ports...any suggestions?

Tried it, doesn't work. I've set up country_list = PH|Philippines|IN|India|CN|China|US|United States|KR|South Korea|IR|Iran|RU|Russia|BR|Brazil|AR|Argentina as banned countries and get a bunch of IPs in hosts.deny from Russia, China, the US etc. Really looks like the script doesn't do anything. Moreover, I get about 277 banned IPs in fail2ban Banned IP List for sshd compared to about 100 in hosts.deny.

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.