iptables/nftables
Linux kernel firewall frameworks for packet filtering, NAT, and network traffic control.
iptables/nftables
Linux kernel firewall frameworks for packet filtering, NAT, and network traffic control.
Overview
iptables and nftables are userspace utilities for configuring the Linux kernel's netfilter packet filtering framework. iptables is the legacy tool that has been the standard for decades, whilst nftables is its modern replacement offering improved performance, a unified syntax, and better rule organisation. Both tools control how the kernel handles network packets traversing the system, enabling firewalling, NAT, port forwarding, and traffic shaping.
flowchart TD
subgraph "Packet Flow Through Netfilter"
A[Incoming Packet] --> B{Destination?}
B -->|Local| C[INPUT Chain]
B -->|Forward| D[FORWARD Chain]
C --> E[Local Process]
E --> F[OUTPUT Chain]
D --> G[POSTROUTING]
F --> G
G --> H[Outgoing Packet]
I[PREROUTING] --> B
A --> I
end
Basic Concepts
Understanding the fundamental building blocks of netfilter is essential for effective firewall configuration.
Key Concepts
- Tables - Containers for chains, organised by function (filter, nat, mangle, raw)
- Chains - Lists of rules processed sequentially (INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING)
- Rules - Individual packet matching criteria and actions
- Targets - Actions taken when a rule matches (ACCEPT, DROP, REJECT, LOG)
- Policies - Default action when no rule matches (typically ACCEPT or DROP)
- Connection Tracking - Stateful inspection of packet flows
flowchart LR
subgraph "iptables Structure"
A[Table] --> B[Chain 1]
A --> C[Chain 2]
B --> D[Rule 1]
B --> E[Rule 2]
B --> F[Rule 3]
D --> G[Match + Target]
E --> G
F --> G
end
iptables Basic Commands
# List all rules in all chains (verbose with line numbers)
iptables -L -v -n --line-numbers
# List rules in specific table
iptables -t nat -L -v -n
# List rules in raw format (for scripting)
iptables -S
iptables -t nat -S
# Show rule statistics
iptables -L -v -n -x
# Flush all rules in a chain
iptables -F INPUT
# Flush all rules in all chains
iptables -F
# Delete all user-defined chains
iptables -X
# Zero packet and byte counters
iptables -Z
# Set default policy for a chain
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
nftables Basic Commands
# List all rules
nft list ruleset
# List specific table
nft list table inet filter
# List specific chain
nft list chain inet filter input
# Flush all rules
nft flush ruleset
# Flush specific table
nft flush table inet filter
# Delete a table
nft delete table inet filter
# Add a table
nft add table inet filter
# Add a chain with policy
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
# Add a rule
nft add rule inet filter input tcp dport 22 accept
# Insert rule at beginning
nft insert rule inet filter input tcp dport 80 accept
# Delete rule by handle
nft delete rule inet filter input handle 10
Examples
# iptables: View current firewall status
iptables -L -v -n --line-numbers
# Output shows chain, policy, packet/byte counts, and rules
# iptables: Save current rules to file
iptables-save > /etc/iptables/rules.v4
# iptables: Restore rules from file
iptables-restore < /etc/iptables/rules.v4
# nftables: Export ruleset
nft list ruleset > /etc/nftables.conf
# nftables: Load ruleset from file
nft -f /etc/nftables.conf
# nftables: Create complete basic structure
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; policy accept \; }
nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
Common Tables
Each table serves a specific purpose in packet processing and contains predefined chains.
Key Concepts
- filter - Default table for packet filtering (ACCEPT, DROP, REJECT)
- nat - Network Address Translation (SNAT, DNAT, MASQUERADE)
- mangle - Packet alteration (TTL, TOS, MARK)
- raw - Exemptions from connection tracking
- security - Mandatory Access Control (SELinux)
flowchart TD
subgraph "Table Processing Order"
A[Incoming Packet] --> B[raw PREROUTING]
B --> C[mangle PREROUTING]
C --> D[nat PREROUTING]
D --> E{Routing Decision}
E -->|Local| F[mangle INPUT]
F --> G[filter INPUT]
G --> H[Local Process]
E -->|Forward| I[mangle FORWARD]
I --> J[filter FORWARD]
J --> K[mangle POSTROUTING]
K --> L[nat POSTROUTING]
H --> M[raw OUTPUT]
M --> N[mangle OUTPUT]
N --> O[nat OUTPUT]
O --> P[filter OUTPUT]
P --> K
L --> Q[Outgoing Packet]
end
iptables Table Usage
# Filter table (default) - firewalling
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -j DROP
# NAT table - address translation
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:8080
# Mangle table - packet modification
iptables -t mangle -A PREROUTING -p tcp --dport 22 -j TOS --set-tos Minimize-Delay
iptables -t mangle -A OUTPUT -p tcp --dport 80 -j MARK --set-mark 1
# Raw table - connection tracking bypass
iptables -t raw -A PREROUTING -p tcp --dport 80 -j NOTRACK
iptables -t raw -A OUTPUT -p tcp --sport 80 -j NOTRACK
nftables Table Types
# nftables uses table families instead of separate tables
# Common families: ip (IPv4), ip6 (IPv6), inet (both), arp, bridge, netdev
# Create tables for different families
nft add table ip filter
nft add table ip6 filter
nft add table inet filter # Handles both IPv4 and IPv6
# Filter chain types
nft add chain inet filter input { type filter hook input priority 0 \; }
# NAT chain types
nft add table ip nat
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
# Route chain type (for mangle-like operations)
nft add chain ip mangle output { type route hook output priority -150 \; }
Examples
# Complete iptables basic firewall setup
# Clear existing rules
iptables -F
iptables -X
iptables -t nat -F
iptables -t mangle -F
# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Allow loopback
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Allow established connections
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow SSH, HTTP, HTTPS
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# Complete nftables equivalent
nft flush ruleset
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
# Allow loopback
nft add rule inet filter input iif lo accept
# Allow established connections
nft add rule inet filter input ct state established,related accept
# Allow SSH, HTTP, HTTPS
nft add rule inet filter input tcp dport { 22, 80, 443 } accept
Rule Syntax and Matching
Rules define the criteria for matching packets and the actions to take.
Key Concepts
- Match Extensions - Additional criteria beyond basic protocol/port matching
- Implicit Matches - Automatically loaded with protocol specification (-p)
- Explicit Matches - Require -m to load the match module
- Negation - Use ! to invert match conditions
- Multiple Matches - Combine criteria for precise filtering
iptables Match Syntax
# Basic matches
iptables -A INPUT -p tcp # Protocol match
iptables -A INPUT -s 192.168.1.0/24 # Source address
iptables -A INPUT -d 10.0.0.1 # Destination address
iptables -A INPUT -i eth0 # Input interface
iptables -A INPUT -o eth1 # Output interface (FORWARD/OUTPUT)
# Port matching (requires -p tcp or -p udp)
iptables -A INPUT -p tcp --dport 22 # Destination port
iptables -A INPUT -p tcp --sport 1024:65535 # Source port range
iptables -A INPUT -p tcp --dport 80:443 # Destination port range
iptables -A INPUT -p tcp -m multiport --dports 22,80,443 # Multiple ports
# TCP flags
iptables -A INPUT -p tcp --tcp-flags SYN,ACK SYN # Match SYN packets
iptables -A INPUT -p tcp --syn # Shortcut for new connections
# ICMP types
iptables -A INPUT -p icmp --icmp-type echo-request
iptables -A INPUT -p icmp --icmp-type echo-reply
# Negation
iptables -A INPUT ! -s 192.168.1.0/24 -j DROP # NOT from this network
iptables -A INPUT ! -p tcp -j ACCEPT # NOT TCP
# Conntrack match (stateful)
iptables -A INPUT -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# Limit match (rate limiting)
iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 4 -j ACCEPT
# String match
iptables -A INPUT -p tcp --dport 80 -m string --string "GET /admin" --algo bm -j DROP
# Time match
iptables -A INPUT -p tcp --dport 22 -m time --timestart 09:00 --timestop 17:00 -j ACCEPT
# Owner match (OUTPUT chain only)
iptables -A OUTPUT -m owner --uid-owner 1000 -j ACCEPT
# MAC address match
iptables -A INPUT -m mac --mac-source 00:11:22:33:44:55 -j ACCEPT
# IP range match
iptables -A INPUT -m iprange --src-range 192.168.1.100-192.168.1.200 -j ACCEPT
# Comment match
iptables -A INPUT -p tcp --dport 22 -m comment --comment "SSH access" -j ACCEPT
nftables Match Syntax
# Basic matches
nft add rule inet filter input ip protocol tcp accept
nft add rule inet filter input ip saddr 192.168.1.0/24 accept
nft add rule inet filter input ip daddr 10.0.0.1 accept
nft add rule inet filter input iifname "eth0" accept
nft add rule inet filter input oifname "eth1" accept
# Port matching
nft add rule inet filter input tcp dport 22 accept
nft add rule inet filter input tcp sport 1024-65535 accept
nft add rule inet filter input tcp dport { 22, 80, 443 } accept
nft add rule inet filter input tcp dport 80-443 accept
# TCP flags
nft add rule inet filter input tcp flags syn accept # SYN bit set (also matches SYN-ACK)
nft add rule inet filter input tcp flags & (syn|ack) == syn accept # true new-connection SYN (== iptables --syn)
# ICMP types
nft add rule inet filter input icmp type echo-request accept
nft add rule inet filter input icmpv6 type { echo-request, echo-reply } accept
# Negation
nft add rule inet filter input ip saddr != 192.168.1.0/24 drop
nft add rule inet filter input ip protocol != tcp accept
# Connection tracking
nft add rule inet filter input ct state { new, established } accept
nft add rule inet filter input ct state invalid drop
# Rate limiting
nft add rule inet filter input icmp type echo-request limit rate 1/second burst 4 packets accept
# IP ranges
nft add rule inet filter input ip saddr 192.168.1.100-192.168.1.200 accept
# Comments (the comment goes after the verdict)
nft add rule inet filter input tcp dport 22 accept comment "SSH access"
# Meta matches
nft add rule inet filter output meta skuid 1000 accept
nft add rule inet filter input meta iiftype loopback accept
Examples
# iptables: Complex rule with multiple matches
iptables -A INPUT \
-p tcp \
-s 10.0.0.0/8 \
--dport 3306 \
-m conntrack --ctstate NEW \
-m time --timestart 09:00 --timestop 18:00 --weekdays Mon,Tue,Wed,Thu,Fri \
-m limit --limit 10/min \
-m comment --comment "MySQL access during business hours" \
-j ACCEPT
# nftables: Equivalent complex rule
nft add rule inet filter input \
ip saddr 10.0.0.0/8 \
tcp dport 3306 \
ct state new \
limit rate 10/minute \
accept \
comment "MySQL access"
# iptables: Anti-DDoS rules
# Limit new connections
iptables -A INPUT -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT
iptables -A INPUT -p tcp --syn -j DROP
# Limit ICMP
iptables -A INPUT -p icmp -m limit --limit 1/s --limit-burst 4 -j ACCEPT
iptables -A INPUT -p icmp -j DROP
# nftables: Anti-DDoS rules
nft add rule inet filter input tcp flags syn limit rate 1/second burst 3 packets accept
nft add rule inet filter input tcp flags syn drop
nft add rule inet filter input icmp type echo-request limit rate 1/second burst 4 packets accept
nft add rule inet filter input icmp type echo-request drop
NAT Configuration
Network Address Translation modifies packet source or destination addresses as they traverse the firewall.
Key Concepts
- SNAT - Source NAT: modify source address of outgoing packets
- DNAT - Destination NAT: modify destination address of incoming packets
- MASQUERADE - Dynamic SNAT for interfaces with changing IP addresses
- REDIRECT - Redirect packets to local machine
- Conntrack - Tracks connections to maintain NAT mappings
flowchart LR
subgraph "SNAT/MASQUERADE"
A[Internal Host<br/>192.168.1.10] -->|src: 192.168.1.10| B[Firewall]
B -->|src: 203.0.113.1| C[Internet]
end
flowchart RL
subgraph "DNAT"
A[Internet] -->|dst: 203.0.113.1:80| B[Firewall]
B -->|dst: 192.168.1.10:8080| C[Internal Server]
end
iptables NAT Commands
# SNAT - Static source address translation
# Use when external IP is static
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 203.0.113.1
# SNAT with port range
iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 203.0.113.1:1024-65535
# MASQUERADE - Dynamic source address translation
# Use for DHCP/PPPoE where external IP may change
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
# MASQUERADE for specific subnet
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
# DNAT - Destination address translation
iptables -t nat -A PREROUTING -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10
# DNAT with port change
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.10:80
# DNAT to multiple servers (basic load balancing)
iptables -t nat -A PREROUTING -p tcp --dport 80 -m statistic --mode nth --every 2 --packet 0 \
-j DNAT --to-destination 192.168.1.10:80
iptables -t nat -A PREROUTING -p tcp --dport 80 \
-j DNAT --to-destination 192.168.1.11:80
# REDIRECT - Redirect to local port
iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 8080
# Full NAT for internal network (router setup)
# Enable IP forwarding first: echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
nftables NAT Commands
# Create NAT table and chains
nft add table ip nat
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
# SNAT - Static source address translation
nft add rule ip nat postrouting oifname "eth0" snat to 203.0.113.1
# MASQUERADE - Dynamic source address translation
nft add rule ip nat postrouting oifname "eth0" masquerade
# MASQUERADE for specific subnet
nft add rule ip nat postrouting ip saddr 192.168.1.0/24 oifname "eth0" masquerade
# DNAT - Destination address translation
nft add rule ip nat prerouting tcp dport 80 dnat to 192.168.1.10
# DNAT with port change
nft add rule ip nat prerouting tcp dport 8080 dnat to 192.168.1.10:80
# REDIRECT - Redirect to local port
nft add rule ip nat prerouting tcp dport 80 redirect to :8080
# Full NAT router setup
nft add table ip nat
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
nft add rule ip nat postrouting ip saddr 192.168.1.0/24 oifname "eth0" masquerade
nft add table inet filter
nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
nft add rule inet filter forward iifname "eth1" oifname "eth0" accept
nft add rule inet filter forward iifname "eth0" oifname "eth1" ct state established,related accept
Examples
# iptables: Complete NAT gateway configuration
# Enable IP forwarding
sysctl -w net.ipv4.ip_forward=1
# Clear existing NAT rules
iptables -t nat -F
# MASQUERADE for internal network
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -o eth0 -j MASQUERADE
# Port forward HTTP to internal web server
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:80
# Port forward HTTPS to internal web server
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.10:443
# Allow forwarding for NAT
iptables -A FORWARD -i eth1 -o eth0 -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# nftables: Complete NAT gateway configuration
nft flush ruleset
# NAT table
nft add table ip nat
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
# MASQUERADE
nft add rule ip nat postrouting ip saddr 192.168.1.0/24 oifname "eth0" masquerade
# Port forwarding
nft add rule ip nat prerouting iifname "eth0" tcp dport 80 dnat to 192.168.1.10:80
nft add rule ip nat prerouting iifname "eth0" tcp dport 443 dnat to 192.168.1.10:443
# Filter table for forwarding
nft add table inet filter
nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
nft add rule inet filter forward iifname "eth1" oifname "eth0" accept
nft add rule inet filter forward iifname "eth0" oifname "eth1" ct state established,related accept
Port Forwarding
Port forwarding redirects incoming connections to different hosts or ports, essential for exposing internal services.
Key Concepts
- PREROUTING Chain - Where DNAT rules are applied for incoming packets
- FORWARD Chain - Must allow the forwarded traffic
- Connection Tracking - Maintains state for return traffic
- Hairpin NAT - Allows internal hosts to access forwarded services via external IP
flowchart LR
subgraph "Port Forwarding Flow"
A[Internet<br/>Client] -->|dst: 203.0.113.1:80| B[Firewall<br/>PREROUTING]
B -->|DNAT| C[Routing]
C -->|dst: 192.168.1.10:8080| D[FORWARD]
D --> E[Internal<br/>Server]
end
iptables Port Forwarding
# Basic port forward
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:80
# Allow forwarded traffic in FORWARD chain
iptables -A FORWARD -i eth0 -o eth1 -p tcp --dport 80 -d 192.168.1.10 -j ACCEPT
# Port forward with port translation
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 2222 -j DNAT --to-destination 192.168.1.20:22
# Forward range of ports
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 10000:10100 -j DNAT --to-destination 192.168.1.30
# Forward UDP traffic
iptables -t nat -A PREROUTING -i eth0 -p udp --dport 53 -j DNAT --to-destination 192.168.1.5:53
iptables -A FORWARD -i eth0 -o eth1 -p udp --dport 53 -d 192.168.1.5 -j ACCEPT
# Hairpin NAT (access from internal network via external IP)
# For internal clients trying to reach 203.0.113.1:80 -> 192.168.1.10:80
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.1.10 -p tcp --dport 80 -j MASQUERADE
# Forward from specific source
iptables -t nat -A PREROUTING -i eth0 -s 10.0.0.0/8 -p tcp --dport 3389 -j DNAT --to-destination 192.168.1.50:3389
nftables Port Forwarding
# Basic port forward
nft add rule ip nat prerouting iifname "eth0" tcp dport 80 dnat to 192.168.1.10:80
# Allow forwarded traffic
nft add rule inet filter forward iifname "eth0" oifname "eth1" ip daddr 192.168.1.10 tcp dport 80 accept
# Port forward with port translation
nft add rule ip nat prerouting iifname "eth0" tcp dport 2222 dnat to 192.168.1.20:22
# Forward multiple ports to same host
nft add rule ip nat prerouting iifname "eth0" tcp dport { 80, 443, 8080 } dnat to 192.168.1.10
# Forward port range
nft add rule ip nat prerouting iifname "eth0" tcp dport 10000-10100 dnat to 192.168.1.30
# Hairpin NAT
nft add rule ip nat postrouting ip saddr 192.168.1.0/24 ip daddr 192.168.1.10 tcp dport 80 masquerade
# Forward from specific source
nft add rule ip nat prerouting iifname "eth0" ip saddr 10.0.0.0/8 tcp dport 3389 dnat to 192.168.1.50:3389
Examples
# Complete web server port forwarding setup
# iptables version
# Enable forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
# NAT rules
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j DNAT --to-destination 192.168.1.10:80
iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 443 -j DNAT --to-destination 192.168.1.10:443
# FORWARD rules
iptables -A FORWARD -i eth0 -o eth1 -p tcp -d 192.168.1.10 --dport 80 \
-m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -i eth0 -o eth1 -p tcp -d 192.168.1.10 --dport 443 \
-m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Hairpin NAT for internal access
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.1.10 -p tcp --dport 80 -j MASQUERADE
iptables -t nat -A POSTROUTING -s 192.168.1.0/24 -d 192.168.1.10 -p tcp --dport 443 -j MASQUERADE
# nftables version
nft flush ruleset
# NAT table
nft add table ip nat
nft add chain ip nat prerouting { type nat hook prerouting priority -100 \; }
nft add chain ip nat postrouting { type nat hook postrouting priority 100 \; }
# Port forwards
nft add rule ip nat prerouting iifname "eth0" tcp dport { 80, 443 } dnat to 192.168.1.10
# Hairpin NAT
nft add rule ip nat postrouting ip saddr 192.168.1.0/24 ip daddr 192.168.1.10 tcp dport { 80, 443 } masquerade
# Filter table
nft add table inet filter
nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
# Forward rules
nft add rule inet filter forward iifname "eth0" oifname "eth1" ip daddr 192.168.1.10 tcp dport { 80, 443 } ct state new accept
nft add rule inet filter forward ct state established,related accept
# Multiple service port forwarding
# SSH to server 1
nft add rule ip nat prerouting iifname "eth0" tcp dport 2201 dnat to 192.168.1.11:22
# SSH to server 2
nft add rule ip nat prerouting iifname "eth0" tcp dport 2202 dnat to 192.168.1.12:22
# MySQL to database server
nft add rule ip nat prerouting iifname "eth0" tcp dport 3306 dnat to 192.168.1.20:3306
Stateful Inspection
Connection tracking enables stateful packet inspection, allowing intelligent handling of related traffic.
Key Concepts
- NEW - First packet of a connection
- ESTABLISHED - Packets belonging to an existing connection
- RELATED - New connections related to existing ones (e.g., FTP data, ICMP errors)
- INVALID - Packets that don't match any known connection
- UNTRACKED - Packets bypassing connection tracking (raw table)
stateDiagram-v2
[*] --> NEW: First packet
NEW --> ESTABLISHED: Reply received
ESTABLISHED --> ESTABLISHED: Bidirectional traffic
ESTABLISHED --> [*]: Connection closed
ESTABLISHED --> RELATED: Related connection
RELATED --> ESTABLISHED: Established
[*] --> INVALID: Malformed/Unknown
INVALID --> [*]: Dropped
iptables Connection Tracking
# Allow established and related connections (essential rule)
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow new outgoing connections
iptables -A OUTPUT -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT
# Drop invalid packets
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# Allow new incoming on specific ports
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
# View connection tracking table
conntrack -L
conntrack -L -p tcp
conntrack -L --src 192.168.1.10
# Delete specific connection
conntrack -D -s 192.168.1.10
# Flush connection tracking table
conntrack -F
# Connection tracking limits
# Increase max tracked connections
sysctl -w net.netfilter.nf_conntrack_max=262144
# View current connection count
cat /proc/sys/net/netfilter/nf_conntrack_count
# Helper modules for application protocols
# FTP helper (for active FTP)
modprobe nf_conntrack_ftp
iptables -A INPUT -p tcp --dport 21 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Track specific connection attributes
iptables -A INPUT -m conntrack --ctstate NEW --ctproto tcp --ctorigsrcport 1024: -j ACCEPT
nftables Connection Tracking
# Allow established and related connections
nft add rule inet filter input ct state established,related accept
nft add rule inet filter forward ct state established,related accept
# Allow new outgoing connections
nft add rule inet filter output ct state new,established accept
# Drop invalid packets
nft add rule inet filter input ct state invalid drop
# Allow new incoming on specific ports
nft add rule inet filter input tcp dport 22 ct state new accept
nft add rule inet filter input tcp dport { 80, 443 } ct state new accept
# Connection tracking with specific states
nft add rule inet filter input ct state { new, established, related } accept
# Track connections by mark
nft add rule inet filter input ct mark 1 accept
# Set connection mark
nft add rule inet filter forward ip saddr 192.168.1.0/24 ct mark set 1
# Connection rate limiting
nft add rule inet filter input ct state new tcp dport 22 limit rate 3/minute accept
# Connection counting
nft add rule inet filter input ct count over 100 drop
Examples
# Complete stateful firewall with iptables
iptables -F
iptables -X
# Default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT
# Loopback
iptables -A INPUT -i lo -j ACCEPT
# Drop invalid
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
# Allow established and related
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
# Allow new connections to specific services
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
# Allow ICMP
iptables -A INPUT -p icmp --icmp-type echo-request -m conntrack --ctstate NEW -j ACCEPT
# Rate limit new SSH connections
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --set --name SSH
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --update --seconds 60 --hitcount 4 --name SSH -j DROP
# Complete stateful firewall with nftables
nft flush ruleset
nft add table inet filter
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
nft add chain inet filter forward { type filter hook forward priority 0 \; policy drop \; }
nft add chain inet filter output { type filter hook output priority 0 \; policy accept \; }
# Loopback
nft add rule inet filter input iif lo accept
# Drop invalid
nft add rule inet filter input ct state invalid drop
# Allow established and related
nft add rule inet filter input ct state established,related accept
# Allow new connections to services
nft add rule inet filter input tcp dport { 22, 80, 443 } ct state new accept
# Allow ICMP
nft add rule inet filter input ip protocol icmp ct state new accept
nft add rule inet filter input ip6 nexthdr icmpv6 ct state new accept
# Rate limit SSH
nft add rule inet filter input tcp dport 22 ct state new limit rate 3/minute accept
Logging and Debugging
Logging provides visibility into firewall decisions, essential for troubleshooting and security monitoring.
Key Concepts
- LOG Target - Write packet information to syslog/dmesg
- NFLOG Target - Send to userspace for advanced logging
- Log Prefix - Identify log entries with custom prefix
- Log Level - Syslog severity level
- Rate Limiting - Prevent log flooding
iptables Logging
# Basic logging
iptables -A INPUT -j LOG --log-prefix "iptables INPUT: "
# Log with specific level
iptables -A INPUT -j LOG --log-prefix "DROPPED: " --log-level 4
# Log and then drop
iptables -A INPUT -j LOG --log-prefix "INPUT DROP: " --log-level warning
iptables -A INPUT -j DROP
# Rate-limited logging (prevent flooding)
iptables -A INPUT -m limit --limit 5/min --limit-burst 10 \
-j LOG --log-prefix "RATE LIMITED: "
# Log specific traffic
iptables -A INPUT -p tcp --dport 22 -j LOG --log-prefix "SSH attempt: "
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# Log dropped traffic
iptables -N LOGGING
iptables -A INPUT -j LOGGING
iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
iptables -A LOGGING -j DROP
# Log TCP flags
iptables -A INPUT -p tcp --tcp-flags ALL NONE -j LOG --log-prefix "NULL scan: "
# Log with additional info
iptables -A INPUT -j LOG --log-prefix "Firewall: " --log-tcp-sequence --log-tcp-options --log-ip-options
# NFLOG for userspace logging
iptables -A INPUT -j NFLOG --nflog-group 1 --nflog-prefix "netfilter"
# View logs
dmesg | grep "iptables"
journalctl -k | grep "iptables"
tail -f /var/log/kern.log | grep "iptables"
nftables Logging
# Basic logging
nft add rule inet filter input log prefix "nft input: "
# Log with specific level
nft add rule inet filter input log prefix "DROPPED: " level warn
# Log and counter
nft add rule inet filter input log prefix "INPUT: " counter
# Rate-limited logging
nft add rule inet filter input limit rate 5/minute log prefix "RATE LIMITED: "
# Log specific traffic
nft add rule inet filter input tcp dport 22 log prefix "SSH: " accept
# Create log chain
nft add chain inet filter log_drop
nft add rule inet filter log_drop limit rate 5/minute log prefix "DROPPED: "
nft add rule inet filter log_drop drop
# Jump to log chain
nft add rule inet filter input tcp dport 23 jump log_drop
# Log with flags
nft add rule inet filter input log prefix "Detailed: " flags all
# Counter without logging
nft add rule inet filter input tcp dport 80 counter accept
# Named counter
nft add counter inet filter http_counter
nft add rule inet filter input tcp dport 80 counter name http_counter accept
# View counters
nft list counters
Debugging Commands
# iptables debugging
# List rules with packet/byte counters
iptables -L -v -n
# List rules in specific table
iptables -t nat -L -v -n
iptables -t mangle -L -v -n
iptables -t raw -L -v -n
# Show rules in numeric format (faster)
iptables -S
# Watch rules in real-time
watch -n 1 'iptables -L -v -n'
# Trace packet through iptables (requires raw table)
iptables -t raw -A PREROUTING -p tcp --dport 80 -j TRACE
iptables -t raw -A OUTPUT -p tcp --dport 80 -j TRACE
# View trace in logs
dmesg | grep TRACE
# nftables debugging
# List ruleset with handles (for deletion)
nft -a list ruleset
# List specific table
nft list table inet filter
# List chain with counters
nft list chain inet filter input
# Monitor events in real-time
nft monitor
# Monitor with trace
nft monitor trace
# Enable tracing for specific packets
nft add rule inet filter input tcp dport 80 meta nftrace set 1
# View trace output
nft monitor trace
# General debugging
# View connection tracking
conntrack -L
conntrack -E # Real-time events
# Check netfilter modules
lsmod | grep nf_
lsmod | grep xt_
# Check for errors
dmesg | tail -50
journalctl -xe
# Packet capture for debugging
tcpdump -i eth0 port 80 -n
# Test connectivity through firewall
nc -vz 192.168.1.10 80
curl -v http://192.168.1.10/
Examples
# Complete logging setup for iptables
# Create custom chains for logging
iptables -N LOG_ACCEPT
iptables -N LOG_DROP
# Define logging chains
iptables -A LOG_ACCEPT -j LOG --log-prefix "ACCEPTED: " --log-level info
iptables -A LOG_ACCEPT -j ACCEPT
iptables -A LOG_DROP -m limit --limit 5/min --limit-burst 10 \
-j LOG --log-prefix "DROPPED: " --log-level warning
iptables -A LOG_DROP -j DROP
# Use in rules
iptables -A INPUT -p tcp --dport 22 -j LOG_ACCEPT
iptables -A INPUT -p tcp --dport 80 -j LOG_ACCEPT
iptables -A INPUT -j LOG_DROP
# Configure rsyslog for iptables
# Add to /etc/rsyslog.d/iptables.conf:
# :msg,contains,"iptables" /var/log/iptables.log
# & stop
# Complete logging setup for nftables
nft flush ruleset
nft add table inet filter
# Create log chains
nft add chain inet filter log_accept
nft add chain inet filter log_drop
# Define log chains
nft add rule inet filter log_accept log prefix "ACCEPTED: " level info
nft add rule inet filter log_accept accept
nft add rule inet filter log_drop limit rate 5/minute log prefix "DROPPED: " level warn
nft add rule inet filter log_drop drop
# Main chains
nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
# Use log chains
nft add rule inet filter input iif lo accept
nft add rule inet filter input ct state established,related accept
nft add rule inet filter input tcp dport { 22, 80, 443 } jump log_accept
nft add rule inet filter input jump log_drop
Quick Reference
iptables Command Reference
| Command | Description |
|---|---|
iptables -L -v -n |
List all rules with details |
iptables -S |
List rules in save format |
iptables -F |
Flush all rules |
iptables -X |
Delete all custom chains |
iptables -Z |
Zero all counters |
iptables -P CHAIN TARGET |
Set default policy |
iptables -A CHAIN |
Append rule to chain |
iptables -I CHAIN [num] |
Insert rule at position |
iptables -D CHAIN [num] |
Delete rule by number |
iptables -R CHAIN num |
Replace rule at position |
iptables -N CHAIN |
Create new chain |
iptables-save |
Output rules for saving |
iptables-restore |
Restore rules from file |
nftables Command Reference
| Command | Description |
|---|---|
nft list ruleset |
List all rules |
nft list table inet filter |
List specific table |
nft flush ruleset |
Flush all rules |
nft add table family name |
Create new table |
nft add chain table name |
Create new chain |
nft add rule table chain ... |
Add rule to chain |
nft insert rule table chain ... |
Insert at beginning |
nft delete rule table chain handle N |
Delete by handle |
nft -a list ruleset |
List with handles |
nft monitor |
Monitor changes |
nft -f file.nft |
Load from file |
Common Targets
| Target | Description |
|---|---|
ACCEPT |
Allow the packet |
DROP |
Silently discard packet |
REJECT |
Discard with ICMP error |
LOG |
Log packet details |
SNAT |
Source NAT |
DNAT |
Destination NAT |
MASQUERADE |
Dynamic SNAT |
REDIRECT |
Redirect to local port |
RETURN |
Return from chain |
Connection States
| State | Description |
|---|---|
NEW |
First packet of connection |
ESTABLISHED |
Part of existing connection |
RELATED |
Related to existing connection |
INVALID |
Cannot be identified |
UNTRACKED |
Bypassed connection tracking |
Common Issues and Solutions
| Issue | Cause | Solution |
|---|---|---|
| Rules not persisting after reboot | Rules not saved | Use iptables-save or install iptables-persistent package |
| Locked out of SSH | Dropped INPUT before allowing SSH | Always add SSH allow rule first: iptables -I INPUT -p tcp --dport 22 -j ACCEPT |
| NAT not working | IP forwarding disabled | Enable with sysctl -w net.ipv4.ip_forward=1 |
| FORWARD rules not matching | Wrong interface direction | Check -i (input) and -o (output) interface names |
| nftables rules not loading | Syntax errors in config | Validate with nft -c -f /etc/nftables.conf |
| Connection tracking table full | Too many connections | Increase nf_conntrack_max sysctl |
| FTP passive mode failing | RELATED packets blocked | Load nf_conntrack_ftp and allow ESTABLISHED,RELATED |
| Hairpin NAT not working | Missing MASQUERADE for internal | Add MASQUERADE rule for internal-to-internal NAT |
| Rules exist but not matching | Rule order incorrect | Check rule position; earlier rules take precedence |
| Docker networking broken | Docker rules flushed | Use Docker's DOCKER-USER chain for custom rules |
| Counters reset to zero | Rules replaced instead of modified | Use -R to replace without resetting counters |
| Slow performance with many rules | Linear rule processing | Use ipset for large IP lists or upgrade to nftables |
Troubleshooting Tips
# Check if netfilter modules are loaded
lsmod | grep nf_conntrack
# Verify IP forwarding is enabled
cat /proc/sys/net/ipv4/ip_forward
# Check current connection tracking count
cat /proc/sys/net/netfilter/nf_conntrack_count
# Monitor dropped packets in real-time
watch -n 1 'iptables -L -v -n | grep DROP'
# Test rules without applying permanently
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# Test, then remove if needed
iptables -D INPUT -p tcp --dport 80 -j ACCEPT
# Safe remote firewall changes (auto-revert)
at now + 5 minutes <<< 'iptables -F'
# Apply changes, test SSH, then cancel: atrm JOB_ID
# Debug nftables with trace
nft add rule inet filter input meta nftrace set 1
nft monitor trace
Related Topics
The following topics would complement this iptables/nftables cheatsheet:
- tcpdump/Wireshark - Capture and analyse network traffic for firewall debugging
- systemd - Configure persistent firewall rules with service units
- Docker - Understand Docker's interaction with iptables rules
- Kubernetes Network Policies - Cluster-level traffic filtering that complements node firewalls
- SELinux/AppArmor - Additional security layer with mandatory access controls
- HAProxy/Nginx - Application-level traffic control complementing network firewalls