
Iptables and Beyond
The iptables project, developed by Rusty Russell in 1999 for managing netfilter, replaced tools like ipchains and ipnatctl in the 2.4 Linux kernel, offering a more expandable way to filter packets, giving system administrators greater control and simplifying rule creation. With ipchains, an administrator had to create a rule in each chain to trace a packet’s entire route, whereas now, a single rule is sufficient. The introduction of modules allowed for easy expansion of capabilities. Over time, iptables was ported to IPv6 (in 2011, as ip6tables), and additional modules like ULOG and nf_conntrack were added, enabling various packet manipulations, traffic classification up to the OSI model’s seventh layer, load balancing, and more. As the number of features grew, the configurations became more complex. Despite some unification, each extension has its own syntax; some support ranges, negation, and prefixes, while others do not. Initially, any rule changes required a complete firewall restart, including unloading modules, which led to disconnections of established connections. This issue no longer exists.
In simple cases, configuring with iptables is straightforward, but in complex networks, managing a large number of rules becomes challenging. Understanding all the settings and how it operates requires time. It’s difficult to immediately grasp what each chain does, and rules start to repeat, making them hard to maintain, update, and transfer to other systems.
It’s not surprising that various tools have been developed to address these issues. In Ubuntu, for instance, ufw (Uncomplicated Firewall) is used for straightforward configuration of firewall rules. For example, to allow access to the SSH port, you simply need to enter
$ sudo ufw allow 22
Application developers can create pre-configured profiles that activate when the package is installed, saving users from having to create and input rules themselves.
Another well-known project that simplifies the maintenance of complex rules is FERM (for Easy Rule Making). FERM stores all rules in a single file that is easy to read, edit, and load with a single command. This file can be effortlessly transferred between computers. The rules themselves are organized into blocks and can include variables and lists, allowing for the same configurations to be more concise and understandable. The final size of FERM rules is about three times smaller than equivalent configurations for iptables. For example, you can block all connections except for HTTP, SSH, and FTP.
chain INPUT {
policy DROP;
mod state state (RELATED ESTABLISHED) ACCEPT;
proto tcp dport (http ssh ftp) ACCEPT;
}
Under the hood, FERM is essentially a Perl script that converts configuration files into iptables rules.
In Fedora 18, the firewalld daemon was announced, which became the official tool for managing netfilter settings in RHEL 7 / CentOS 7. These systems are becoming increasingly popular on VDS, so it’s important to be aware of their specific features.
Features of Firewalld
Firewalld operates as a daemon, allowing new rules to be added without restarting or resetting the existing firewall. Configuration changes can be made at any time and are applied instantly, with no need to save or manually apply them. It supports IPv4, IPv6, automatic kernel module loading, and network zones to define the trust level of connections. Firewalld offers an easy interface for adding rules for services and applications, as well as a whitelist for applications authorized to change rules. Currently, it is supported by libvirt, Docker, fail2ban, Puppet, the Virtuozzo installation script, and many other projects. YUM repositories already include packages like fail2ban-firewalld and puppet-firewalld, making it possible to enable them with a single command.
Firewalld provides information about the current firewall settings via a D-Bus API and accepts changes through D-Bus using PolicyKit authentication methods. It uses iptables, ip6tables, ebtables, and ipset as backends, with plans to integrate nftables. However, firewalld cannot interpret rules created directly by these utilities, so both methods cannot be used simultaneously.
Management is done using command-line utilities like firewall-cmd
or the graphical firewall-config
, which allows you to configure all the rules in a user-friendly environment. The firewall-offline-cmd
utility is used to assist in migrating current iptables rules to firewalld
, and by default, it reads from /
. Recent releases include the firewallctl
utility, which features a simple syntax and enables you to get information about the service’s status, firewall configuration, and to modify rules.


Checking the status:
# systemctl status firewalld
# firewall-cmd --state
running
Allowing a connection on a specific port is quite straightforward:
# firewall-cmd --permanent --add-port=22/tcp
For any changes to take effect, you must always run a command after making edits.
# firewall-cmd --reload
The parameter --remove-port
is used to delete a port from the rules:
# firewall-cmd --remove-port=22/tcp
In general, many --add-*
commands have corresponding --query-*
for status checks, --list-*
for lists, --change-*
for modifications, or --remove
for deleting the respective values. For brevity, we’ll not dwell further on these details. After reloading the rules, let’s proceed to check:
# firewall-cmd --list-ports
Firewalld includes a mode that allows you to block all connections with a single command:
# firewall-cmd --panic-on
To check which mode the firewall is in, there is a special command:
# firewall-cmd --query-panic
Disabling panic mode:
# firewall-cmd --panic-off
With firewalld, you don’t need to know which port is associated with a service; you just need to specify the service name. The utility will handle the rest.
Once firewalld is installed, it recognizes the configurations of over 50 services. Let’s get the list of these services.
# firewall-cmd --get-services
Let’s enable the connection to HTTP:
# firewall-cmd --add-service=http
By using curly braces, you can configure multiple services simultaneously. Information about service settings is available through
# firewall-cmd --info-service=http
Firewalld stores all its configurations in XML files located in directories under /usr/lib/firewalld. Specifically, the services are found in the services directory. Inside each file, you’ll find details such as the name, protocol, and port.
<?xml version="1.0" encoding="utf-8"?><service> <short>MySQL</short> <description>MySQL Database Server</description> <port protocol="tcp" port="3600"/></service>
This is a system directory, and nothing should be changed there. If you need to override settings or create your own service, copy any file as a template into /
, modify it according to your needs, and apply the settings.
A separate set of rules is used for configuring ICMP. Here’s how to get a list of supported ICMP types:
# firewall-cmd --get-icmptypes
Checking the status:
# firewall-cmd --zone=public --query-icmp-block=echo-reply
# firewall-cmd --zone=public --add-icmp-block=echo-reply


Zone Management
In firewalld, zones are used to determine the level of trust for a network connection. A zone can contain multiple network connections, but each network connection can only belong to one zone. You can get a list of all zones using the command firewall-cmd
.

Upon installation, nine zones are created. Depending on the purpose, one or more of these zones can be utilized:
- Trusted: All network connections are allowed.
- Work/Home/Internal: These zones have similar settings with different purposes. Maximum trust is given to computers on the network, allowing only specific incoming connections (by default SSH and DHCPv6 client; with home and internal also allowing MDNS and Samba client).
- DMZ: For computers in a demilitarized zone, accessible from the Internet with limited access to the internal network. Only specified incoming connections are allowed (by default SSH).
- External: A rule suitable for routers to be used in external networks with masquerading enabled, characterized by maximum distrust and clearly defined allowed incoming connections (by default SSH).
- Public: For use in public places, with maximum distrust towards other computers, allowing only specific incoming connections (by default SSH and DHCPv6 client).
- Block: Incoming network connections are rejected with an icmp-host-prohibited message, only connections initiated from this system are allowed.
- Drop: Only outgoing connections are allowed, all incoming connections are blocked.
Zone descriptions are also provided in XML files located in /
.
After installing the system, the ‘public’ zone is typically used. If the existing zones are not sufficient, you can create new zones using the appropriate tools.
# firewall-cmd --permanent --new-zone=zone_name

All packets that do not fall within specified zones are processed in the default zone.
# firewall-cmd --get-default-zone
Now, let’s look at which zones are currently active and which interfaces are associated with them.
# firewall-cmd --get-active-zones
We can also obtain feedback on which zone the interface is associated with.
# firewall-cmd --get-zone-of-interface=eno1
Let’s review the zone settings (services, ports, protocols, etc.).
# firewall-cmd --zone=public --list-all
# firewall-cmd --zone=public --list-services
If the parameter is empty, it means that the settings have not been configured. If needed, reassign the interface to the zone:
# firewall-cmd --zone=home --add-interface=eno1 --permanent
If you check the output of firewall-cmd
now, you’ll notice that the network interface is missing from the setup list. Let’s allow the service connection:
# firewall-cmd --zone=home --add-service=openvpn --permanent
Here’s how you can remove it:
# firewall-cmd --zone=home --remove-service=openvpn --permanent
Zones can also be associated with other sources, identified by MAC address, individual IP, or network address. Any packet arriving from such a source will be processed according to the zone’s rules.
# firewall-cmd --permanent --zone=trusted --add-source=192.168.1.0/24
You can view the list of all sources using --zone=trusted
. NAT, which allows multiple computers to connect to the network, can be enabled in firewalld with a single command. To check the current masquerade settings:
# firewall-cmd --zone=external --query-masquerade
If the response we receive is no
, then activate:
# firewall-cmd --zone=external --add-masquerade
That’s all. To enable external access, we’ll set up port forwarding to one of the computers. For example, if we need SSH access to an internal server:
# firewall-cmd --zone=external --add-forward-port=port=22:proto=tcp:toport=22:toaddr=192.168.1.100
Let’s check:
# firewall-cmd --zone=external --list-all
The forwarding rule can be deleted using --remove-forward-port
.
Advanced Rules
For individual PCs or small networks, the basic features are usually sufficient. To configure complex rules in firewalld, a so-called direct syntax was initially proposed, and a Rich Language was introduced later. The first option requires knowledge of iptables syntax and is recommended only as a last resort since rules do not persist after a reboot.
The syntax for a direct rule is as follows:
# firewall-cmd [--permanent] --direct --add-rule { ipv4 | ipv6 | eb } <table> <chain> <priority> <args>
The syntax for <
is exactly the same as that of iptables. Here’s how to retrieve the current settings:
# firewall-cmd --direct --get-chains ipv4 filter
# firewall-cmd --direct --get-rules ipv4 filter input
Add a rule that allows connections through port 25:
# firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -m tcp -p tcp --dport 25 -j ACCEPT
Let’s forward the connection on port 22 to another server:
# firewall-cmd --permanent --direct --add-rule ipv4 filter FORWARD 0 -i eno1 -o eno2 -p tcp --dport 22 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
Let’s check:
# firewall-cmd --direct --get-all-rules
Rich Language allows you to write complex rules in a more comprehensible format. In a rule, you can specify any parameters that define a packet, such as source, destination, service, port, protocol, masquerading, logging, auditing, and action. For instance, you can permit a subnet to connect via HTTP and add auditing:
# firewall-cmd --permanent --zone=public --add-rich-rule="rule family="ipv4" source address="192.168.0.0/24" service name="http" audit limit value="1/m" accept
A significant advantage of Rich Language is that all parameters can be described in XML within the zone file. The file format is very straightforward and mirrors the parameter names:
<rule> <service name="ssh"/> <accept/></rule>
PANEL
Configuring a firewall is often a matter of habit. Many people find it more convenient to use a command they’ve relied on for years rather than learning a new utility. That’s why sometimes there’s a desire to bring back the classic tool. This isn’t an issue. Iptables isn’t included in CentOS 7 by default, so you’ll need to reinstall it:
# yum install -y iptables-services
To avoid having to configure everything from scratch, it’s better to save the current rules generated by firewalld.
# iptables-save > /etc/sysconfig/iptables
# ip6tables-save > /etc/sysconfig/ip6tables
Stopping firewalld and starting iptables:
# systemctl stop firewalld && systemctl disable firewalld
# systemctl start iptables && systemctl enable iptables
# systemctl start ip6tables && systemctl enable ip6tables
Reviewing the current rules:
# iptables -L
# iptables -S
Prevent firewalld from automatically starting when the OS boots:
# systemctl disable firewalld
Conclusions
As you can see, it’s nothing complicated! Firewalld simplifies the setup process, especially considering that configurations can easily be transferred.

2022.06.01 — F#ck AMSI! How to bypass Antimalware Scan Interface and infect Windows
Is the phrase "This script contains malicious content and has been blocked by your antivirus software" familiar to you? It's generated by Antimalware Scan Interface…
Full article →
2023.04.19 — Kung fu enumeration. Data collection in attacked systems
In penetration testing, there's a world of difference between reconnaissance (recon) and data collection (enum). Recon involves passive actions; while enum, active ones. During recon,…
Full article →
2022.01.12 — First contact. Attacks against contactless cards
Contactless payment cards are very convenient: you just tap the terminal with your card, and a few seconds later, your phone rings indicating that…
Full article →
2022.06.03 — Playful Xamarin. Researching and hacking a C# mobile app
Java or Kotlin are not the only languages you can use to create apps for Android. C# programmers can develop mobile apps using the Xamarin open-source…
Full article →
2022.02.16 — Timeline of everything. Collecting system events with Plaso
As you are likely aware, forensic analysis tools quickly become obsolete, while hackers continuously invent new techniques enabling them to cover tracks! As…
Full article →
2022.06.01 — Cybercrime story. Analyzing Plaso timelines with Timesketch
When you investigate an incident, it's critical to establish the exact time of the attack and method used to compromise the system. This enables you to track the entire chain of operations…
Full article →
2022.06.01 — Routing nightmare. How to pentest OSPF and EIGRP dynamic routing protocols
The magic and charm of dynamic routing protocols can be deceptive: admins trust them implicitly and often forget to properly configure security systems embedded in these protocols. In this…
Full article →
2022.01.13 — Bug in Laravel. Disassembling an exploit that allows RCE in a popular PHP framework
Bad news: the Ignition library shipped with the Laravel PHP web framework contains a vulnerability. The bug enables unauthorized users to execute arbitrary code. This article examines…
Full article →
2022.02.09 — Kernel exploitation for newbies: from compilation to privilege escalation
Theory is nothing without practice. Today, I will explain the nature of Linux kernel vulnerabilities and will shown how to exploit them. Get ready for an exciting journey:…
Full article →
2023.02.21 — SIGMAlarity jump. How to use Sigma rules in Timesketch
Information security specialists use multiple tools to detect and track system events. In 2016, a new utility called Sigma appeared in their arsenal. Its numerous functions will…
Full article →