Bash script to block IP by country

Script I originally posted on IPInfoDB to block country based on IP address geolocation using iptables.

#!/bin/bash
### IpInfoDB iptables countries block bash script###
### Slightly modified script from http://www.cyberciti.biz
### Countries code available : http://ipinfodb.com/country.txt ###
### 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
ZONEROOT="/root/iptables/"
IPTCBRESTORE="/root/iptables/iptables.cb"
 
### Network config ###
IPTCBDEVICE=eth0
ALLOWPORTS=80,443
ALLOWSUBNET=192.168.0.0/255.255.0.0
 
### No editing below ###
CBLIST="countrydrop"
MAXZONEAGE=7
DLROOT="http://ipinfodb.com/country_query_test.php?country="
 
cleanOldRules(){
    $IPT -L $CBLIST > /dev/null 2>&1
    if [ $? = 0 ] ; then
	$IPT -D INPUT ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST
	$IPT -D OUTPUT ${IPTCBDEVICE:+-o }${IPTCBDEVICE} -j $CBLIST
	$IPT -D FORWARD ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST
    fi
    $IPT -F $CBLIST
    $IPT -X $CBLIST
 
    for i  in `$IPT -L -n | grep Chain | cut -f 2 -d ' ' | grep '\-$CBLIST'`
    do
	$IPT -F ${i}
	$IPT -X ${i}
    done
}
 
updateZoneFiles() {
    ZONEARCH=${ZONEROOT}/arch
    mkdir -p ${ZONEARCH}
    find ${ZONEROOT} -maxdepth 1 -mindepth 1 -ctime +${MAXZONEAGE} -exec mv {} ${ZONEARCH} \;
 
    for c  in $ISO
    do
	# local zone file
	tDB=$ZONEROOT/$c.zone
 
	if [ -f $tDB ] ; then
	    printf "Zone file %s is new enough - no update required.\n" $tDB
	else
	    # get fresh zone file if it is newer than MAXZONEAGE days
	    $WGET -O $tDB $DLROOT$c
	fi
    done
    oldzones=`find ${ZONEROOT} -mindepth 1 -maxdepth 1 -type f -exec basename {} \; | cut -f 1 -d '.'`
    # Archive old zones no longer blocked
    for z in $oldzones ; do
	archme=${c}
	for c  in $ISO ; do
	    if [ $c = $z ] ; then archme="X"; fi
	done
	if [ $archme = $z ] ; then
	    mv ${archme} ${ZONEARCH}
	else
	    printf "Working from previous zone file for %s\n" ${z}
	fi
    done
}
 
createIPTLoadFile() {
    printf "# Generated by %s on" $0 > ${IPTCBRESTORE}
    printf "%s " `date` >> ${IPTCBRESTORE}
    printf "\n*filter\n" >> ${IPTCBRESTORE}
    # Create CBLIST chain
    printf ":$CBLIST - [0:0]\n" >> ${IPTCBRESTORE}
    printf "%s INPUT ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST\n" "-I" > ${IPTCBRESTORE}.tmp
    printf "%s OUTPUT ${IPTCBDEVICE:+-o }${IPTCBDEVICE} -j $CBLIST\n" "-I"  >> ${IPTCBRESTORE}.tmp
    printf "%s FORWARD ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST\n" "-I" >> ${IPTCBRESTORE}.tmp
 
    if [ "Z${ALLOWPORTS}" = "Z" ] ; then
	printf "Blocking all traffic from country - no ports allowed\n"
    else
	printf "%s $CBLIST -p tcp -m multiport --dports ${ALLOWPORTS} -j RETURN\n" "-I">> ${IPTCBRESTORE}.tmp
    fi
 
    if [ "Z${ALLOWSUBNET}" = "Z" ] ; then
	printf "Blocking all traffic from country - no subnets excluded\n"
    else
	printf "%s $CBLIST -s ${ALLOWSUBNET} -j RETURN\n" "-I">> ${IPTCBRESTORE}.tmp
    fi
 
    for c  in $ISO
    do
	# local zone file
	tDB=$ZONEROOT/$c.zone
 
	# country specific log message
	SPAMDROPMSG="iptables: ${c}-Country-Drop: "
 
        # Create drop chain for identified packets
	CBLISTDROP=${c}-${CBLIST}-DROP
	printf ":${CBLISTDROP} - [0:0]\n" >> ${IPTCBRESTORE}
	printf "%s ${CBLISTDROP} -j LOG --log-prefix \"$SPAMDROPMSG\"\n" "-A" >> ${IPTCBRESTORE}.tmp
	printf "%s ${CBLISTDROP} -j DROP\n" "-A" >> ${IPTCBRESTORE}.tmp
 
	# Load IP ranges into chains correlating to first octet
	BADIPS=$(egrep -v "^#|^$" $tDB)
	for ipblock in $BADIPS
	do
	    topip=`echo $ipblock | cut -f 1 -d '.'`
	    chainExists=`grep -c :${topip}-${CBLIST} ${IPTCBRESTORE}`
	    if [ $chainExists = 0 ] ; then
		printf "Creating chain for octet %s\n" ${topip}
		printf ":$topip-$CBLIST - [0:0]\n" >> ${IPTCBRESTORE}
		sip=${topip}.0.0.0/8
		printf "%s $CBLIST -s ${sip} -j $topip-$CBLIST\n" "-A" >> ${IPTCBRESTORE}.tmp
	    fi
	    printf "  Adding rule for %s to chain for octet %s\n" ${ipblock} ${topip}
	    printf "%s $topip-$CBLIST -s $ipblock -j ${CBLISTDROP}\n" "-A" >> ${IPTCBRESTORE}.tmp
	done
    done
    cat ${IPTCBRESTORE}.tmp >> ${IPTCBRESTORE} && rm -f ${IPTCBRESTORE}.tmp
    printf "COMMIT\n# Completed on " >> ${IPTCBRESTORE}
    printf "%s " `date` >> ${IPTCBRESTORE}
    printf "\n" >> ${IPTCBRESTORE}
}
 
directLoadTables() {
    # Create CBLIST chain
    $IPT -N $CBLIST
    $IPT -I INPUT ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST
    $IPT -I OUTPUT ${IPTCBDEVICE:+-o }${IPTCBDEVICE} -j $CBLIST
    $IPT -I FORWARD ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST
 
    if [ "Z${ALLOWPORTS}" = "Z" ] ; then
	printf "Blocking all traffic from country - no ports allowed\n"
    else
	$IPT -I $CBLIST -p tcp -m multiport --dports ${ALLOWPORTS} -j RETURN
    fi
 
    if [ "Z${ALLOWSUBNET}" = "Z" ] ; then
	printf "Blocking all traffic from country - no subnets allowed\n"
    else
	$IPT -I $CBLIST -s ${ALLOWSUBNET} -j RETURN
    fi
 
    for c  in $ISO
    do
	# local zone file
	tDB=$ZONEROOT/$c.zone
 
	# country specific log message
	SPAMDROPMSG="$c Country Drop"
 
        # Create drop chain for identified packets
	CBLISTDROP=${c}-${CBLIST}-DROP
	$IPT -N ${CBLISTDROP}
	$IPT -A ${CBLISTDROP} -j LOG --log-prefix "$SPAMDROPMSG"
	$IPT -A ${CBLISTDROP} -j DROP
 
	# Load IP ranges into chains correlating to first octet
	BADIPS=$(egrep -v "^#|^$" $tDB)
	for ipblock in $BADIPS
	do
	    topip=`echo $ipblock | cut -f 1 -d '.'`
	    $IPT -L $topip-$CBLIST > /dev/null 2>&1
	    if [ $? = 1 ] ; then
		printf "Creating chain for octet %s\n" ${topip}
		$IPT -N $topip-$CBLIST
		sip=${topip}.0.0.0/8
		$IPT -A $CBLIST -s ${sip} -j $topip-$CBLIST
	    fi
	    printf "  Adding rule for %s to chain for octet %s\n" ${ipblock} ${topip}
	    $IPT -A $topip-$CBLIST -s $ipblock -j ${CBLISTDROP}
	done
    done
}
 
loadTables() {
    createIPTLoadFile
    ${IPT}-restore -n ${IPTCBRESTORE}
    #directLoadTables
    printf "Country block instituted for: %s\n" "$ISO"
}
 
# create a dir
[ ! -d $ZONEROOT ] && /bin/mkdir -p $ZONEROOT
 
# clean old rules
cleanOldRules
 
# update zone files as needed
updateZoneFiles
 
# create a new iptables list
loadTables
 
exit 0