#!/bin/bash               
### IpInfoDB iptables countries unblock bash script###
### Slightly modified script from http://www.cyberciti.biz
### Countries code available : http://ipinfodb.com/country.txt ###
### Geofence allows access from specific countries where the default INPUT policy is DROP ##
### Jun7/2010 http://foxpa.ws ###

ISO="CA"                                                              
                                                                      
### Set PATH ###                                                      
IPT=/sbin/iptables                                                    
WGET=/usr/bin/wget                                                    
EGREP=/bin/egrep                                                      
ZONEROOT="/var/geofence/"                                             
IPTCBRESTORE="/var/geofence/iptables.cb"                              
                                                                      
### Network config ###                                                
####change this to reflect your servers wan interface ###             
IPTCBDEVICE=eth0                                                      

### Uncomment this to add exceptions from the unblocking i.e. allow unblocked countrys access to specific ports ### 
#ALLOWPORTS=80,443                                                                                                  
#ALLOWSUBNET=x.x.x.x/255.255.255.0                                                                                
                                                                                                                    
### No editing below ###                                                                                            
CBLIST="geofence"                                                                                                   
MAXZONEAGE=6                                                                                                        
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 unblocked                                                                         
    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 other countries - no ports allowed\n"                                             
    else                                                                                                            
printf "%s $CBLIST -p tcp -m multiport --dports ${ALLOWPORTS} -j ACCEPT\n" "-I">> ${IPTCBRESTORE}.tmp               
    fi                                                                                                              
                                                                                                                    
    if [ "Z${ALLOWSUBNET}" = "Z" ] ; then                                                                           
printf "Blocking all traffic from other countries - no subnets excluded\n"                                          
    else                                                                                                            
printf "%s $CBLIST -s ${ALLOWSUBNET} -j ACCEPT\n" "-I">> ${IPTCBRESTORE}.tmp                                        
    fi                                                                                                              
                                                                                                                    
    for c  in $ISO                                                                                                  
    do                                                                                                              
# local zone file                                                                                                   
tDB=$ZONEROOT/$c.zone                                                                                               
                                                                                                                    
 # Create drop chain for identified packets                                                                         
CBLISTACCEPT=${c}-${CBLIST}-ACCEPT                                                                                  
printf ":${CBLISTACCEPT} - [0:0]\n" >> ${IPTCBRESTORE}                                                              
printf "%s ${CBLISTACCEPT} -j ACCEPT\n" "-A" >> ${IPTCBRESTORE}.tmp                                                 
                                                                                                                    
# Load IP ranges into chains correlating to first octet                                                             
SAFEIPS=$(egrep -v "^#|^$" $tDB)                                                                                    
for ipunblock in $SAFEIPS                                                                                           
do                                                                                                                  
    topip=`echo $ipunblock | 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" ${ipunblock} ${topip}                                     
    printf "%s $topip-$CBLIST -s $ipunblock -j ${CBLISTACCEPT}\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 other countries - no ports allowed\n"                                             
    else                                                                                                            
$IPT -I $CBLIST -p tcp -m multiport --dports ${ALLOWPORTS} -j ACCEPT                                                
    fi                                                                                                              
                                                                                                                    
    if [ "Z${ALLOWSUBNET}" = "Z" ] ; then                                                                           
printf "Blocking all traffic from other countries - no subnets allowed\n"                                           
    else                                                                                                            
$IPT -I $CBLIST -s ${ALLOWSUBNET} -j ACCEPT                                                                         
    fi                                                                                                              
                                                                                                                    
    for c  in $ISO                                                                                                  
    do                                                                                                              
# local zone file
tDB=$ZONEROOT/$c.zone

# Create drop chain for identified packets
CBLISTACCEPT=${c}-${CBLIST}-ACCEPT
$IPT -N ${CBLISTACCEPT}
$IPT -A ${CBLISTACCEPT} -j ACCEPT

# Load IP ranges into chains correlating to first octet
SAFEIPS=$(egrep -v "^#|^$" $tDB)
for ipunblock in $SAFEIPS
do
    topip=`echo $ipunblock | 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" ${ipunblock} ${topip}
    $IPT -A $topip-$CBLIST -s $ipunblock -j ${CBLISTACCEPT}
done
    done
}

loadTables() {
    createIPTLoadFile
    ${IPT}-restore -n ${IPTCBRESTORE}
    #directLoadTables
    printf "Geofence 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
