Block an entire Country with iptables

Here is a pretty fancy “trick” for the ones who wants to block certain parts of the world from accessing your VPS.

first of all you need to know the netblocks for the country you want to block, this information can be found at this page, each country has their own file in CIDR format.

Then we can add those netblocks to IPTABLES and  “problem solved”.
Save below script as root user to “country.block.iptables.sh” and change the ISO variable to match the country name using ISO country codes.

When you are done, make sure it updates atleast weekly so it inludes recently added IP, this will be done by adding the following as a cron job.

first execute:

add:

close and save.

To start blocking immediately type:

12 comments for “Block an entire Country with iptables

  1. February 27, 2013 at 22:54

    Found this site via LET and glad I visited – hope you go from strength to strength. This script is brilliant and is now in use on my VPS. Saves me trying to ban via htaccess!!

  2. March 1, 2013 at 04:11

    Hello,

    Nice tip, but you don’t say that this script will remove all iptables settings from your system. Because of that you need to add next to this script :

    #This will remove your settings. Add your old rules. Ex. for SSH on port 22.
    #Check -i settings too. Remove # befor iptabeles to use this rules.
    # If you don’t have your own rules, don’t use this 😉
    #iptables -I INPUT -p tcp –dport 22 -i eth0 -m state –state NEW -m recent –set
    #iptables -I INPUT -p tcp –dport 22 -i eth0 -m state –state NEW -m recent –update –seconds 90 –hitcount 4 -j DROP

    • March 1, 2013 at 11:46

      Hello,
      thank you for the input.

      If you take a closer look at the script it does say this:
      # clean old rules
      cleanOldRules

      which run, among other things, IPTABLES -F
      That will flush all your previous rules.

      Easiest way to fix this is to find this in the script:
      # call your other iptable script
      # /path/to/other/iptables.sh

      remove the # from the second line and update the path to your own iptables file. (which should not include an IPTABLES -F).

      Hope it helps.

      • March 1, 2013 at 12:04

        Hello again,

        I agree with you. Your solution is good for advanced users, but most of VPS users will take care only about SSH security, because of that i wrote this part of script, but after all this is only for sys admins and use it only if you are sure what you are doing.

        You need to know, that after this settings your system will use more server memory, and if you don’t have it, i propose you to learn how to use ipset framework.

        Thanks and cheers !

        • March 1, 2013 at 14:18

          That’s the beauty with it 🙂

          There are never one specific solution, you can do something in a thousand ways and still manage to get the needed solution.

  3. Wahid
    December 25, 2014 at 06:55

    Thanks for the great work!.

    Ipdeny now offers aggregated IP blocks. Can I still use the script with the aggregated zone files?

  4. John
    April 3, 2016 at 16:33

    Hi,

    Just tried this script on a Centos 6.7 VPS and it fails with Memory allocation problem, so not usable.

    ans to Stingray: ipsets are blocked on a VPS so cannot use that either.

     

  5. Luxilius
    July 26, 2016 at 16:31

    You not need to use CleanOldRules
    because if you already have good rule, not need to delete, then remove that line from script and just upload this script in your iptables

  6. May 8, 2018 at 20:59

    For those getting a syntax error please use this.

    #!/bin/bash
    ### Block all traffic from AFGHANISTAN (af) and CHINA (CN). Use ISO code ###
    ISO=”af cn”

    ### Set PATH ###
    IPT=/sbin/iptables
    WGET=/usr/bin/wget
    EGREP=/bin/egrep

    ### No editing below ###
    SPAMLIST=”countrydrop”
    ZONEROOT=”/root/iptables”
    DLROOT=”http://www.ipdeny.com/ipblocks/data/countries”

    cleanOldRules(){
    $IPT -F
    $IPT -X
    $IPT -t nat -F
    $IPT -t nat -X
    $IPT -t mangle -F
    $IPT -t mangle -X
    $IPT -P INPUT ACCEPT
    $IPT -P OUTPUT ACCEPT
    $IPT -P FORWARD ACCEPT
    }

    # create a dir
    [ ! -d $ZONEROOT ] & /bin/mkdir -p $ZONEROOT

    # clean old rules
    cleanOldRules

    # create a new iptables list
    $IPT -N $SPAMLIST

    for c in $ISO
    do
    # local zone file
    tDB=$ZONEROOT/$c.zone

    # get fresh zone file
    $WGET -O $tDB $DLROOT/$c.zone

    # country specific log message
    SPAMDROPMSG=”$c Country Drop”

    # get
    BADIPS=$(egrep -v “^#|^$” $tDB)
    for ipblock in $BADIPS
    do
    $IPT -A $SPAMLIST -s $ipblock -j LOG –log-prefix “$SPAMDROPMSG”
    $IPT -A $SPAMLIST -s $ipblock -j DROP
    done
    done

    # Drop everything
    $IPT -I INPUT -j $SPAMLIST
    $IPT -I OUTPUT -j $SPAMLIST
    $IPT -I FORWARD -j $SPAMLIST

    # call your other iptable script
    # /path/to/other/iptables.sh

    exit 0

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.