Firewalld Tutorial

Service

Install and enable Firewalld

$ apt-get install firewalld firewall-cmd
$ systemctl enable firewalld
$ systemctl start firewalld

Check if firewalld is active

$ firewall-cmd --state
running

Make current rules persistent

$ firewall-cmd --runtime-to-permanent
$ firewall-cmd --reload

Reload the firewall

$ firewall-cmd --reload

Interfaces

Get zone of interface

$ firewall-cmd --get-zone-of-interface tun0
external

Remove an interface from a zone

$ firewall-cmd --zone=external \
               --remove-interface tun0

Add an interface to a zone

$ firewall-cmd --zone=internal \ 
               --add-interface tun0

Zones

Get zone names

$ firewall-cmd --get-zones
FedoraServer FedoraWorkstation block dmz drop external home internal public trusted work

Get default zone

$ firewall-cmd --get-default-zone
public

Change the default zone

$ firewall-cmd --set-default-zone external

Adding a service to a zone

$ firewall-cmd --zone=home \
               --add-service ssh

Adding a source IP to a zone

$ firewall-cmd --zone=home \
               --add-source 203.0.113.224/27 

Adding a source MAC to a zone

$ firewall-cmd --zone=trusted \
               --add-source 5a:c2:5c:02:f3:e9

Get active zones

$ firewall-cmd --get-active-zones
external
 interfaces: ens3
home
 sources: 203.0.113.224/27
internal
 interfaces: tun0

Describe all zones and rules

$ firewall-cmd --list-all-zones
external (active)
  target: default
  icmp-block-inversion: no
  interfaces: ens3
  sources:
  services: openvpn
  ports:
  protocols:
  masquerade: yes
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

home (active)
  target: default
  icmp-block-inversion: no
  interfaces:
  sources: 203.0.113.224/27
  services: cockpit ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:

internal (active)
  target: default
  icmp-block-inversion: no
  interfaces: tun0
  sources:
  services: http https ssh cockpit dns
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules: 

Using the drop and trusted zone

Firewalld includes a special zone known as trusted that will unconditionally allow traffic.
“Trusted” sources or interfaces can be added to this zone.

$ firewall-cmd --zone trusted \
               --add-source 172.28.29.30 \

$ firewall-cmd --zone trusted \
               --add-interface virbr3

Firewalld also includes a drop zone which can be used to unconditionally drop traffic from specific interfaces or source addresses

$ firewall-cmd --zone drop \
               --add-source 169.254.0.0/16

Clear services from zones

Firewalld is preinstalled with a default configuration for every zone. For example, the home zone includes services such as samba and mDNS. I prefer starting with a clean slate. The command below will clear every service from every zone. Be careful not to lock yourself out!

for zone in $(firewall-cmd --get-zones); do firewall-cmd \
--list-services --zone=$zone | xargs -n1 firewall-cmd \
--zone=$zone --remove-service; done

Rich rules

Allow any traffic from source address

This rule allows any traffic with a source address of 10.20.30.40.
This rule only applies to sources/interfaces in the internal zone

$ firewall-cmd --zone=internal \
               --add-rich-rule 'rule 
                                family=ipv4 
                                source address=10.20.30.40 
                                accept'

Allow service from source address

This rule allows SSH if the source address is 192.0.2.111
This rule only applies to sources/interfaces in the external zone

$ firewall-cmd --zone=external \
               --add-rich-rule 'rule 
                                family=ipv4 
                                service name=ssh 
                                source address=192.0.2.111 
                                accept'

Allow traffic to destination address and port

This rule allows traffic to port 1194/udp if the destination address is 198.51.100.123.
This rule applies to the default zone

$ firewall-cmd --add-rich-rule 'rule 
                                family=ipv4 
                                protocol=udp port=1194
                                destination address=198.51.100.123 
                                accept'

Allow a service with rate-limit

$ firewall-cmd --add-rich-rule='rule 
                                service name=ssh 
                                limit value=10/m 

Accept a service and log (with ratelimit)

$ firewall-cmd --add-rich-rule='rule 
                                family=ipv4 
                                service name=ssh 
                                log prefix=ssh 
                                level=info
                                limit value=3/m 
                                accept

IPset

Define a new ipset

$ firewall-cmd --permanent \
               --new-ipset china 
               --type hash:net 

Add an ipset from XML file

$ firewall-cmd --permanent \ 
               --new-ipset-from-file=china.netset.xml \
               --name=china \

Add ipset entries from file

$ firewall-cmd --permanent \
               --ipset china \
               --add-entries-from-file ip2location_country_cn.netset

Block sources by ipset

$ firewall-cmd --permanent \
               --zone=drop \
               --source ipset:china

Find the XML file containing ipset

$ firewall-cmd --permanent --path-ipset china
/etc/firewalld/ipsets/china.xml

Miscellaneous

Time-limited rules

Using the timeout option, it is possible to set a maximum lifetime of a rule; the rules below will be automatically deleted after 60s

$ firewall-cmd --timeout 60 \
               --add-service https

$ firewall-cmd --timeout 60 \
               --add-rich-rule 'rule family=ipv4 
                                source address=10.122.4.20 
                                accept'

Adding traditional iptables rules

$ firewall-cmd --permanent \
               --direct \
               --add-rule ipv4 filter FORWARD 1 -i tun+ -d 10.0.0.0/8 -j DROP

Configure NAT masquerading

$ firewall-cmd --zone=external \
               --add-masquerade

Configure port forwarding

 $ firewall-cmd --zone=external \
                --add-forward-port 'port=8080:proto=tcp:toport=80:toaddr=10.10.10.10'