Technotes for future me


firewall-cmd --list-all
firewall-cmd --get-active-zones
firewall-cmd --zone=internal --permanent --add-port=5678/tcp
firewall-cmd --list-all --zone=internal
firewall-cmd --reload

firewall-cmd --state
firewall-cmd --get-services
firewall-cmd --zone=public --add-service=http --permanent
firewall-cmd --get-default-zone
firewall-cmd --set-default-zone=internal

firewall-cmd --list-all-zones

firewall-cmd --get-active-zones
firewall-cmd --zone=public --add-port=12345/tcp --permanent
firewall-cmd --zone=public --remove-port=12345/tcp --permanent
firewall-cmd --zone=public --add-masquerade

firewall-cmd --zone="public" --add-forward-port=port=80:proto=tcp:toport=12345
firewall-cmd --zone="public" --add-forward-port=port=80:proto=tcp:toport=8080:toaddr=123.456.78.9

firewall-cmd --zone=public --add-rich-rule 'rule family="ipv4" source address= accept'
firewall-cmd --list-rich-rules

firewall-cmd --zone=public --permanent --add-rich-rule='rule source ipset="blacklist" log prefix="FirewallD dropped: " level="info" drop'

firewall-cmd --permanent --new-ipset=blacklist --type=hash:ip
firewall-cmd --reload
firewall-cmd --ipset=blacklist --add-entry=
firewall-cmd --add-rich-rule='rule source ipset=blacklist drop'
firewall-cmd --permanent --new-ipset=blacklist6 --type=hash:ip --option=family=inet6
firewall-cmd --ipset=blacklist6 --add-entry=fe80::07FF:0004

In a previous post, I mentioned how to create an ipset blacklist. In recent versions of firewalld, the developers implemented support for ipset from within firewalld, thus there is no need to setup ipset separately. Here is a quick and easy way to create an IP/net blacklist by using the new firewall-cmd commands. At the same time I will demonstrate how to block entire countries from being able to access your server.

Create the blacklist:

firewall-cmd --permanent --new-ipset=blacklist --type=hash:net --option=family=inet --option=hashsize=4096 --option=maxelem=200000
* –permanent = use to make changes to the permanent configuration

    –new-ipset = name of the new IP/net blacklist

    –type = storage hash type, "net" is for subnets, while "ip" for individual ip addresses

    –option=family = IPv4 or IPv6 network, inet is for IPv4

    –option=hashsize = the initial hash size of the list

    –option=maxelem = max number of elements

Download net blocks:

tar -vxzf all-zones.tar.gz

Choose which countries you would like to block, provides net blocks by country. The above command will download all country zones together in one archive. Once extracted you should end up with various files, each named after a country, for example “” for China. I can’t tell you what to block, it all depends on what kind of service you provide and the location of your “real” requests. Personally, I run many major European sites and based on my logs, I block the following countries: ar bd bg br by cn co il in ir kp ly mn mu pa sd tw ua ro ru ve vn

After block the above countries, SPAM and hacking attempts dropped to nearly zero. Pretty much anything else comes via a European or American proxy, but that is easy to mitigate, once I file an abuse report to their network provider, the proxy is usually shut down rather quickly. While orchestrated and methodical hacks won’t be mitigated by a simple country block list, everything else will be blocked, especially spam.

Populate the blacklist:

firewall-cmd --permanent --ipset=blacklist --add-entries-from-file=./

The above command will load a country zone file to our blacklist. Make sure to change the path and filename to your chosen country zone file. You may also add individual IP addresses or net blocks by yourself, from the shell or by using a tool like fail2ban, with the following simple shell script (for example, save it as ~/bin/ban):

firewall-cmd --permanent --ipset=blacklist --add-entry=$1
firewall-cmd --ipset=blacklist --add-entry=$1

Run it like this:


Redirect the blacklist to the drop zone

firewall-cmd --permanent --zone=drop --add-source=ipset:blacklist
firewall-cmd --reload

So far, we have created a blacklist and populated it with IP addresses and net blocks, but it is not blocking anything. In order to use our blacklist, we set it as a firewall “source”, this means that anything that matches our blacklist will be redirected to a specific zone. Thus, by redirecting the blacklist to the “drop” zone, we effectively block all connections that match our blacklist. Simple and effective. The reload command at the end is needed to bring our permanent changes to the live/running firewall.

iptables Examples

ipset create smtpblocks hash:net counters
ipset add smtpblocks
ipset add smtpblocks
iptables -A INPUT -p tcp --dport 25 -m set --match-set smtpblocks src -j DROP

iptables allow

iptables -A INPUT -i eth0 -p tcp --dport 22 -j ACCEPT

iptables - Loopback Routing

iptables -t nat -A POSTROUTING -d <internal web server IP> -s <internal network address> -p tcp --dport 80 -j SNAT --to-source <external web server IP>

iptables - Show active rules

iptables -S
iptables -L
iptables -L <table>

iptables - Full flush

iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
iptables -P INPUT ACCEPT

iptables - Allow established

iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT

iptables - Log failed requests

iptables -I INPUT 5 -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

iptables - Persistency on Debian

apt-get install iptables-persistent

# Set some rules and call
invoke-rc.d iptables-persistent save


Default Rules

sudo ufw default allow outgoing
sudo ufw default deny incoming


ufw enable
ufw status

Allow rule

ufw allow ssh
ufw allow 22
ufw allow 80/tcp
ufw allow http/tcp
ufw allow 1725/udp
ufw allow from
ufw allow from
ufw allow from to any port 22 proto tcp

Deny rule

ufw deny 111

Delete rule

ufw delete allow 80


ufw logging on
ufw logging low|medium|high

A normal log entry will resemble the following, and will be located at /var/logs/ufw:

Sep 16 15:08:14 <hostname> kernel: [UFW BLOCK] IN=eth0 OUT= MAC=00:00:00:00:00:00:00:00:00:00:00:00:00:00 SRC= DST=987.65.43.21 LEN=40 TOS=0x00 PREC=0x00 TTL=249 ID=8475 PROTO=TCP SPT=48247 DPT=22 WINDOW=1024 RES=0x00 SYN URGP=0

The initial values list the date, time, and hostname. Additional important values include:

  • [UFW BLOCK]: This location is where the description of the logged event will be located. In this instance, it blocked a connection.

  • IN: If this contains a value, then the event was incoming

  • OUT: If this contain a value, then the event was outgoing

  • MAC: A combination of the destination and source MAC addresses

  • SRC: The IP of the packet source

  • DST: The IP of the packet destination

  • LEN: Packet length

  • TTL: The packet TTL, or time to live. How long it will bounce between routers until it expires, if no destination is found.

  • PROTO: The packet’s protocol

  • SPT: The source port of the package

  • DPT: The destination port of the package

  • WINDOW: The size of the packet the sender can receive

  • SYN URGP: Indicated if a three-way handshake is required. 0 means it is not.


nft list tables
nft list chains

nft add    <table|chain|rule> ...
nft list   <table|chain|rule> ...
nft flush  <table|chain|rule> ...
nft delete <table|chain|rule> ...

List rules with numbers

nft list ruleset -a

Simple Example

Create new table and chain

nft add table    inet table1
nft create chain inet table1 { type filter hook input priority 0\; }
nft add rule     inet table1 chain1 iif lo accept

Allow existing and outbind, as well as SSH

nft add rule     inet table1 chain1 ct state established,related accept
nft add rule     inet table1 chain1 tcp dport 22 ct state new accept

Default drop policy

nft add rule     inet table1 chain1 drop


Inject rule at position

nft add rule inet table1 chain1 position <number> <rule>

Convert iptables to nftables

Check out iptables-translate

Debug rule changes

nft monitor               # Reports all rule changes live
nft monitor new tables
nft monitor destroy rules
Last updated on 31 Jan 2021
Published on 11 Dec 2019
Edit on GitHub