Using Linux Debian Bookworm.
Problem
I want to block all incoming connections to my server coming from specific countries.
Edit
As someone pointed out in the comments, I really shouldn't be doing this with iptables since this will grind my server to a halt once the list of IP addresses it blocks grows to an unmanageable size (like thousands of IP addresses). Instead, I should use ipset
(to block entire ranges). Problem with that is that it's depending on lists I need to download on a regular base. I want something I set once (preferably).
So how can I stop connections from specific countries? Traffic (and sometimes brute force attacks) originating from China and Russia is getting out of hand. They bring my server to its knees regularly. They don't adhere to the robots.txt file and they crawl the site very aggressively (with hundreds, sometimes thousands of connections simultaneously). I really need to stop that. My guesstimate is that well over 90% of all traffic my server handles is malicious/malformed.
Edit 2
I found some online tutorials (like this one) how to do this, but it seems these tutorials are pretty old. Also, it requires downloading and compiling/installing some modules. I'm worried this might break in the future (when updating/upgrading other packages or even the distribution) or might become a security risk in the future. I keep my server up to date and current (by running apt-get update / apt-get upgrade / apt-get dist-upgrade regularly).
Original Message
I found a script online that (in a nutshell) gets a list of ip addresses of established connections every second, then uses geoiplookup to get the IP address' country. If country is from the list of countries you would like to block, it adds the ip address to your firewall filter using iptables. I made a few slight changes to the script (making it more readable and because I wasn't interested in this script sending me an email every time it blocked an ip address). This script is then run every minute through crontab:
#!/bin/bash
# Script found on lautenbacher.io"
end=$((SECONDS+55))
while [ $SECONDS -lt $end ]; do
echo $SECONDS
netstat -ant | egrep ':.*ESTABLISHED' | awk '{print $5}' | cut -d: -f1 | sort | uniq -c > testcc.txt
sed 's/^[ t]*//' -i testcc.txt
sed '/^$/d' -i testcc.txt
while read c d; do
if [[ $c > "0" ]]; then
bGF1dGVuYmFjaGVyLmlv=$(geoiplookup $d | awk -v ip="$d" '{FS=" "} {if($4 == "RU," || $4 == "CN," || $4 == "BLR,") {print 1}}')
if [[ $bGF1dGVuYmFjaGVyLmlv = "1" ]]; then
echo "running geolookup"
echo checking ip $d
geoiplookup $d
isCloudflare=0
# The original script made an exception for CLOUDFLARE. I don't want that exception
# bGF1dGVuYmFjaGVyLmlX=$(whois $d)
# if [[ "$bGF1dGVuYmFjaGVyLmlX" == *"CLOUDFLARE "* ]]; then
# isCloudflare=1
# echo Cloudflare detected
# fi
if [[ "$isCloudflare" != 1 ]]; then
echo try to add ip $d to blocklist
sudo iptables -I INPUT -s $d -j DROP
### I would like to sever the connection here ###
fi
fi
fi
done < testcc.txt
sleep 1
:
done
BTW, I have no idea why the script's author uses such weird variable names ("bGF1dGVuYmFjaGVyLmlv").
Anyways, the problem is whenever it finds a connection with an IP address from a banned country, it runs
sudo iptables -I INPUT -s $d -j DROP
on the ip address. This is all fine, but most of these connections are somewhat persistent, meaning a second later the same ip address is found and is again added using iptables. I'm not sure what happens (does it create duplicate rules?), but I would like to immediately drop the connection after the ipaddress was added with iptables.
So in short: How can I kill a(ll) connection(s) with an IP address?
'bGF1dGVuYmFjaGVyLmlX' == base64('lautenbacher.iW')