====== Blacklist Countries with Shorewall and IPset ======
I run SSH on standard port 22 with fail2ban to prevent brute-force logins. Despite this I am still annoyed by the frequency of fail2ban alerts for countries like China.
Geoblock blacklist
geoallow whitelist
Startup at boot
====== Geoblock blacklist ======
I use a dynamic ipset referenced by shorewall as a blacklist because I have no reason for IPs from certain countries to contact my server.
**/usr/local/sbin/ipset-geoblock-country.sh**:
#!/bin/bash
#Debug
# set -x
exec 1> >(logger -s -t $(basename $0)) 2>&1
logger "Start: $0"
/sbin/ipset create geoblock hash:net -exist
/sbin/ipset flush geoblock
#for IP in $(/usr/bin/wget -O - http://www.ipdeny.com/ipblocks/data/countries/{ca,us}.zone)
for IP in $(/usr/bin/wget -q -O - ftp://ftp.arin.net/pub/stats/apnic/delegated-apnic-latest | awk -F'|' 'BEGIN{OFS=""} ( $2 == "CN" || $2 == "VN" ) && $3 == "ipv4" {print $4,"/",32-(log($5)/log(2))}' | aggregate)
do
/usr/sbin/ipset -A geoblock $IP -exist
done
logger "End: $0"
and I symlinked that script into /etc/cron.weekly to add IPs to this ipset (fast lookup) list
cd /etc/cron.weekly
ln -s /usr/local/sbin/ipset-geoblock-country.sh .
apt install ipset aggregate
chmod u+x /usr/local/sbin/ipset-geoblock-country.sh
Finally I told shorewall to use the ipset as its blacklist, and applied the blacklist to the public interface.
**/etc/shorewall/blacklist**:
###############################################################################
#ADDRESS/SUBNET PROTOCOL PORT OPTIONS
+geoblock
**/etc/shorewall/interfaces**:
#ZONE INTERFACE BROADCAST OPTIONS
net eth0 detect tcpflags,nosmurfs,routefilter,logmartians,blacklist
:~# iptables-save | grep geoblock
-A blacklst -m set --match-set geoblock src -j DROP
You can use +geoblock in other places in your shorewall configuration to provide a more surgical block or allow (/etc/shorewall/rules).
====== geoallow whitelist ======
Here I populated an ipset called geoallow which contains only the countries I want to allow to ssh to my server.
**/etc/shorewall/rules**:
Ping(ACCEPT) all all
ACCEPT net:+geoallow $FW tcp ssh
:~# iptables-save | grep geoallow
-A net2fw -p tcp -m tcp --dport 22 -m set --match-set geoallow src -j ACCEPT
====== Startup at boot ======
It is important to create the ipset (even though its empty) on reboot, or shorewall won't start.
Add the create to **/etc/defaults/shorewall** or anything that starts before shorewall:
/usr/sbin/ipset -N geoblock nethash
and add the script to **/etc/shorewall/started** or anything that runs after the network is up:
#!/bin/bash
/usr/local/sbin/ipset-geoblock-country.sh &