Block or allow countries using iptables, ipset and ipdeny.com
- Supports RH and Debian with iptables, nftables and firewalld
- Also works with ipverse.com and other block list providers
- Both ipv4 and ipv6 are supported
Setup firewall first if you have not done so yet, at least an input chain is needed.
Then run this script manually and if all is well, add to cron (e.g. /etc/cron.daily) or systemd service.
To automatically setup a daily systemd timer, run ipset-country -i
.
To uninstall, run: ipset-country -u
.
Or to run script on boot, add it to rc (e.g. '/etc/rc.local').
Running this script will add rules to your firewall. Make sure you do not lock yourself out in case of issues on a remote system.
Note that all options and settings are explained in the script itself, see ipset-country
Optionally, you can use a separate config file located in the same directory as the script. To specify a custom location use ipset-country -c /path/to/conf
(like "/etc/ipset-country.conf" or "/usr/local/etc/ipset-country.conf".)
The config file will overwrite any options set in script. To create a new conf file, run:
sed -n '/# CONFIGURATION:/,/# END OF CONFIG/p' ipset-country > ipset-country.conf
If needed, change OS using DISTRO
setting. Default is "auto", which should usually work OK.
Options are:
- "auto", "debian" or "redhat"
- "manual"
confdir="/etc/iptables"
(example)rulesfile="${confdir}/myrules"
(example)
Specify countries to block as "ISOCODE,Name"
(same as ipdeny.com), multiple entries should be separated by semicolon ;
Example:
COUNTRY="CN,China; US,United States; RU,Russia"
In case of issues check the log file '/var/log/ipset-country.log'.
To change log file location, set: LOG="/path/to/log"
Disable all logging: LOG="/dev/null 2>&1"
Or, log to screen only: LOG="/dev/stdout"
Set option FIREWALL
to: "iptables", "ntftables" or "firewalld"
Default is "iptables"
To block specified Countries, set MODE
to target "reject" or "drop" (blacklist).
To allow specified Countries and block all others, set MODE
to "accept" (whitelist).
Default is "reject".
The script will add iptables chains, rules and sets (needs ipset
).
Change DENY_RULENUM
to "1" to insert 'deny' rule at beginning of existing rules.
Or, set a specific rule number (see iptables --numeric -L INPUT --line-numbers
)
Default is 0 (add at end).
Uses nft with native sets. Needs at least a table and "input" chain already setup.
Minimal ipv4 example:
nft add table ip filter
nft add chain ip filter input \{ type filter hook input priority 0\; \}
table ip filter {
chain input {
type filter hook input priority filter; policy accept;
# ...
}
}
To use optional location specifier of an existing rule set NFT_RULE_LOC
. Default is empty/unset (""
), which appends.
Example: NFT_RULE_LOC="handle 3"
or NFT_RULE_LOC="index 5"
See nft --handle list ruleset
or man nft
for more details.
FirewallD does not support LOGIPS=1
or MODE='reject"
Set MODE
to "drop" or "accept":
- if mode is "accept", ipset will be added to "drop zone" as allowed (whitelist)
- if mode is "drop", ipset will added to "public zone" as denied (blacklist)
There are issues with firewalld and nft on CentOS/RHEL 8 which can cause your firewall to break resulting in being locked out. Adding large ipsets apparently can take a VERY long time. To abort, you need remote console access and run:
pkill firewal-cmd; nft flush ruleset
Unsupported frontend. Apparently it is possible to run both iptables and ufw and mix rules. Enable with
UFW=1
(untested).
Set URLs for ipv4 and/or ipv6 block files, you probably do not have to change these.
By default ipdeny.com is used
IPBLOCK_URL_V4="http://www.ipdeny.com/ipblocks/data/aggregated"
IPBLOCK_URL_V6="http://www.ipdeny.com/ipv6/ipaddresses/blocks"
To change to ipverse, set:
IPBLOCK_URL="https://raw.githubusercontent.com/ipverse/rir-ip/master/country"
Add argument -f
to load unchanged zonefiles instead of skipping
For more details see inside script.
Useful commands to check and clear blocked ips
ipset list
ipset test setname <ip>
ipset flush
ipset destroy
nft --handle list ruleset
nft list table ip filter
nft list sets
nft list set ip filter <proto>-<country>
(e.g. 'ipv4-china')nft list chain ip filter input
nft flush set ip filter <proto>-<country>
nft delete set ip filter <proto>-<country>
- [20250729] add suport for nftables
- [20250721] add option to inject rejct rule on specific rulenum (pr #22 by miathedev)
- [20220227] fixed iptables-legacy paths (pr #16 by mainboarder)
- [20201212] added config file option, systemd install (pr #14 by srulikuk)
- [20201108] added flush option, fix restore=0 (pr #13 by srulikuk)
- [20200927] fixed restore + logips bug (pr #10 by G4bbix)
- [20200605] added Blacklist/Whitelist mode (#3)
- [20200129] added option to DROP instead of REJECT (#1)
- [20191116] added ipverse support, md5check option
- [20190905] tested on debian 10 and centos 7
- [20190905] blocking multiple countries should work
- [20190905] it will check if INPUT chain exists in iptables
- [20190905] cleaned it up a bit
- [20190905] using firewalld is also supported now
Also available: github.com/tokiclover/dotfiles/blob/master/bin/ips.bash
This used to be a Gist but was moved here instead Please do not add Gist comments, but create an issue here