Skip to content

Instantly share code, notes, and snippets.

@sophieforceno
Last active December 11, 2021 23:37
Show Gist options
  • Save sophieforceno/80f2064de09657ad4df8b1bcad323acf to your computer and use it in GitHub Desktop.
Save sophieforceno/80f2064de09657ad4df8b1bcad323acf to your computer and use it in GitHub Desktop.
Bash script that uses ipset and iptables to block countries
#! /bin/bash
# blockbygeo.sh - Download country ipsets & add to iptables firewall rules
# By: Sophie Forceno
#
# Depends on: wget, ipset, iptables
IFS=$'\n'
action="$1"
country="$2"
# To add a country:
# Append country code to end of this array
# run 'sudo ./blockbygeo.sh add xx' where xx
# where xx is the country code you appended to ${COUNTRY[@]}
COUNTRY=( "cn" "ru" )
add_country() {
# Adds rule and creates ipset for a country added to ${COUNTRY[@]}
echo "Creating new ipset..."
sudo ipset -N "$country" hash:net
echo "Adding new firewall rule..."
iptables -v -I INPUT -m set --match-set "$country" src -j DROP
if [ ! -e /etc/blockbygeo/zones/ ]; then
echo "Creating zones/ directory..."
mkdir /etc/blockbygeo/zones
fi
echo "Downloading ipset..."
sudo wget --quiet -P . http://www.ipdeny.com/ipblocks/data/countries/"$country".zone -O /etc/blockbygeo/zones/"$country".zone
echo "Adding IPs from zone file to ipset..."
zonefile=( $(sudo cat /etc/blockbygeo/zones/"$country".zone) )
for i in "${zonefile[@]}"; do
sudo ipset -A "$country" "$i" -exist
done
echo "Done. Don't forget to add country to country code array in blockbygeo.sh"
}
update_ipsets() {
echo "Removing old zone files..."
sudo rm -f /etc/blockbygeo/zones/*.zone
echo "Flushing existing IPsets..."
sudo ipset flush
dl_ipsets
add_ipsets
}
add_rules() {
# Adds firewall rules for each of the new IPsets
echo "Adding ipset iptables firewall rules..."
for x in ${COUNTRY[@]}; do
echo "Adding rule for ipset: $x"
iptables -v -I INPUT -m set --match-set "$x" src -j DROP
done
}
make_ipsets() {
# Create IPsets for each country code in array
for x in ${COUNTRY[@]}; do
echo "Creating ipset: $x"
sudo ipset -N "$x" hash:net
done
}
dl_ipsets() {
# Pull the latest IP set for countries
echo "Downloading latest IP sets for countries..."
if [ ! -e /etc/blockbygeo/zones ]; then
mkdir /etc/blockbygeo/zones
fi
ping -w 10 -c 3 ipdeny.com > /dev/null
rc=$?
# Verify there is an active internet connection
if [ $rc -eq 0 ]; then
# Confirm wget is installed before proceeding
for c in ${COUNTRY[@]}; do
echo "Downloading "$c".zone..."
sudo wget --quiet -P . http://www.ipdeny.com/ipblocks/data/countries/"$c".zone -O /etc/blockbygeo/zones/"$c".zone
done
else
echo "Can't reach ipdeny.com to download zone files. Check your internet connection."
fi
}
add_ipsets() {
# Add each IP address from the downloaded list into each ipset
echo "Adding IPs from downloaded zones into ipsets..."
for c in ${COUNTRY[@]}; do
echo "Adding IPs to ipset: $c"
zonefile=( $(sudo cat /etc/blockbygeo/zones/"$c".zone) )
for i in "${zonefile[@]}"; do
sudo ipset -A "$c" "$i" -exist
done
done
}
## Main
main() {
# Create ipsets if they don't exist
if [ $(sudo ipset -L | head -c1 | wc -c) -eq 0 ]; then
make_ipsets
fi
# Only add iptables firewall rules on first run
if [ ! -e /etc/blockbygeo/.firstrun ]; then
add_rules
sudo touch /etc/blockbygeo/.firstrun
fi
# Remove old lists
echo "Removing old zone files..."
sudo rm -f /etc/blockbygeo/zones/*.zone
dl_ipsets
add_ipsets
}
# Make sure user is root
if [ "$EUID" -ne 0 ]; then
echo "Blockbygeo.sh must be run as root."
exit
fi
case "$1" in
add | -a)
add_country
;;
update | -u)
update_ipsets
;;
*)
main
;;
esac
exit 0
@sophieforceno
Copy link
Author

Recommend running as a cron job on a weekly, or even daily, basis.

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