One of those challenges in operations is the constant threat of cyberattacks from different parts of the world.
One way to mitigate this risk is by utilizing iptables, as its natively installed on most systems and quite easy to use.
How it Works
By using GeoIP databases, iptables can be configured to identify the originating country of an IP address. With this information, rules can be crafted to block or allow traffic from entire countries. This kind of country-based blocking can be extremely useful in some scenarios.
Why it’s Good to Have
Targeted Security: If your system or network is experiencing targeted attacks from specific countries, blocking those countries entirely can provide an immediate mitigation strategy.
Compliance and Regulation: Certain legal and regulatory frameworks may require you to limit or block access to or from particular geographic locations. Using iptables in conjunction with GeoIP databases makes this process straightforward.
Performance Optimization: If your services are intended for a specific region, blocking unnecessary countries can reduce unwanted traffic and optimize the performance of your applications.
Customization: The iptables block script is highly customizable, allowing for complex rules that can fit specific security needs.
How to Implement It
Implementing a country-based block with iptables is relatively simple. The basic steps include:
- Installing the necessary GeoIP modules.
- Updating the GeoIP database.
- Crafting the iptables rules using the country codes you want to block or allow.
- Monitoring and tweaking the rules as needed.
A Note of Caution
While powerful, country-based blocking should be used with care. Overly broad rules can inadvertently block legitimate users, impacting your service’s accessibility and potentially harming your business or reputation. A comprehensive understanding of your network’s needs and careful implementation are essential.
This one I have used is fairly robust and easy to use when the need has arised: nixCraft Linux Iptables Just Block By Country
iptables-country-block.sh
The script below is the modified version with a more robust action set, thnx nixcraft and David Picard.
#!/bin/bash
#
# iptables-country-block Add country blocking rules to iptables firewall
#
# chkconfig: 2345 09 91
# description: Adds and removes country blocking rules to iptables firewall
#
# config: /etc/sysconfig/iptables-cblock-config
#
# Origin from http://www.cyberciti.biz/faq/block-entier-country-using-iptables
# Modified by David Picard of PSInd, LLC - dpicard [a-t] psind [d-ot] com - to
# include ability to cache the address list, create chains by subnet thus
# optimizing rule execution, clean up the rules without wiping the existing
# tables, include port overrides to allow traffic deemed 'safe', and leverage
# iptables-restore to optimize rules loading.
# Source function library.
# The following values may be overridden in the config
### Block all traffic from AFGHANISTAN (af), CHINA (CN) and KOREA(kr).
### Use ISO code ###
ISO="af cn au jp id"
IPTCBRESTORE="/etc/sysconfig/iptables.cb"
IPTCBDEVICE=ens4
ALLOWPORTS=80,443
ALLOWSUBNET=10.128.0.0/255.255.0.0
MAXZONEAGE=7
#DLROOT="https://www.ipdeny.com/ipblocks/data/countries"
DLROOT="https://www.ipdeny.com/ipblocks/data/aggregated"
IPTABLES_VERBOSE="no"
IPTABLES_STATUS_NUMERIC="yes"
IPTABLES_STATUS_VERBOSE="yes"
IPTABLES_STATUS_LINENUMBERS="yes"
### Set PATH ###
IPT=/sbin/iptables
WGET=/usr/bin/wget
EGREP=/bin/egrep
IPTABLES_CB_CONFIG=/etc/sysconfig/iptables-cblock-config
### No editing below ###
IPTABLESCB=`basename $0`
CBLIST="countrydrop"
IPTCBLOG=/var/log/iptables_country_block.log
IPTCBLOAD=`mktemp`
IPTCBTMP=`mktemp`
ZONEROOT="/var/iptables"
# Load country blocking firewall configuration.
[ -f "$IPTABLES_CB_CONFIG" ] && . "$IPTABLES_CB_CONFIG"
cleanOldRules(){
$IPT -L $CBLIST > /dev/null 2>&1
if [ $? = 0 ] ; then
$IPT -D INPUT ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST
$IPT -D FORWARD ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST
$IPT -D OUTPUT ${IPTCBDEVICE:+-o }${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-aggregated.zone
if [ -f $tDB ] ; then
printf "Zone file %s is new enough - no update required.\n" $tDB >>${IPTCBLOG}
else
# get fresh zone file if it is newer than MAXZONEAGE days
$WGET -O $tDB $DLROOT/$c-aggregated.zone
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} >>${IPTCBLOG}
fi
done
}
createIPTLoadFile() {
printf "# Generated by %s on" $0 > ${IPTCBLOAD}
printf "%s " `date` >> ${IPTCBLOAD}
printf "\n*filter\n" >> ${IPTCBLOAD}
# Create CBLIST chain
printf ":$CBLIST - [0:0]\n" >> ${IPTCBLOAD}
printf "%s INPUT ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST\n" "-I" > ${IPTCBTMP}
printf "%s OUTPUT ${IPTCBDEVICE:+-o }${IPTCBDEVICE} -j $CBLIST\n" "-I" >> ${IPTCBTMP}
printf "%s FORWARD ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST\n" "-I" >> ${IPTCBTMP}
printf "%s $CBLIST -m state --state RELATED,ESTABLISHED -j ACCEPT\n" "-I">> ${IPTCBTMP}
if [ "Z${ALLOWPORTS}" = "Z" ] ; then
printf "Blocking all traffic from country - no ports allowed\n" >>${IPTCBLOG}
else
printf "%s $CBLIST -p tcp -m multiport --dports ${ALLOWPORTS} -j RETURN\n" "-I">> ${IPTCBTMP}
fi
if [ "Z${ALLOWSUBNET}" = "Z" ] ; then
printf "Blocking all traffic from country - no subnets excluded\n" >>${IPTCBLOG}
else
printf "%s $CBLIST -s ${ALLOWSUBNET} -j RETURN\n" "-I">> ${IPTCBTMP}
fi
for c in $ISO
do
# local zone file
tDB=$ZONEROOT/$c-aggregated.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" >> ${IPTCBLOAD}
printf "%s ${CBLISTDROP} -j LOG --log-prefix \"$SPAMDROPMSG\"\n" "-A" >> ${IPTCBTMP}
printf "%s ${CBLISTDROP} -j DROP\n" "-A" >> ${IPTCBTMP}
# 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} ${IPTCBLOAD}`
if [ $chainExists = 0 ] ; then
printf "Creating chain for octet %s\n" ${topip} >>${IPTCBLOG}
printf ":$topip-$CBLIST - [0:0]\n" >> ${IPTCBLOAD}
sip=${topip}.0.0.0/8
printf "%s $CBLIST -s ${sip} -j $topip-$CBLIST\n" "-A" >> ${IPTCBTMP}
fi
printf " Adding rule for %s to chain for octet %s\n" ${ipblock} ${topip} >>${IPTCBLOG}
printf "%s $topip-$CBLIST -s $ipblock -j ${CBLISTDROP}\n" "-A" >> ${IPTCBTMP}
done
done
cat ${IPTCBTMP} >> ${IPTCBLOAD} && rm -f ${IPTCBTMP}
printf "COMMIT\n# Completed on " >> ${IPTCBLOAD}
printf "%s " `date` >> ${IPTCBLOAD}
printf "\n" >> ${IPTCBLOAD}
}
directLoadTables() {
# Create CBLIST chain
$IPT -N $CBLIST
# Block inbound packets on specified network device
$IPT -I INPUT ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST
# The following rules are useful only in multi-NIC systems / gateways
$IPT -I FORWARD ${IPTCBDEVICE:+-i }${IPTCBDEVICE} -j $CBLIST
$IPT -I OUTPUT ${IPTCBDEVICE:+-o }${IPTCBDEVICE} -j $CBLIST
if [ "Z${ALLOWPORTS}" = "Z" ] ; then
printf "Blocking all traffic from country - no ports allowed\n" >>${IPTCBLOG}
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" >>${IPTCBLOG}
else
$IPT -I $CBLIST -s ${ALLOWSUBNET} -j RETURN
fi
for c in $ISO
do
# local zone file
tDB=$ZONEROOT/$c.-aggregatedzone
# 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} >>${IPTCBLOG}
$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} >>${IPTCBLOG}
$IPT -A $topip-$CBLIST -s $ipblock -j ${CBLISTDROP}
done
done
}
loadTables() {
createIPTLoadFile
${IPT}-restore -n ${IPTCBLOAD}
if [ ! "z${IPTCBRESTORE}" = "z" ] ; then
RESTORE_DIR=`dirname ${IPTCBRESTORE}`
[ -d ${RESTORE_DIR} ] && mv -f ${IPTCBLOAD} ${IPTCBRESTORE}
fi
#directLoadTables
printf "Country block instituted for: %s\n" "$ISO" >>${IPTCBLOG}
}
status() {
NUM=
[ "x$IPTABLES_STATUS_NUMERIC" = "xyes" ] && NUM="-n"
VERBOSE=
[ "x$IPTABLES_STATUS_VERBOSE" = "xyes" ] && VERBOSE="--verbose"
COUNT=
[ "x$IPTABLES_STATUS_LINENUMBERS" = "xyes" ] && COUNT="--line-numbers"
for table in "filter" ; do
echo $"Table: $table"
$IPT -t $table --list $CBLIST $NUM $VERBOSE $COUNT
done
return 0
}
stop() {
echo -n $"${IPTABLESCB}: Removing cb firewall rules: "
# clean old rules
cleanOldRules
if [ $? -eq 0 ]; then
success; echo
else
failure; echo; return 1
fi
}
start() {
echo -n $"${IPTABLESCB}: Applying cb firewall rules: "
# create a dir
[ ! -d $ZONEROOT ] && /bin/mkdir -p $ZONEROOT
# update zone files as needed
updateZoneFiles
# create a new iptables list
loadTables
if [ $? -eq 0 ]; then
success; echo
else
failure; echo; return 1
fi
}
restart() {
stop
start
}
#[ ! "x$IPTABLES_VERBOSE" = "xyes" ] && exec 1>/dev/null
case "$1" in
start)
[ -f "$VAR_SUBSYS_IPTABLES" ] && exit 0
start
RETVAL=$?
;;
stop)
[ "x$IPTABLES_SAVE_ON_STOP" = "xyes" ] && save
stop
RETVAL=$?
;;
restart|force-reload)
restart
RETVAL=$?
;;
status)
status
RETVAL=$?
;;
*)
echo $"Usage: ${IPTABLESCB} {start|stop|restart|condrestart|status}"
RETVAL=2
;;
esac
exit $RETVAL
Buy Me a Coffee