The most surprising thing about iptables chains is that they aren’t really "chains" in the way you might think; they’re more like ordered lists of rules that packets traverse, and the system doesn’t always go through them linearly.
Let’s watch iptables in action. Imagine a packet arriving at your Linux server.
# Packet arrives from eth0, destined for port 22 (SSH)
# This packet will first hit the INPUT chain.
# If it's allowed, it might then be processed by other chains.
# Example rule: Allow SSH traffic
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Example rule: Drop all other incoming traffic
iptables -A INPUT -j DROP
# Now, consider a packet that needs to be routed *through* this server to another destination.
# This packet will hit the FORWARD chain.
# Example rule: Allow forwarding for trusted internal networks
iptables -A FORWARD -s 192.168.1.0/24 -j ACCEPT
# Example rule: Drop all other forwarded traffic
iptables -A FORWARD -j DROP
# Finally, consider traffic originating *from* this server.
# This packet will hit the OUTPUT chain.
# Example rule: Allow outgoing SSH connections
iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
# Example rule: Allow outgoing DNS requests
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
# Example rule: Drop all other outgoing traffic
iptables -A OUTPUT -j DROP
These commands build a firewall. But what’s really happening under the hood?
The iptables command-line utility interacts with the Netfilter framework within the Linux kernel. Netfilter provides hooks at various points in the network stack where custom packet filtering and manipulation can occur. The iptables tool configures these hooks.
There are five main tables in iptables: filter (the default, used for packet filtering), nat (for Network Address Translation), mangle (for specialized packet alteration), raw (for configuring connection tracking exemptions), and security (for Mandatory Access Control). Each table has one or more built-in chains.
The three chains you’re asking about—INPUT, OUTPUT, and FORWARD—are all part of the filter table.
INPUTChain: This chain handles packets that are destined for the local machine. When a packet arrives at your server’s network interface and its destination IP address is the server itself, it enters theINPUTchain. Think of it as the "incoming mail" for the server’s own processes.OUTPUTChain: This chain handles packets that are originating from the local machine. When a process on your server initiates a network connection or sends data, the resulting packets enter theOUTPUTchain before being sent out onto the network. This is the "outgoing mail" from the server.FORWARDChain: This chain handles packets that are passing through the local machine. If your server is acting as a router or gateway, and a packet arrives destined for a different IP address (not the server itself), it will enter theFORWARDchain. This is for "transit mail."
Each chain is essentially an ordered list of rules. When a packet enters a chain, iptables examines each rule in order.
- If a rule matches the packet,
iptablesperforms the specified target action. The most common targets areACCEPT(let the packet through),DROP(silently discard the packet), andREJECT(discard the packet and send an error message back to the sender). - If a rule matches and its target is
ACCEPT,DROP, orREJECT, the traversal of that chain for that packet stops. The packet is either allowed to continue to its next stage (or be sent out), or it’s discarded. - If a rule matches and its target is something else (like
LOGfor logging, or a jump to another user-defined chain), the packet’s journey continues according to that target’s instructions. - If a packet goes through all the rules in a chain without matching any that cause a terminal action (
ACCEPT,DROP,REJECT), it then falls through to the chain’s default policy. This policy is set when the chain is created (e.g.,iptables -P INPUT DROP) and dictates what happens to packets that "fall through" the entire list of rules.
The order of rules is critical. For example, if you have a DROP rule at the beginning of your INPUT chain and an ACCEPT rule later, the DROP rule will always take precedence for any incoming packet, and the ACCEPT rule will never be reached for those packets. This is why you typically see ACCEPT rules for specific traffic (like SSH) placed before a general DROP rule at the end of a chain.
The NAT table has chains like PREROUTING (for packets arriving at the interface, before routing decisions) and POSTROUTING (for packets leaving the interface, after routing decisions). The mangle table also has PREROUTING and POSTROUTING chains, plus INPUT and OUTPUT chains. A packet might traverse multiple chains across different tables. For example, a packet destined for the local machine might hit PREROUTING in the nat table (if NAT is involved), then INPUT in the filter table. A packet to be forwarded might hit PREROUTING (nat), then FORWARD (filter), then POSTROUTING (nat).
The most common mistake people make is assuming that a packet only enters one chain. In reality, a single packet can traverse multiple chains across different tables based on its origin, destination, and whether it’s being routed.
The next thing you’ll run into is understanding how to manage user-defined chains and the nat and mangle tables for more complex network configurations.