TIP: Country based IP filtering
Some days ago was the 80th anniversary of the d-day landings. Thousands of soldiers at the same place, the same day to flood nazi's defenses. Probability to die far away from home was huge, but they didn't escape. In the east part of Europe, URSS did the same. But, 80 years later, russia seems to have forgot what means war, nazi and dictator... Vladimir Poutine sends, for 2 years now, people to death without any concern.
This is why I first decided to redirect all people visiting my website to this thread if they're coming from an russian website. Some weeks ago, I finally decided to block every connexion that comes from russia because my website contains some computer stuff that can helps industry. I know, it's not fair for all people that just want to live normally and being informed or just want to see different things. But, even if filtering can be bypassed using a VPN, this is what I can do to help a bit Ukraine.
The script output commands for nftables (Linux kernel firewall). It reads data from one of ripe.net database (filled by AFRINIC, ARIN, APNIC, LACNIC and RIPENCC organisations) which contains allocated IP ranges for all countries. These databases are updated everyday. For an easier databases retrieval, you can look at my own project iptogeo or directly on ripe.net.
#!/usr/bin/env python3
TABLE_NAME = 'BAN_RU'
COUNTRY = 'RU'
RIPE_FILE = 'ripencc'
# Create table and add an inet filter chain
print(f'nft delete table inet {TABLE_NAME}')
print(f'nft create table inet {TABLE_NAME}')
print(f'nft add chain inet {TABLE_NAME} input "{{ type filter hook input priority filter; }}"')
# ripencc|RU|ipv4|2.56.88.0|1024|20190313|allocated|caa02a36-bb09-4e4f-a834-1038f57676c1
# ripencc|RU|ipv6|2001:640::|32|19991115|allocated|ea8bf0c4-24e1-4e58-8a09-cee9da9a38f5
with open(RIPE_FILE, 'r') as fd:
for line in fd.readlines():
parts = line.split('|')
if parts[1] != COUNTRY: continue
if parts[2] == 'ipv4':
nb_ip = int(parts[4])
bits = (~(nb_ip - 1)) & 0xffffffff
mask = 0
for i in range(31,-1,-1):
if (bits & (1 << i)) == 0: break
mask += 1
print(f'nft add rule inet {TABLE_NAME} input ip saddr {parts[3]}/{mask} drop')
elif parts[2] == 'ipv6':
mask = int(parts[4])
print(f'nft add rule inet {TABLE_NAME} input ip6 saddr {parts[3]}/{mask} drop')
else:
continue
Output must be redirected to a file, then you can source it. For russia, there is about 20 000 entries.