Generate country based IP sets for packet filtering in the Linux kernel.
./ipset.py -h
./ipset.py cn | sudo ipset restore
sudo iptables -A INPUT -m set --match-set country-cn-v4 src -j REJECT
sudo ip6tables -A INPUT -m set --match-set country-cn-v6 src -j REJECT
Included is an Ansible playbook that can be used to set up multiple hosts with the same rules.
for country in $(yq -r '.countries[]' < ansible/vars.yaml); do ./ipset.py "$country" > "ipset-$country.txt"; done
ansible-playbook ansible/update.yaml
The script is not packaged. If you want to use it, clone or download this repository. The only requirement is Python 3.x (no external packages).
There are plenty of blog posts / tutorials / gists on this subject. So why yet
another ipset generator?
Here are some features unique to this script:
-
Validate input. Don't blindly shell-execute
sudo whatever $IP, where$IPis neither quoted nor escaped and could be any shell construct. -
Compare data from two (hopefully) independent sources:
By default, if there's a mismatch between the two sources, an error message is displayed and the set is not generated. You can opt to ignore a limited number of differences by using the
-iparameter. Sets generated in this manner contain only networks that are present in both data sources. -
Generate a list of commands (a session) that can be fed into
ipset restoreinstead of directly executingipset. This has several advantages:- the generator script doesn't need root privileges,
- the generated file can be put under version control, diff-reviewed and redistributed to many servers,
- a single
ipset restorecall is a lot faster than thousands ofipset addcalls.
-
Fail safely on errors. If a generated command fails while replacing an existing set, the original set will not be modified. In that case, you may have to manually delete a temporary set named
country-$COUNTRYCODE.tmp-$GMTDATETIME. -
Don't change
iptablesrules, only generate the IP set. This makes it easier to generate sets for various contexts (for blacklisting or for whitelisting, for separate servers etc.). -
The script is an importable Python module, which means it can be easily integrated with other Python based solutions.