Skip to content

Instantly share code, notes, and snippets.

@Pandry
Last active July 3, 2024 13:07
Show Gist options
  • Save Pandry/21fc0e30abbfd0579ec69c491b99a446 to your computer and use it in GitHub Desktop.
Save Pandry/21fc0e30abbfd0579ec69c491b99a446 to your computer and use it in GitHub Desktop.
Block countries IPs via Firewalld
#!/bin/bash
##
# Name: GeoIP Firewall script
# Author: Pandry
# Version: 0.1.1
# Description: This is a simple script that will set up a GeoIP firewall blocking all the zones excecpt the specified ones
# it is possible to add the whitelisted zones @ line 47
# Additional notes: Usage of [iprange](https://github.com/firehol/iprange) is suggested
# for best performances
##
BLACKLIST_NAME="geoblacklist"
TMPDIR="/tmp/geoip"
if [ $(which yum) ]; then
echo -e "[\e[32mOK\e[39m] Detected a RHEL based environment!"
echo -e "[\e[93mDOING\e[39m] Making sure firewalld is installed..."
yum -y install firewalld > /dev/null 2> /dev/null
if [[ $? -eq 0 ]];then
echo -e "[\e[32mOK\e[39m] firewalld is installed!"
systemctl enable --now firewalld > /dev/null 2> /dev/null
else
echo -e "[\e[31mFAIL\e[39m] Couldn't install firewalld, aborting!"
exit 1
fi
elif [ $(which apt) ]; then
echo -e "[\e[32mOK\e[39m] Detected a Debian based environment!"
echo -e "[\e[93mDOING\e[39m] Making sure firewalld is installed..."
apt -y install firewalld > /dev/null 2> /dev/null
if [[ $? -eq 0 ]];then
echo -e "[\e[32mOK\e[39m] firewalld is installed!"
systemctl enable --now firewalld > /dev/null 2> /dev/null
else
echo -e "[\e[31mFAIL\e[39m] Couldn't install firewalld, aborting!"
exit 1
fi
elif [ $(which apk) ]; then
echo -e "[\e[31mFAIL\e[39m] Alpine Linux is not supported yet!"
exit 1
else
echo -e "[\e[31mFAIL\e[39m] Couldn't determine the current OS, aborting!"
exit 1
fi
#Create the blacklist (only if necessary)
#200k should be enough - $(find . -name "*.zone" | xargs wc -l) gives 184688 lines without the it zone
firewall-cmd --get-ipsets| grep "$BLACKLIST_NAME" > /dev/null 2> /dev/null
if [[ $? -ne 0 ]];then
echo -e "[\e[93mDOING\e[39m] Creating "
firewall-cmd --permanent --new-ipset="$BLACKLIST_NAME" --type=hash:net --option=family=inet --option=hashsize=4096 --option=maxelem=200000 > /dev/null 2> /dev/null
if [[ $? -eq 0 ]];then
echo -e "[\e[32mOK\e[39m] Blacklist $BLACKLIST_NAME successfully created!"
else
echo -e "[\e[31mFAIL\e[39m] Couldn't create the blacklist $BLACKLIST_NAME, aborting!"
exit 1
fi
fi
#create the folder
mkdir -p $TMPDIR
#Downloads the GeoIP database
if [[ $? -eq 0 ]];then
echo -e "[\e[93mDOING\e[39m] Downloading latest ip database... "
curl -L -o $TMPDIR/geoip.tar.gz http://www.ipdeny.com/ipblocks/data/countries/all-zones.tar.gz > /dev/null 2> /dev/null
if [[ $? -eq 0 ]];then
echo -e "[\e[32mOK\e[39m] Database successfully downloaded!"
else
echo -e "[\e[31mFAIL\e[39m] Couldn't download the database, aborting!"
exit 1
fi
else
echo -e "[\e[31mFAIL\e[39m] Couldn't create the $TMPDIR directory!"
exit 1
fi
#Extract the zones in the database
tar -xzf $TMPDIR/geoip.tar.gz -C $TMPDIR
#Remove all the zones you want to allow
rm $TMPDIR/it.zone $TMPDIR/eu.zone
#Add the IPs to the blacklist
for f in $TMPDIR/*.zone; do
echo -e "[\e[93mDOING\e[39m] Adding lines from $f ..."
firewall-cmd --permanent --ipset="$BLACKLIST_NAME" --add-entries-from-file=$f > /dev/null
if [[ $? -eq 0 ]];then
echo -e "[\e[32mOK\e[39m] Added $f with no issues";
else
echo -e "[\e[31mFAIL\e[39m] Some errors verified while adding the $f zone";
fi
echo ""
done
# Drop the IPs
firewall-cmd --permanent --zone=drop --add-source="ipset:$BLACKLIST_NAME" > /dev/null
#Reload the firewall
firewall-cmd --reload
cd ~
# Remove the traces
rm -rf /tmp/geoip
@snarl817
Copy link

Ok, I've done some more digging, and debugging, and the issue is nftables is TERRIBLE at managing large ipsets when using firewalld as a frontend. There are two solutions for this:

  1. Switch the FirewallBackend from nftables to iptables in /etc/firewalld/firewalld.conf
  2. Use nftables to load the the ipset outside of firewalld.

I'm having difficulty locating documentation on HOW to implement #2, so I just switched the backend to iptables. Yes, it's deprecated and will be going away "soon", but I'd imagine that they'll keep it around until libnftables gets fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment