• Home
  • Ubuntu 18.04
    • Whats New?
    • Upgrade Ubuntu
    • Install Java
    • Install Node.js
    • Install Docker
    • Install Git
    • Install LAMP Stack
  • Tutorials
    • AWS
    • Shell Scripting
    • Docker
    • Git
    • MongoDB
  • Funny Tools
  • FeedBack
  • Submit Article
  • About Us
TecAdmin
Menu
  • Home
  • Ubuntu 18.04
    • Whats New?
    • Upgrade Ubuntu
    • Install Java
    • Install Node.js
    • Install Docker
    • Install Git
    • Install LAMP Stack
  • Tutorials
    • AWS
    • Shell Scripting
    • Docker
    • Git
    • MongoDB
  • Funny Tools
  • FeedBack
  • Submit Article
  • About Us

How to Allow SSH/FTP Access Based on Country using GeoIP

Written by Rahul, Updated on October 28, 2020

GeoIP database has the records of Geographical location-based on IP address. Using this database we can search any IP belongs to which country using the Linux command line. This article will help you to allow SSH or FTP (vsftpd) access based on the user’s country. This example uses TCP wrappers to secure your services.

country based ssh access

Install GeoIP and GeoIP Database

First install GeoIP binary for Linux and their database based on your operating system. For CentOS and RedHat users GeoIP binary and database are combined in single package.

On CentOS and RedHat:
sudo yum install GeoIP 
On Ubuntu and Debian:
sudo apt-get install geoip-bin geoip-database 

Create the SSH/FTP Filter Script

Now create a shell script which checks for all incoming connection IP addresses and search their corresponding country using GeoIP database and allowed only those countries which code is defined in ALLOW_COUNTRIES variable in the script.

vim /usr/local/bin/ipfilter.sh 
#!/bin/bash
# License: WTFPL

# UPPERCASE space-separated country codes to ACCEPT
ALLOW_COUNTRIES="IN US"
LOGDENY_FACILITY="authpriv.notice"

if [ $# -ne 1 ]; then
  echo "Usage:  `basename $0` " 1>&2
  exit 0 # return true in case of config issue
fi

if [[ "`echo $1 | grep ':'`" != "" ]] ; then
  COUNTRY=`/usr/bin/geoiplookup6 "$1" | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`
else
  COUNTRY=`/usr/bin/geoiplookup "$1" | awk -F ": " '{ print $2 }' | awk -F "," '{ print $1 }' | head -n 1`
fi
[[ $COUNTRY = "IP Address not found" || $ALLOW_COUNTRIES =~ $COUNTRY ]] && RESPONSE="ALLOW" || RESPONSE="DENY"

if [[ "$RESPONSE" == "ALLOW" ]] ; then
  logger -p $LOGDENY_FACILITY "$RESPONSE sshd connection from $1 ($COUNTRY)"
  exit 0
else
  logger -p $LOGDENY_FACILITY "$RESPONSE sshd connection from $1 ($COUNTRY)"
  exit 1
fi

Script srouce: https://gist.github.com/jokey2k/a74f56955124880749e7

Make this script executable

chmod +x /usr/local/bin/ipfilter.sh 

Restrict SSH/FTP Connections

Now apply SSH and FTP restrictions using TCP wrappers. First we need to deny everyone by adding below line in /etc/hosts.deny.

/etc/hosts.deny:

sshd: ALL
vsftpd: ALL

Now edit /etc/hosts.allow and allow only those ips which are allowed by your IP filter script.

/etc/hosts.allow:

sshd: ALL: spawn /usr/local/bin/ipfilter.sh %a
vsftp: ALL: spawn /usr/local/bin/ipfilter.sh %a

Above FTP restrictions are for vsftpd only. Also, make sure you have enabled (tcp_wrappers=YES) in your vsftpd configuration. You can also create similar rules for any other services supported by TCP wrapper.

Testing

Finally, test your server by login using SSH or FTP from different-2 locations and analyze the access log files. Below are some demo logs created by ipfilter.sh.

Feb 27 13:03:29 TecAdmin root: DENY sshd connection from 212.191.246.202 (PL)
Feb 27 13:34:28 TecAdmin root: DENY sshd connection from 212.181.246.202 (SE)
Feb 27 13:34:36 TecAdmin root: DENY sshd connection from 211.181.246.203 (KR)
Feb 27 13:35:00 TecAdmin root: DENY sshd connection from 221.191.146.204 (JP)
Feb 27 15:11:04 TecAdmin root: ALLOW sshd connection from 49.15.212.12 (IN)
Feb 27 15:11:09 TecAdmin root: ALLOW sshd connection from 149.15.212.12 (US)
Feb 27 15:11:22 TecAdmin root: ALLOW sshd connection from 49.15.156.123 (IN)
Feb 27 15:11:32 TecAdmin root: ALLOW sshd connection from 231.15.156.123 (IP Address not found)
Feb 27 15:14:04 TecAdmin root: DENY sshd connection from 111.15.15.123 (CN)
Feb 27 15:14:56 TecAdmin root: ALLOW sshd connection from 49.15.110.123 (IN)

In logs you can say that all ips belong to the US (United States) and IN (India) are allowed. Also if any ip do not matches in GeoIP database will be allowed by default. The rest of the matching other countries’ ips are denied.

Share it!
Share on Facebook
Share on Twitter
Share on LinkedIn
Share on Reddit
Share on Tumblr
Share on Whatsapp
Rahul
Rahul
Connect on Facebook Connect on Twitter

I, Rahul Kumar am the founder and chief editor of TecAdmin.net. I am a Red Hat Certified Engineer (RHCE) and working as an IT professional since 2009..

24 Comments

  1. Avatar aokromes Reply
    January 13, 2021 at 8:55 am

    geoip-database is outdated since long time ago.

    geoip-database is already the newest version (20181108-1).

  2. Avatar Ansari Reply
    October 27, 2020 at 8:06 pm

    I use Centos 8, as the TCP wrapper (hosts.allow/deny)been removed here, how can I use GEOIP in centos 8 still?

  3. Avatar Anon Reply
    September 23, 2020 at 6:29 pm

    I tried this on Debian, but it was allowing connections even when the script returned ‘DENY’ instead of ‘ALLOW’! The solution is to use ‘aclexec’ instead of ‘spawn’ in the /etc/hosts.allow file. That way, the return status of the script is taken into account.

  4. Avatar Olivier Reply
    July 1, 2020 at 11:30 am

    Hello,
    I have followed the instruction to install the script, geoip and all thestuff.
    I get in my logs the results but ssh access is still allowed for users having an Ip not allowed.

    Centos 6

    I get this in the logs:

    Jul 1 13:27:51 db Olivier: DENY sshd connection from 43.226.150.122 (CN)
    Jul 1 13:27:54 db sshd[27318]: Invalid user ajeet from 43.226.150.122
    Jul 1 13:27:54 db sshd[27329]: input_userauth_request: invalid user ajeet
    Jul 1 13:27:54 db sshd[27318]: pam_unix(sshd:auth): check pass; user unknown
    Jul 1 13:27:54 db sshd[27318]: pam_unix(sshd:auth): authentication failure; logname= uid=0 euid=0 tty=ssh ruser= rhost=43.226.150.122
    Jul 1 13:27:54 db sshd[27318]: pam_succeed_if(sshd:auth): error retrieving information about user ajeet
    Jul 1 13:27:56 db sshd[27318]: Failed password for invalid user ajeet from 43.226.150.122 port 35876 ssh2

  5. Avatar Keerthiraja Reply
    June 12, 2020 at 5:42 pm

    This works perfectly in CentOS / RHEL 6.x & 7.x but in CentOS 8 this method will not work because
    the TCP Wrapper been removed.

    Any solution to work on RHEL / CentOS 8.x

  6. Avatar Rani Ahmad Reply
    May 11, 2020 at 6:47 am

    Thanks for the script but please put
    ALLOW_COUNTRIES=”IN US”
    as
    ALLOW_COUNTRIES=”EU US”

    something other than India just because I was confused by the word “IN”. Methought it was like the word “INput” .
    thanks.

  7. Avatar blog Reply
    June 20, 2019 at 11:22 pm

    Hi to every body, it’s my first pay a visit of this webpage; this web site contains
    amazing and truly fine information designed for visitors.

  8. Avatar zouhair kasmi Reply
    March 16, 2019 at 9:00 pm

    i have red all your comments all that stuff doesn’t work properly with my centos 7

  9. Avatar A_marucevich Reply
    February 22, 2019 at 9:28 pm

    Hello.
    how can I use it for smtp? smtpd .. allow connection to send mail from a defined country.
    thanks, Andres.

  10. Avatar steve martins Reply
    November 7, 2018 at 7:10 pm

    I’m close to having a centos solution by using FUSE and python to return a rule in a virtual text file created by ‘opening’ /mnt/myfusefolder/8.8.8.8 (any ip address) where the rule is either accept or deny based on geoiplookup.

  11. Avatar Michiel van Es Reply
    August 20, 2017 at 2:17 pm

    For all CentOS users, spawn or aclexec does not work, the hint is already given by using iptables to block the user.
    The iptables command given appends (-A) so the connection might still go through, to really block the IP you have to insert (-I) the block rule at rule #1.
    You can use my altered script for a working CentOS/RHEL version: https://github.com/chiel1980/scripts/blob/master/ipfilter.sh

  12. Avatar dd Reply
    July 9, 2017 at 7:20 pm

    There is a simple workaroud for this : using a vpn in the allowed country. Is it possible to detect the source of the IP, and refuse VPN connections ?

  13. Avatar dns Reply
    March 9, 2017 at 7:07 am

    I know this might be old, but I just can’t get it to work on CentOS …
    I’m using spawn but it seems like that the hosts.allow file does not get the response back for the actual block and just allows everything…

    Anyone got this working on CentOS ?

  14. Avatar Michael Reply
    January 30, 2017 at 8:11 am

    Thanks for this, I have modified the script slightly and it works great =) Within half an hour I have already blocked a bunch of attempts to login to ssh.

  15. Avatar Frank Reply
    July 15, 2016 at 6:26 am

    Yaysen, I found spawn did not work as it doesn’t’ return so everyone gets though still.

    The lack of aclexec on RHEL is an issue here.. I got around it by putting IPTABLES drop rules in the DENY block of the script. ( I had posted the code but then I couldn’t submit as it said I’d done something dodgy.) I’ll try encoding it and see if that gets it though.

    /sbin/iptables -A INPUT -i eth0 -p tcp –destination-port 22 -s $1 -j DROP

    Works, secure log is full of entries from logger, and iptables -L shows all of those IP’s being blocked.

    For added measure I put this too:
    echo “ALL: $1” >> /etc/hosts.deny

    cheers

    Frank

  16. Avatar agus Reply
    October 27, 2015 at 2:10 pm

    same here.. still can access when hit on enter

  17. Avatar Agus Reply
    October 27, 2015 at 12:16 pm

    Hi
    may i know where i can find the log file?

    • Avatar cope Reply
      May 11, 2017 at 9:13 am

      Try in /var/log/secure

  18. Avatar Bruno Reply
    May 27, 2015 at 11:44 am

    The manual is good. In the log file everything is also displayed correctly (DENY / ALLOW). But I can still sign me even with DENY. I have a system of CentOS 7 installed. Installation was carried out as described. Any idea why it does not work? Thanks, Bruno

    • Avatar Andrew Reply
      September 2, 2015 at 8:20 pm

      You ever figure out your problem? I have the same issue. Geoip correctly determines the source of the ip logging in, but no connections are ever denied. Thanks!

      • Avatar dns Reply
        March 9, 2017 at 8:02 am

        Still same issue here 🙂

    • Avatar andrew Reply
      November 20, 2018 at 3:56 pm

      Not sure how people get this to work. Nothing I can find indicates the tcp wrappers spawn command returns any sort of conditional allow/deny value. I did have to disable selinux to even get the spawn command to function but then it simply allowed every connection regardless of the return value of the spawn command.

  19. Avatar Jaysen Johnson Reply
    March 27, 2015 at 10:53 pm

    Excellent tutorial. Only change I had to make for CentOS 6 was that “aclexec” did not work in the hosts.allow file. I changed it to “spawn” and it works great.

    sshd: ALL: spawn /usr/local/bin/ipfilter.sh %a
    vsftp: ALL: spawn /usr/local/bin/ipfilter.sh %a

    Thanks,

    Jaysen Johnson

    • Rahul Rahul Reply
      March 30, 2015 at 3:10 am

      Hi Jaysen,

      Thanks, I have updated article with spawn.

Leave a Reply Cancel reply

Popular Posts

  • How To Install Python 3.9 on Ubuntu 20.04 5
  • How to Install Python 3.9 on CentOS/RHEL 7 & Fedora 32/31 0
  • How To Install VNC Server on Ubuntu 20.04 1
  • How To Install NVM on macOS with Homebrew 0
  • (Solved) apt-add-repository command not found – Ubuntu & Debian 0
© 2013-2020 Tecadmin.net. All Rights Reserved | Terms  | Privacy Policy