4.2.2. nftables, iptables, and IP Forwarding
💡 First Principle: nftables is the modern Linux packet filtering framework that replaces iptables. Both operate on the Netfilter kernel subsystem, but nftables uses a cleaner syntax, better performance, and atomic rule updates. On modern systems (RHEL 8+, Debian 10+), iptables commands are actually wrappers around nftables.
nftables Concepts:
| Concept | iptables Equivalent | Description |
|---|---|---|
| table | table | Top-level container; has a family (ip, ip6, inet) |
| chain | chain | Ordered set of rules within a table |
| rule | rule | Match criteria + action |
| set | ipset | Named collection of IPs/ports for efficient matching |
nft list ruleset # Show all nftables rules
nft list tables # List tables
# Create a simple firewall with nftables
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
nft add rule inet filter input iif lo accept # Allow loopback
nft add rule inet filter input ct state established,related accept # Allow established
nft add rule inet filter input tcp dport 22 accept # Allow SSH
nft add rule inet filter input tcp dport '{ 80, 443 }' accept # Allow HTTP/S (quote the set braces from the shell)
# Persistent: save to /etc/nftables.conf
nft list ruleset > /etc/nftables.conf
systemctl enable --now nftables
iptables (legacy — still tested):
iptables -L -n -v # List all rules (numeric, verbose)
iptables -L INPUT -n --line-numbers # Input chain with line numbers
# Basic rules
iptables -A INPUT -p tcp --dport 22 -j ACCEPT # Allow SSH
iptables -A INPUT -p tcp --dport 80 -j ACCEPT # Allow HTTP
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT # Allow established
iptables -P INPUT DROP # Default drop policy
# NAT with iptables
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # Enable masquerade
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.5:80
# Save and restore (RHEL)
iptables-save > /etc/sysconfig/iptables
iptables-restore < /etc/sysconfig/iptables
# ipset — efficient IP matching
ipset create blocklist hash:ip
ipset add blocklist 10.0.0.5
iptables -I INPUT -m set --match-set blocklist src -j DROP
Stateful vs. Stateless Firewalls:
| Type | Tracks Connections? | Example Rule | Use Case |
|---|---|---|---|
| Stateful | ✅ Yes | Allow ESTABLISHED,RELATED | Modern firewalls; automatically allow return traffic |
| Stateless | ❌ No | Allow src port > 1024 | Simple routers; must manually allow return traffic |
IP Forwarding (Routing Between Interfaces):
# Check current state
sysctl net.ipv4.ip_forward # 0 = disabled, 1 = enabled
# Enable temporarily (runtime)
sysctl -w net.ipv4.ip_forward=1
echo 1 > /proc/sys/net/ipv4/ip_forward
# Enable persistently
echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.d/99-ipforward.conf
sysctl -p /etc/sysctl.d/99-ipforward.conf
# IPv6 forwarding
sysctl -w net.ipv6.conf.all.forwarding=1
IP forwarding must be enabled for a Linux system to act as a router or NAT gateway — without it, the kernel drops packets destined for other hosts.
⚠️ Exam Trap: iptables and nftables rules are not persistent by default — they exist only in memory and are lost on reboot. You must save them explicitly (iptables-save, nft list ruleset > /etc/nftables.conf) and ensure the appropriate service restores them at boot. firewalld handles persistence automatically through its --permanent mechanism.
Reflection Question: A Linux server needs to act as a NAT gateway for a private subnet (192.168.10.0/24) sharing the server's public interface eth0. What two things must be configured to enable this?