CentOS 7, CentOS 8, CentOS Stream 8, CentOS Stream 9 use firewalld service for the firewall of the machine. Firewalld service is easily controlled by the command-line tool firewall-cmd, which has a relatively simple syntax. It imposes an abstraction layer over the much more complex Linux kernels backends like iptables, ip6tables, arptables, ebtables, ipsetand, and nftables. The Firewalld organizes the firewall rules with the help of policies and zones, but there is a catch – it is not possible to list all the firewall rules to check whether an IP, network, or ethernet interface takes part in some rule or policy.
Yes, it is possible to list all rules of a firewalld zone (firewall-cmd –list-all), but what if there are multiple zones? First, get all the zone names and then enumerate all the zones with a list command to check for an IP. It is not practical and fast.
There is the other trick, searching through the Firewalld configuration files in the directory /etc/firewalld/, which saves all the permanent rules. But what if there are temporary rules, which are not saved in the configuration?
From CentOS 8.2 (RHEL 8.2) firewalld backend defaults to nftables instead of “iptables”. By using the nftables tools we can list all the rules applied in text or JSON format. It is like a snapshot of all the running rules applied by the Linux kernel firewall infrastructure no matter in which zone and policy. There is no such command with the firewall-cmd tool.
CentOS 8.2 (RHEL 8.2) and above including CentOS Stream 9
There is an export command using the nfs command line tool.
nft list ruleset
Here is a real case, of how the IP=5.5.5.5 is not visible at first check because the 5.5.5.5 is added in the newly user-created firewall zone and it is only in the running configuration (i.e. not permanent). Using grep would expose the presence of the 5.5.5.5 no matter in which zone it is added. The user should enumerate all zones if he does not know where to look for the IP. There are 10 built-in firewall zones.
[root@srv ~]# firewall-cmd --list-all public (active) target: default icmp-block-inversion: no interfaces: enp0s3 sources: services: cockpit dhcpv6-client ssh ports: protocols: forward: yes masquerade: no forward-ports: source-ports: icmp-blocks: rich rules: [root@srv ~]# nft list ruleset|grep 5.5.5.5 ip saddr 5.5.5.5 goto mangle_PRE_testzone ip saddr 5.5.5.5 goto nat_PRE_testzone ip daddr 5.5.5.5 goto nat_POST_testzone ip saddr 5.5.5.5 goto filter_IN_testzone ip saddr 5.5.5.5 goto filter_FWD_testzone
Just one command nft will output all the running firewall rules and using grep it shows the lines with the IP
The IP 5.5.5.5 could be find in user-created firewall zone testzone:
[root@srv ~]# firewall-cmd --get-zones block dmz drop external home internal nm-shared public testzone trusted work [root@srv ~]# firewall-cmd --list-all --zone=testzone testzone (active) target: default icmp-block-inversion: no interfaces: sources: 5.5.5.5 services: ports: protocols: forward: no masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
It is not fast and easy to list all the zones’ rules. In fact, some firewall rules may not even be listed such as passthrough rules with –direct –add-passthrough.
There are all the default rules in CentOS Stream 9 exported with nft.
[root@srv ~]# nft list ruleset table inet firewalld { chain mangle_PREROUTING { type filter hook prerouting priority mangle + 10; policy accept; jump mangle_PREROUTING_ZONES } chain mangle_PREROUTING_POLICIES_pre { jump mangle_PRE_policy_allow-host-ipv6 } chain mangle_PREROUTING_ZONES { iifname "enp0s3" goto mangle_PRE_public goto mangle_PRE_public } chain mangle_PREROUTING_POLICIES_post { } chain nat_PREROUTING { type nat hook prerouting priority dstnat + 10; policy accept; jump nat_PREROUTING_ZONES } chain nat_PREROUTING_POLICIES_pre { jump nat_PRE_policy_allow-host-ipv6 } chain nat_PREROUTING_ZONES { iifname "enp0s3" goto nat_PRE_public goto nat_PRE_public } chain nat_PREROUTING_POLICIES_post { } chain nat_POSTROUTING { type nat hook postrouting priority srcnat + 10; policy accept; jump nat_POSTROUTING_ZONES } chain nat_POSTROUTING_POLICIES_pre { } chain nat_POSTROUTING_ZONES { oifname "enp0s3" goto nat_POST_public goto nat_POST_public } chain nat_POSTROUTING_POLICIES_post { } chain filter_PREROUTING { type filter hook prerouting priority filter + 10; policy accept; icmpv6 type { nd-router-advert, nd-neighbor-solicit } accept meta nfproto ipv6 fib saddr . mark . iif oif missing drop } chain filter_INPUT { type filter hook input priority filter + 10; policy accept; ct state { established, related } accept ct status dnat accept iifname "lo" accept jump filter_INPUT_ZONES ct state invalid drop reject with icmpx admin-prohibited } chain filter_FORWARD { type filter hook forward priority filter + 10; policy accept; ct state { established, related } accept ct status dnat accept iifname "lo" accept ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable jump filter_FORWARD_ZONES ct state invalid drop reject with icmpx admin-prohibited } chain filter_OUTPUT { type filter hook output priority filter + 10; policy accept; ct state { established, related } accept oifname "lo" accept ip6 daddr { ::/96, ::ffff:0.0.0.0/96, 2002::/24, 2002:a00::/24, 2002:7f00::/24, 2002:a9fe::/32, 2002:ac10::/28, 2002:c0a8::/32, 2002:e000::/19 } reject with icmpv6 addr-unreachable jump filter_OUTPUT_POLICIES_pre jump filter_OUTPUT_POLICIES_post } chain filter_INPUT_POLICIES_pre { jump filter_IN_policy_allow-host-ipv6 } chain filter_INPUT_ZONES { iifname "enp0s3" goto filter_IN_public goto filter_IN_public } chain filter_INPUT_POLICIES_post { } chain filter_FORWARD_POLICIES_pre { } chain filter_FORWARD_ZONES { iifname "enp0s3" goto filter_FWD_public goto filter_FWD_public } chain filter_FORWARD_POLICIES_post { } chain filter_OUTPUT_POLICIES_pre { } chain filter_OUTPUT_POLICIES_post { } chain filter_IN_public { jump filter_INPUT_POLICIES_pre jump filter_IN_public_pre jump filter_IN_public_log jump filter_IN_public_deny jump filter_IN_public_allow jump filter_IN_public_post jump filter_INPUT_POLICIES_post meta l4proto { icmp, ipv6-icmp } accept reject with icmpx admin-prohibited } chain filter_IN_public_pre { } chain filter_IN_public_log { } chain filter_IN_public_deny { } chain filter_IN_public_allow { tcp dport 22 ct state { new, untracked } accept ip6 daddr fe80::/64 udp dport 546 ct state { new, untracked } accept tcp dport 9090 ct state { new, untracked } accept } chain filter_IN_public_post { } chain nat_POST_public { jump nat_POSTROUTING_POLICIES_pre jump nat_POST_public_pre jump nat_POST_public_log jump nat_POST_public_deny jump nat_POST_public_allow jump nat_POST_public_post jump nat_POSTROUTING_POLICIES_post } chain nat_POST_public_pre { } chain nat_POST_public_log { } chain nat_POST_public_deny { } chain nat_POST_public_allow { } chain nat_POST_public_post { } chain filter_FWD_public { jump filter_FORWARD_POLICIES_pre jump filter_FWD_public_pre jump filter_FWD_public_log jump filter_FWD_public_deny jump filter_FWD_public_allow jump filter_FWD_public_post jump filter_FORWARD_POLICIES_post reject with icmpx admin-prohibited } chain filter_FWD_public_pre { } chain filter_FWD_public_log { } chain filter_FWD_public_deny { } chain filter_FWD_public_allow { oifname "enp0s3" accept } chain filter_FWD_public_post { } chain nat_PRE_public { jump nat_PREROUTING_POLICIES_pre jump nat_PRE_public_pre jump nat_PRE_public_log jump nat_PRE_public_deny jump nat_PRE_public_allow jump nat_PRE_public_post jump nat_PREROUTING_POLICIES_post } chain nat_PRE_public_pre { } chain nat_PRE_public_log { } chain nat_PRE_public_deny { } chain nat_PRE_public_allow { } chain nat_PRE_public_post { } chain mangle_PRE_public { jump mangle_PREROUTING_POLICIES_pre jump mangle_PRE_public_pre jump mangle_PRE_public_log jump mangle_PRE_public_deny jump mangle_PRE_public_allow jump mangle_PRE_public_post jump mangle_PREROUTING_POLICIES_post } chain mangle_PRE_public_pre { } chain mangle_PRE_public_log { } chain mangle_PRE_public_deny { } chain mangle_PRE_public_allow { } chain mangle_PRE_public_post { } chain filter_IN_policy_allow-host-ipv6 { jump filter_IN_policy_allow-host-ipv6_pre jump filter_IN_policy_allow-host-ipv6_log jump filter_IN_policy_allow-host-ipv6_deny jump filter_IN_policy_allow-host-ipv6_allow jump filter_IN_policy_allow-host-ipv6_post } chain filter_IN_policy_allow-host-ipv6_pre { } chain filter_IN_policy_allow-host-ipv6_log { } chain filter_IN_policy_allow-host-ipv6_deny { } chain filter_IN_policy_allow-host-ipv6_allow { icmpv6 type nd-neighbor-advert accept icmpv6 type nd-neighbor-solicit accept icmpv6 type nd-router-advert accept icmpv6 type nd-redirect accept } chain filter_IN_policy_allow-host-ipv6_post { } chain nat_PRE_policy_allow-host-ipv6 { jump nat_PRE_policy_allow-host-ipv6_pre jump nat_PRE_policy_allow-host-ipv6_log jump nat_PRE_policy_allow-host-ipv6_deny jump nat_PRE_policy_allow-host-ipv6_allow jump nat_PRE_policy_allow-host-ipv6_post } chain nat_PRE_policy_allow-host-ipv6_pre { } chain nat_PRE_policy_allow-host-ipv6_log { } chain nat_PRE_policy_allow-host-ipv6_deny { } chain nat_PRE_policy_allow-host-ipv6_allow { } chain nat_PRE_policy_allow-host-ipv6_post { } chain mangle_PRE_policy_allow-host-ipv6 { jump mangle_PRE_policy_allow-host-ipv6_pre jump mangle_PRE_policy_allow-host-ipv6_log jump mangle_PRE_policy_allow-host-ipv6_deny jump mangle_PRE_policy_allow-host-ipv6_allow jump mangle_PRE_policy_allow-host-ipv6_post } chain mangle_PRE_policy_allow-host-ipv6_pre { } chain mangle_PRE_policy_allow-host-ipv6_log { } chain mangle_PRE_policy_allow-host-ipv6_deny { } chain mangle_PRE_policy_allow-host-ipv6_allow { } chain mangle_PRE_policy_allow-host-ipv6_post { } }
Older system with firewalld
Older systems with firewalld service use the iptables utility to manage the firewall. Such systems are older than CentOS 8.2 like CentOS 7 and some older versions of Ubuntu.
Use the iptables-save command to output all the firewall rules to the console or file:
[root@srv ~]# iptables-save |grep 5.5.5.5 -A POSTROUTING_ZONES_SOURCE -d 5.5.5.5/32 -g POST_testzone -A PREROUTING_ZONES_SOURCE -s 5.5.5.5/32 -g PRE_testzone -A PREROUTING_ZONES_SOURCE -s 5.5.5.5/32 -g PRE_testzone -A PREROUTING_ZONES_SOURCE -s 5.5.5.5/32 -g PRE_testzone -A FORWARD_IN_ZONES_SOURCE -s 5.5.5.5/32 -g FWDI_testzone -A FORWARD_OUT_ZONES_SOURCE -d 5.5.5.5/32 -g FWDO_testzone -A INPUT_ZONES_SOURCE -s 5.5.5.5/32 -g IN_testzone
The firewalld syntax is the same suing firewall-cmd
[root@srv ~]# firewall-cmd --get-zones block dmz drop external home internal public testzone trusted work [root@srv ~]# firewall-cmd --list-all --zone=testzone testzone (active) target: default icmp-block-inversion: no interfaces: sources: 5.5.5.5 services: ports: protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
It should be explicitly enumerated all the firewall zones and their rules to find an IP/network/rule in them.
The default CentOS 7 firewall rules are dumped with iptables-save command.
[root@srv ~]# iptables-save # Generated by iptables-save v1.4.21 on Tue Feb 14 10:52:25 2023 *nat :PREROUTING ACCEPT [2:253] :INPUT ACCEPT [1:60] :OUTPUT ACCEPT [1:72] :POSTROUTING ACCEPT [1:72] :OUTPUT_direct - [0:0] :POSTROUTING_ZONES - [0:0] :POSTROUTING_ZONES_SOURCE - [0:0] :POSTROUTING_direct - [0:0] :POST_public - [0:0] :POST_public_allow - [0:0] :POST_public_deny - [0:0] :POST_public_log - [0:0] :PREROUTING_ZONES - [0:0] :PREROUTING_ZONES_SOURCE - [0:0] :PREROUTING_direct - [0:0] :PRE_public - [0:0] :PRE_public_allow - [0:0] :PRE_public_deny - [0:0] :PRE_public_log - [0:0] -A PREROUTING -j PREROUTING_direct -A PREROUTING -j PREROUTING_ZONES_SOURCE -A PREROUTING -j PREROUTING_ZONES -A OUTPUT -j OUTPUT_direct -A POSTROUTING -j POSTROUTING_direct -A POSTROUTING -j POSTROUTING_ZONES_SOURCE -A POSTROUTING -j POSTROUTING_ZONES -A POSTROUTING_ZONES -o enp0s3 -g POST_public -A POSTROUTING_ZONES -g POST_public -A POST_public -j POST_public_log -A POST_public -j POST_public_deny -A POST_public -j POST_public_allow -A PREROUTING_ZONES -i enp0s3 -g PRE_public -A PREROUTING_ZONES -g PRE_public -A PRE_public -j PRE_public_log -A PRE_public -j PRE_public_deny -A PRE_public -j PRE_public_allow COMMIT # Completed on Tue Feb 14 10:52:25 2023 # Generated by iptables-save v1.4.21 on Tue Feb 14 10:52:25 2023 *mangle :PREROUTING ACCEPT [87:8758] :INPUT ACCEPT [87:8758] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [61:47725] :POSTROUTING ACCEPT [61:47725] :FORWARD_direct - [0:0] :INPUT_direct - [0:0] :OUTPUT_direct - [0:0] :POSTROUTING_direct - [0:0] :PREROUTING_ZONES - [0:0] :PREROUTING_ZONES_SOURCE - [0:0] :PREROUTING_direct - [0:0] :PRE_public - [0:0] :PRE_public_allow - [0:0] :PRE_public_deny - [0:0] :PRE_public_log - [0:0] -A PREROUTING -j PREROUTING_direct -A PREROUTING -j PREROUTING_ZONES_SOURCE -A PREROUTING -j PREROUTING_ZONES -A INPUT -j INPUT_direct -A FORWARD -j FORWARD_direct -A OUTPUT -j OUTPUT_direct -A POSTROUTING -j POSTROUTING_direct -A PREROUTING_ZONES -i enp0s3 -g PRE_public -A PREROUTING_ZONES -g PRE_public -A PRE_public -j PRE_public_log -A PRE_public -j PRE_public_deny -A PRE_public -j PRE_public_allow COMMIT # Completed on Tue Feb 14 10:52:25 2023 # Generated by iptables-save v1.4.21 on Tue Feb 14 10:52:25 2023 *security :INPUT ACCEPT [87:8617] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [62:49365] :FORWARD_direct - [0:0] :INPUT_direct - [0:0] :OUTPUT_direct - [0:0] -A INPUT -j INPUT_direct -A FORWARD -j FORWARD_direct -A OUTPUT -j OUTPUT_direct COMMIT # Completed on Tue Feb 14 10:52:25 2023 # Generated by iptables-save v1.4.21 on Tue Feb 14 10:52:25 2023 *raw :PREROUTING ACCEPT [88:8810] :OUTPUT ACCEPT [62:49365] :OUTPUT_direct - [0:0] :PREROUTING_ZONES - [0:0] :PREROUTING_ZONES_SOURCE - [0:0] :PREROUTING_direct - [0:0] :PRE_public - [0:0] :PRE_public_allow - [0:0] :PRE_public_deny - [0:0] :PRE_public_log - [0:0] -A PREROUTING -j PREROUTING_direct -A PREROUTING -j PREROUTING_ZONES_SOURCE -A PREROUTING -j PREROUTING_ZONES -A OUTPUT -j OUTPUT_direct -A PREROUTING_ZONES -i enp0s3 -g PRE_public -A PREROUTING_ZONES -g PRE_public -A PRE_public -j PRE_public_log -A PRE_public -j PRE_public_deny -A PRE_public -j PRE_public_allow COMMIT # Completed on Tue Feb 14 10:52:25 2023 # Generated by iptables-save v1.4.21 on Tue Feb 14 10:52:25 2023 *filter :INPUT ACCEPT [0:0] :FORWARD ACCEPT [0:0] :OUTPUT ACCEPT [62:49365] :FORWARD_IN_ZONES - [0:0] :FORWARD_IN_ZONES_SOURCE - [0:0] :FORWARD_OUT_ZONES - [0:0] :FORWARD_OUT_ZONES_SOURCE - [0:0] :FORWARD_direct - [0:0] :FWDI_public - [0:0] :FWDI_public_allow - [0:0] :FWDI_public_deny - [0:0] :FWDI_public_log - [0:0] :FWDO_public - [0:0] :FWDO_public_allow - [0:0] :FWDO_public_deny - [0:0] :FWDO_public_log - [0:0] :INPUT_ZONES - [0:0] :INPUT_ZONES_SOURCE - [0:0] :INPUT_direct - [0:0] :IN_public - [0:0] :IN_public_allow - [0:0] :IN_public_deny - [0:0] :IN_public_log - [0:0] :OUTPUT_direct - [0:0] -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A INPUT -i lo -j ACCEPT -A INPUT -j INPUT_direct -A INPUT -j INPUT_ZONES_SOURCE -A INPUT -j INPUT_ZONES -A INPUT -m conntrack --ctstate INVALID -j DROP -A INPUT -j REJECT --reject-with icmp-host-prohibited -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -i lo -j ACCEPT -A FORWARD -j FORWARD_direct -A FORWARD -j FORWARD_IN_ZONES_SOURCE -A FORWARD -j FORWARD_IN_ZONES -A FORWARD -j FORWARD_OUT_ZONES_SOURCE -A FORWARD -j FORWARD_OUT_ZONES -A FORWARD -m conntrack --ctstate INVALID -j DROP -A FORWARD -j REJECT --reject-with icmp-host-prohibited -A OUTPUT -o lo -j ACCEPT -A OUTPUT -j OUTPUT_direct -A FORWARD_IN_ZONES -i enp0s3 -g FWDI_public -A FORWARD_IN_ZONES -g FWDI_public -A FORWARD_OUT_ZONES -o enp0s3 -g FWDO_public -A FORWARD_OUT_ZONES -g FWDO_public -A FWDI_public -j FWDI_public_log -A FWDI_public -j FWDI_public_deny -A FWDI_public -j FWDI_public_allow -A FWDI_public -p icmp -j ACCEPT -A FWDO_public -j FWDO_public_log -A FWDO_public -j FWDO_public_deny -A FWDO_public -j FWDO_public_allow -A INPUT_ZONES -i enp0s3 -g IN_public -A INPUT_ZONES -g IN_public -A IN_public -j IN_public_log -A IN_public -j IN_public_deny -A IN_public -j IN_public_allow -A IN_public -p icmp -j ACCEPT -A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW,UNTRACKED -j ACCEPT COMMIT # Completed on Tue Feb 14 10:52:25 2023