Available for day contractsFrom 21st September I have availability for day and half day contracts. Please contact for more information.

Contact →
mikepreston.org

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.

Packet Flow Through NetfilterLocalForwardIncoming PacketDestination?INPUT ChainFORWARD ChainLocal ProcessOUTPUT ChainPOSTROUTINGOutgoing PacketPREROUTINGPacket Flow Through NetfilterLocalForwardIncoming PacketDestination?INPUT ChainFORWARD ChainLocal ProcessOUTPUT ChainPOSTROUTINGOutgoing PacketPREROUTING

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
iptables StructureTableChain 1Chain 2Rule 1Rule 2Rule 3Match + Targetiptables StructureTableChain 1Chain 2Rule 1Rule 2Rule 3Match + Target

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)
Table Processing OrderLocalForwardIncoming Packetraw PREROUTINGmangle PREROUTINGnat PREROUTINGRouting Decisionmangle INPUTfilter INPUTLocal Processmangle FORWARDfilter FORWARDmangle POSTROUTINGnat POSTROUTINGraw OUTPUTmangle OUTPUTnat OUTPUTfilter OUTPUTOutgoing PacketTable Processing OrderLocalForwardIncoming Packetraw PREROUTINGmangle PREROUTINGnat PREROUTINGRouting Decisionmangle INPUTfilter INPUTLocal Processmangle FORWARDfilter FORWARDmangle POSTROUTINGnat POSTROUTINGraw OUTPUTmangle OUTPUTnat OUTPUTfilter OUTPUTOutgoing Packet

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
SNAT/MASQUERADEsrc: 192.168.1.10src: 203.0.113.1Internal Host192.168.1.10FirewallInternetSNAT/MASQUERADEsrc: 192.168.1.10src: 203.0.113.1Internal Host192.168.1.10FirewallInternet
DNATdst: 203.0.113.1:80dst:192.168.1.10:8080InternetFirewallInternal ServerDNATdst: 203.0.113.1:80dst:192.168.1.10:8080InternetFirewallInternal Server

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
Port Forwarding Flowdst: 203.0.113.1:80DNATdst:192.168.1.10:8080InternetClientFirewallPREROUTINGRoutingFORWARDInternalServerPort Forwarding Flowdst: 203.0.113.1:80DNATdst:192.168.1.10:8080InternetClientFirewallPREROUTINGRoutingFORWARDInternalServer

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)
First packetReply receivedBidirectional trafficConnection closedRelated connectionEstablishedMalformed/UnknownDroppedNEWESTABLISHEDRELATEDINVALIDFirst packetReply receivedBidirectional trafficConnection closedRelated connectionEstablishedMalformed/UnknownDroppedNEWESTABLISHEDRELATEDINVALID

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:

  1. tcpdump/Wireshark - Capture and analyse network traffic for firewall debugging
  2. systemd - Configure persistent firewall rules with service units
  3. Docker - Understand Docker's interaction with iptables rules
  4. Kubernetes Network Policies - Cluster-level traffic filtering that complements node firewalls
  5. SELinux/AppArmor - Additional security layer with mandatory access controls
  6. HAProxy/Nginx - Application-level traffic control complementing network firewalls