The filter table is actually the default table used by iptables, and you don’t need to explicitly specify it most of the time.
Let’s see iptables in action. Imagine a simple firewall setup. We want to allow SSH traffic (port 22) from anywhere, but block all other incoming traffic by default.
# Allow established and related connections (important for return traffic)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow SSH traffic from any IP address
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Set the default policy for the INPUT chain to DROP
iptables -P INPUT DROP
# Allow all outgoing traffic
iptables -P OUTPUT ACCEPT
# Allow all traffic on the loopback interface
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
In this example, we’re manipulating the filter table (implicitly) to control network traffic. The INPUT chain dictates what happens to packets destined for the local machine, and the OUTPUT chain handles packets originating from the local machine. The ACCEPT and DROP are targets, specifying the action to take. ESTABLISHED,RELATED and --dport 22 are matches, conditions that a packet must meet for a rule to apply.
iptables operates on a packet-processing model. When a packet arrives, it traverses the relevant chain in the appropriate table. Each chain is a list of rules, and iptables evaluates these rules sequentially. If a packet matches a rule, the specified target (like ACCEPT, DROP, REJECT, or a jump to another chain) is executed, and packet processing for that chain stops. If a packet goes through all rules in a chain without a match, the chain’s default policy is applied.
The four primary tables are filter, nat, mangle, and raw.
The filter table is the workhorse for packet filtering. It has three built-in chains: INPUT (for packets destined for the local system), FORWARD (for packets being routed through the system), and OUTPUT (for packets originating from the local system). Its primary purpose is to decide whether a packet should be allowed or denied.
The nat (Network Address Translation) table is used to modify the source or destination addresses and ports of packets. This is crucial for scenarios like sharing a single public IP address among multiple private IPs (masquerading) or redirecting traffic to a different host or port. It has three chains: PREROUTING (for altering packets as they arrive, before routing decisions are made), POSTROUTING (for altering packets as they leave, after routing decisions), and OUTPUT (for altering locally generated packets before they leave).
The mangle table is for specialized packet alteration. It’s used for tasks that involve modifying packet headers in ways other than source/destination addresses, such as setting the Type of Service (TOS) bits or the Don’t Fragment (DF) flag. It has the same five chains as nat: PREROUTING, POSTROUTING, INPUT, FORWARD, and OUTPUT.
The raw table is the first table a packet encounters and is used for fine-grained control over connection tracking. It has two chains: PREROUTING and OUTPUT. Its main use case is to exempt specific packets from connection tracking, which can be beneficial for performance in high-traffic scenarios or for specific protocols.
When a packet arrives at the network interface, it first enters the raw table’s PREROUTING chain (if it’s not locally generated). Then, it proceeds to the mangle table’s PREROUTING chain, followed by the nat table’s PREROUTING chain. If the packet is destined for the local machine, it then goes through the mangle table’s INPUT chain and finally the filter table’s INPUT chain. If the packet is to be forwarded, it goes through the mangle table’s FORWARD chain and then the filter table’s FORWARD chain. If the packet originates from the local machine, it traverses the raw table’s OUTPUT chain, then mangle table’s OUTPUT, nat table’s OUTPUT, and finally the filter table’s OUTPUT chain. Packets that are modified by nat’s POSTROUTING chain or mangle’s POSTROUTING chain are processed after the routing decision has been made.
The most surprising thing about iptables is that the order of tables matters, but the order of chains within a table also has a strict sequence for packet traversal, and you can’t just pick any chain for any table. For instance, nat and mangle tables have PREROUTING and POSTROUTING chains that are processed before and after routing decisions, respectively, while filter only has INPUT, FORWARD, and OUTPUT which are processed relative to routing decisions.
Understanding the strict packet traversal order through the tables and their respective chains is key to building complex firewall rulesets. The next concept you’ll likely grapple with is connection tracking (conntrack) and how it interacts with these tables and chains, especially for stateful firewalling.