Packet Processing
The Linux Netfilter code is responsible for processing all incoming packets and making decisions about the final disposition of each one. By understanding how Netfilter works when configured via iptables, the iptables rules become a bit easier to understand. Note that packet processing could look different than what is presented here if nftables or another userspace utility is used to configure Netfilter.
Video Lecture
How Packets are Processed
When packets arrive from the network, the Netfilter component of the Linux kernel recognizes and groups packets into streams or flows. Netfilter then performs Stateful Packet Inspection (SPI), which analyzes both packet headers and packet contents to track connections, which are groups of related inbound and outbound packets.
In general, each packet in a stream is processed by the firewall. There are, however, some some performance optimizations in place to reduce CPU load when working with fast networks. For example, NAT rules are only computed for the first packet in a stream. All subsequent packets in the same NAT stream receive the same processing as the first packet.
Rule Organization
Within the Netfilter framework, three basic units of organization may be found: tables, chains, and rules. A Netfilter table handles packets from a single layer-3 protocol. When using iptables or ip6tables as the configuration tool, several tables are created automatically by default. In contrast, nftables requires the system administrator to define all the tables manually.
Each table contains chains, which are groups of related rules. Each rule describes properties that can be used to match a packet. If the packet matches the properties specified by the rule, then a corresponding action is taken by performing a jump to another chain or to a target.
Within a chain, a packet starts at the top (or head) of the chain and is matched rule-by-rule in the order that the rules are specified. When a match is found, the action given by the matched rule is taken, which normally causes processing to jump to another chain or target. If a packet reaches the end of a chain, the default policy for that chain is applied.
Table Selection
Whenever a packet arrives at a Linux host that has Netfilter configured, the packet is first sent through the Netfilter code. When iptables or ip6tables is used to configure Netfilter, incoming packets are first sent to the raw table’s PREROUTING chain. If that chain does not REJECT or DROP the packet, then the packet next goes to the PREROUTING chain of the mangle table. Once again, if the packet isn’t discarded, it then travels to the PREROUTING chain of the nat table.
After PREROUTING is complete, the kernel next determines whether or not the packet is destined for this host – that is, the host that is running this particular firewall. When a Linux computer is configured as a router and has devices active behind it, many of the incoming packets it receives will be destined for those other devices. In this case, packets that are to be routed elsewhere go to the FORWARD chain of the mangle table. Packets that are being sent to the router for consumption by the router itself are instead sent to the INPUT chain of the mangle table.
INPUT: Packets Destined for This Host
Figure 2 depicts what happens to an inbound packet that gets sent to the INPUT chain of the mangle table. This packet is destined for the machine that is running the firewall and will not be forwarded anywhere else. What is common about this processing path is that it uses the INPUT chain on each of several tables (mangle, filter, and security). When we configure a host firewall for a machine that is not a router, most of the firewall rules we write will go into the INPUT chain on the filter table.
FORWARD: Packets to be Routed Somewhere Else
Whenever we configure a Linux machine to act as a router, it needs to forward packets between the public side (typically, the Wide Area Network, or WAN) and the private site (the Local Area Network, or LAN). As shown in Figure 3, this forwarding process takes several steps. When iptables is used to configure Netfilter, several tables are also utilized for this process.
Whenever a packet to be forwarded arrives from the nat table’s PREROUTING chain, it first goes to the FORWARD chain in the mangle table. From there, it traverses the FORWARD chains in the filter and security tables. We typically configure some FORWARD chain rules in the filter table to decide whether or not our router is willing to forward the received packet.
Even if our rules permit the router to forward a received packet, the packet might not be routable. For example, it might have an invalid source or destination address, or an address from a reserved and unusable part of the IPv4 address space. In these cases, the kernel will simply drop a packet that it cannot otherwise route.
Assuming the packet is routable, it next goes through the POSTROUTING chains on the mangle and nat tables. In a typical NAT router, we have a rule in the POSTROUTING chain of the nat table that enables masquerading, or rewriting packets to make them look like they came from the router instead of from the original device that sent them. Network Address Translation is implemented at this step.
OUTPUT: Packets Sent from This Host
Whether or not a Linux machine is configured as a router, it is still also an installed operating environment with network connectivity. Various services on the machine might make network connections. Non-router Linux workstations typically have users who like to browse the Internet. All Linux systems typically connect to package repositories to obtain software updates. In each of these cases, packets that originate on the system running the firewall are sent through the firewall before going out to the network. Figure 4 illustrates what happens.
First, a program that wants to communicate on the network opens a socket, which is an interface provided by the operating system that permits network packets to be generated and received. Once the packet has been sent to the kernel via the socket, it traverses the OUTPUT chains of five different tables, in order: raw, mangle, nat, filter, and security. As long as none of those tables discard the packet, the kernel then inspects the packet to be sure that it is well-formed and can be sent out over the network. If the packet is invalid, the kernel simply drops it.
A valid packet might need to be adjusted further before being sent out via a network interface. The POSTROUTING chains of the mangle and nat tables are consulted to determine if any such changes need to be made. Finally, a packet that makes it through the POSTROUTING chain of the nat table is sent to the outbound network interface for transmission.
Composing the Firewall
In a working Linux system, packets are constantly being sent and received over the network. If the system is also a router, packets are simultaneously being forwarded between network segments. All three of the previous types of packet handling are in use, as depicted in Figure 5.
Although we have simplified the discussion of the iptables firewall to IPv4, as shown in the above diagrams, the same process is also used for IPv6. However, IPv6 uses a separate set of tables to process the packets independently from the older version of the protocol. One potential advantage (or disadvantage, depending on perspective) of using nftables over iptables and ip6tables is that nftables is capable of using a single set of tables to support both versions of the Internet Protocol.