A firewall is a security device (hardware/software) that protects the network by filtering traffic and blocking unwanted/unauthorized access to private data. Having a proper firewall is important to protect your servers and infrastructure. It can not only block unwanted traffic but also block malicious software from infecting the system.
In the Linux ecosystem, iptables is a popular firewall that interfaces with the netfilter framework on the Linux kernel. Most of the modern Linux systems come with these tools pre-built. To make the most out of these systems, it’s quintessential to understand their architectures. Otherwise, developing reliable firewall policies can be daunting. It could lead to creating complicated syntaxes, interrelated parts in the framework, etc.
This guide will dive deep into the architecture of iptables to help users who need to create their own firewall policies. We will also explore how iptables interface with netfilter and how the various components fit together.
Iptables and Netfilter
In Linux, the iptables firewall is the most common one. It works by interfacing with the packet filtering hooks in the Linux kernel’s networking stack. It’s these kernel hooks that are collectively referred to as the netfilter framework.
Every incoming/outgoing packet in the system will trigger these hooks as it progresses through the stack. Thus, the programs registered with these hooks are able to interact with the traffic at key points. Finally, the kernel modules associated with iptables connect to these hooks to enforce the specified firewall rules.
Netfilter Hooks
For programs to connect, there are five different netfilter hooks. As packets progress through the stack, the hooks trigger the kernel modules registered with them. The trigger condition depends on conditions, such as: the package direction (incoming/outgoing), the packet destination, whether the packet was dropped/rejected at a previous point, etc.
These are the hooks representing various well-defined points in the network stack:
-
NF_IP_PRE_ROUTING: This hook is triggered by any incoming traffic. The trigger takes place before any routing decision is made regarding the packet’s destination.
-
NF_IP_LOCAL_IN: This hook is triggered after routing an incoming packet. The packet also needs to be destined for the local system.
-
NF_IP_FORWARD: This hook is also triggered after routing an incoming packet. However, it triggers if the packet is to be routed to another host.
-
NF_IP_LOCAL_OUT: Any local outbound traffic, as soon as it hits the network stack, triggers this hook.
-
NF_IP_POST_ROUTING: This hook is triggered by any outgoing/forwarded traffic after the routing has taken place before the packet reaches the wire.
Kernel modules willing to register at these hooks must provide a priority number. This value helps determine the order in which they will be called once the hook is triggered. Such a mechanism allows multiple modules (different modules or multiple copies of the same module) to connect to each of the hooks in a deterministic ordering. Each module will return a decision to the netfilter framework after processing the packets.
Tables and Chains in Iptables
To organize its rules, the iptables firewall uses tables. The tables categorize the rules based on the type of decisions they make. For example, if a rule deals with NAT (network address translation), then the rule is put under the nat table. Similarly, if a rule is deciding whether to allow/deny a packet to its destination, it’s added to the filter table.
Inside each table of iptables, rules are further organized within separate “chains”. While the table represents the type of rules they are holding, the chains describe the netfilter hooks that trigger the rules. In short, chains determine when the rule will be evaluated.
Here are the built-in chains of iptables. Interestingly, the chain names also mirror the name of the associated netfilter hooks:
Chain (iptables) | Utilisation |
PREROUTING | NF_IP_PRE_ROUTING |
INPUT | NF_IP_LOCAL_IN |
FORWARD | NF_IP_FORWARD |
OUTPUT | NF_IP_LOCAL_OUT |
POSTROUTING | NF_IP_POST_ROUTING |
Using the chains, admins can determine at which stage of the packet delivery the rule will be evaluated. As each table contains multiple chains, it can also extend its influence at multiple points in the processing. Certain decisions only make sense at certain points of the network stack. Thus, every table won’t have a chain registered with each kernel hook.
The netfilter framework only offers 5 kernel hooks. As such, chains from multiple tables are registered at each point of the hooks. For example, if three chains have the PREROUTING chains, then it’s registered with the NF_IP_PRE_ROUTING hook. Each of them must provide a priority that decides in which order each table’s PREROUTING chain is called. The highest priority PREROUTING chain is evaluated first, the next highest priority one is evaluated second, and so on.
The iptables Tables
Let’s take a step back and have a look at the tables that iptables offer. As mentioned earlier, each table represents different sets of rules, organized by area of concern, for packet evaluation.
-
filter Table
In iptables , the filter table is one of the most popular ones. It’s used to determine whether a packet will be permitted to continue to its destination or not. In firewall terminology, this process is known as “filtering” packets.
It’s the functions of the filter table that people refer to when discussing firewalls (for the most part).
-
nat Table
This table implements rules regulating NAT. When packets enter the network stack, the rules described in this table decide how to modify the packet’s source/destination address, impacting the routing of the packet and any response traffic.
Oftentimes, the nat table is used to route packets to networks where there’s no direct access.
-
mangle Table
This table holds the rules that modify the IP headers of the packets in various ways. For example, it can modify the TTL (Time to Live) value of a packet by lengthening/shortening the number of valid network hops the packet can sustain. In addition, the mangle table can modify other IP headers in a similar fashion.
This table is also allowed to put an internal kernel “mark” on the packet that other tables and network tools can pick up for further processing. This mark doesn’t touch the actual packet but rather, adds the mark to the kernel’s representation of the packet.
-
raw Table
The iptables firewall is stateful, implying that the packets are evaluated in the context of their relation to previous packets. The connection tracking feature developed on top of the netfilter framework allows iptables to view packets as a part of an ongoing connection or session rather than as a stream of discrete, unrelated packets. Generally, the connection tracking logic is applied very soon after the packet reaches the network interface.
The raw table comes with a very narrowly-defined function. The sole purpose of this table is to provide a mechanism for marking packets in order to opt out of connection tracking.
-
security Table
The security table puts internal SELinux security context marks on packets. This, in turn, affects how SELinux (or any other app that interprets SELinux security contexts) will handle the packets.
The SELinux marks can be applied on a per-packet or per-connection basis.
Chains Implemented in Each Table
So far, we have talked about tables and chains separately. Time to go over which chains are available at each table. This topic extends the discussion about the evaluation order of chains registered to the same hook. For example, what happens if three tables have PREROUTING chains? What is their order of evaluation?
Next, have a look at the following table. It indicates the chains that are available within each iptables table.
PREROUTING | INPUT | FORWARD | OUTPUT | POSTROUTING | |
(routing decision) |
✓ | ||||
raw |
✓ | ✓ | |||
(connection tracking enabled) |
✓ | ✓ | |||
mangle |
✓ | ✓ | ✓ | ✓ | ✓ |
nat (DNAT) |
✓ | ✓ | |||
(routing decision) |
✓ | ✓ | |||
filter |
✓ | ✓ | ✓ | ||
security |
✓ | ✓ | ✓ | ||
nat (SNAT) |
✓ | ✓ |
When read from left to right, it describes what tables contain what chains. For example, the raw table has both PREROUTING and OUTPUT chains. When read from top-to-bottom, it describes in which order each chain is called when its associated netfilter hook is triggered.
Note that the nat table was split between DNAT operations (altering the destination of a packet) and SNAT operations (altering the source of a packet) to specify their ordering more clearly. The table also included representation points where routing decisions are made and where connection tracking is enabled.
The hooks (columns) that a packet will trigger are based on the packet’s nature (incoming/outgoing), the routing decisions that are made, and whether a packet meets the filtering criteria.
Certain events can skip a table’s chain during processing. For example, only the first packet in a connection will be evaluated against the NAT rules as described by the nat table. Any subsequent packet in the same connection will have the same nat decisions applied without any additional evaluation. Responses to the NAT connections will automatically have the reverse NAT rules applied for proper routing.
Chain Traversal Order
Assuming that the server knows the packet routing rules and firewall rules allow the transmission, the following flows represent how different paths will be traversed:
-
Incoming packets destined for the local system: PREROUTING >> INPUT
-
Incoming packets destined for another host: PREROUTING >> FORWARD >> POSTROUTING
-
Locally generated packets: OUTPUT >> POSTROUTING
In conclusion, combining all the information we have discussed so far, we can see that any incoming packet destined for the local system will be evaluated against the PREROUTING chains of the raw, mangle, and nat tables. Then, it will pass through the INPUT chains of mangle, filter, security, and nat tables before finally reaching the local socket.
Iptables Rules
The iptables firewall rules are placed within a specific chain of a specific table. When a chain is called, the packet in question will be evaluated against each rule in the chain. Each rule has two components: a matching component and an action component.
-
Matching
The matching part of a rule specifies the conditions that a packet must meet before the specified action (or “target”) is executed.
The matching system offers incredible flexibility. Its functionality can also be extended with the help of iptables extensions. Rules can be described to match packets by protocol type, source/destination address, source/destination port, source/destination network, input/output interface, headers, connection state, and other criteria. A rule can also have a combination of these conditions, resulting in complex rule sets to differentiate between different traffic.
-
Targets
A target is the action taken when a packet meets the matching criteria of a rule. Generally, targets are divided into two groups:
-
-
Terminating targets: It terminates the evaluation process within the chain and returns the control to the netfilter hook. Based on the return value, the hook will either allow the packet to continue its journey or drop it.
-
Non-terminating targets: The target performs an action and the evaluation in the chain continues. Although each chain must pass through a final terminating decision, any number of non-terminating targets can take place beforehand.
-
The availability of each target within rules is dependent on context. For example, the chain and table type may impact the availability of targets. Other possible factors include activated extensions in the rule and the matching clauses.
User-Defined Chains
There’s also a special class of non-terminating targets: the jump target. Jump targets are actions performed when the evaluation moves from one chain to another for additional processing. So far, we have talked about built-in chains that are closely connected to the netfilter hooks that call them. However, iptables also allows admins to create their custom chains.
Rules in user-defined chains are also similar to those in built-in chains. The key difference is that user-defined chains are only reachable by “jumping” to them from a rule. It’s because user-defined chains are not linked with any netfilter hooks.
You can think of user-defined chains as extensions to the chain that originally called them. For example, in a user-defined chain, the evaluation will pass back to the calling chain if it reaches the end of the rule list or, a matching rule executes a RETURN target. Interestingly, a user-defined chain can also “jump” the evaluation to another user-defined chain.
This feature lays the groundwork for better organization and the necessary framework for robust branching.
Connection Tracking
When discussing the raw table and connection state matching criteria, we discussed the connection tracking system implemented on top of the netfilter framework. This feature allows iptables to view packets in the context of an ongoing connection. The connection tracking system also provides iptables with the necessary functionality needed to perform “stateful” operations.
Just after a packet enters the networking stack, connection tracking is applied. The raw table chains and some basic sanity checks are all the logics that goes into associating packets with a connection.
The system checks each packet against a set of existing connections. If needed, the system will update the state of the existing connections or create new ones. Packets that were marked with the NOTRACK target in any raw table chains will bypass further connection tracking routines.
-
Available States
Connections that are tracked by the connection tracking system will have any of the following states assigned:
-
-
NEW : Upon arrival of a packet that’s not associated with an existing connection but isn’t invalid as a first packet, a new connection is added to the system with this label. It takes place for both connection-aware protocols (TCP, for example) and connectionless protocols (UDP, for example).
-
ESTABLISHED: The state of a connection is updated from NEW to ESTABLISHED when it receives a valid response from the opposite direction. For TCP connections, it signifies a SYN/ACK. For UDP and ICMP traffic, it signifies a response where the source and destination of the original packet are switched.
-
RELATED: Packets that aren’t a part of a connection but related to an established connection get labeled as RELATED . It can mean a helper connection (for example, in FTP data transmission connection), or ICMP responses to connection attempts by other protocols.
-
INVALID: Packets that aren’t part of an established connection, are deemed as inappropriate for opening a new connection, can’t be identified, aren’t routable etc. get labeled as INVALID.
-
UNTRACKED: A packet can be labeled as UNTRACKED if they were targeted in a raw table chain to bypass tracking.
-
SNAT: It signifies a virtual state set when the source address is modified by a NAT operation. It’s handled by the connection tracking system so that the source addresses are translated in reply packets.
-
DNAT: Similar to SNAT, it signifies a virtual state when the destination address is modified by a NAT operation. The connection tracking system handles it so that it knows to translate the destination address back when routing reply packets.
-
These states tracked by the connection tracking system let admins craft specific rules targeting specific points in a connection lifetime. It provides the necessary functionality for more thorough and secure rules.
Final Thoughts
In Linux, the netfilter framework and the iptables firewall serve as the basis for most firewalls. The netfilter hooks are close enough to the networking stack to allow powerful control over packets processed by the system. Leveraging these capabilities, the iptables firewall offers a flexible way of communicating policy requirements to the kernel.
This guide goes in-depth about the inner structure of the netfilter framework and iptables firewall. In addition, it discusses the connection tracking system. By understanding how these pieces fit together, you can better utilize them to craft more robust and secure server environments.
Finally, while this guide tackles the inner workings, check out this guide on configuring iptables to apply them in action. In addition, you can see how the UFW firewall further simplifies iptables. Furthermore, it will be useful to learn how to list and delete iptables firewall rules.
Happy Computing!
- How To Enable, Create and Use the .htaccess File: A Tutorial - March 8, 2023
- An Overview of Queries in MySQL - October 28, 2022
- Introduction to Cookies: Understanding and Working with JavaScript Cookies - October 25, 2022
- An Overview of Data Types in Ruby - October 24, 2022
- The Architecture of Iptables and Netfilter - October 10, 2022