Comprehensive Guide: Debugging iptables Firewall Rules and Common Configuration Pitfalls


2 views

When troubleshooting firewall issues, always start with these fundamental commands:


# View current rules with line numbers (critical for rule management)
iptables -L -n -v --line-numbers

# Check NAT rules (often overlooked)
iptables -t nat -L -n -v

# Inspect connection tracking
conntrack -L

# Monitor real-time traffic hitting your rules
iptables -L -v -n --line-numbers | grep -v "0     0"

1. The Default Policy Trap


# Dangerous example (blocks all traffic by default)
iptables -P INPUT DROP  
iptables -P FORWARD DROP
iptables -P OUTPUT DROP

# Safer approach during debugging:
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD DROP

2. Rule Order Matters
Rules are processed top-down. A common mistake:


# Bad order (DROP rule blocks everything below)
iptables -A INPUT -j DROP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Correct approach:
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -j DROP

Packet Tracing with TRACE Target


modprobe ipt_LOG
iptables -t raw -A PREROUTING -p tcp --dport 80 -j TRACE
iptables -t raw -A OUTPUT -p tcp --dport 80 -j TRACE

# View traces in kernel logs
dmesg | grep TRACE

Connection Tracking Issues


# Check if connections are being tracked
conntrack -L

# Common problem: NAT not working properly
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

# Verify with:
iptables -t nat -L -n -v

When abstraction layers fail, check the actual rules they generate:


# For UFW:
iptables -L | grep -A 10 ufw

# For FirewallD:
firewall-cmd --list-all
iptables -S
ip6tables -S

Case: SSH Access Blocked

  1. Check if rules exist: iptables -L -n | grep 22
  2. Verify chain order: iptables -L INPUT -n --line-numbers
  3. Test with temporary rule: iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT
  4. Check connection tracking: conntrack -L | grep 22

Diagnostic Script


#!/bin/bash
echo "=== iptables Rules ==="
iptables -L -n -v --line-numbers
echo "\n=== NAT Rules ==="
iptables -t nat -L -n -v
echo "\n=== Connection Tracking ==="
conntrack -L 2>/dev/null || echo "conntrack not available"
echo "\n=== Current Listening Ports ==="
ss -tulnp

Modern Linux systems implement firewalling through multiple abstraction layers:

User Tools (UFW/FirewallD) → iptables → Netfilter hooks → Kernel modules

Always check these first when troubleshooting:

# View current rules with line numbers
iptables -L -n -v --line-numbers

# Check NAT rules
iptables -t nat -L -n -v

# Examine specific chain
iptables -L INPUT -n -v

# View connection tracking
conntrack -L

# Check loaded kernel modules
lsmod | grep nf_

Rules are evaluated top-to-bottom. A classic mistake:

# Problematic order:
iptables -A INPUT -j DROP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT  # Never reached!

# Correct approach:
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT  # Insert at top
iptables -A INPUT -j DROP

Many admins forget about stateful filtering:

# Without connection tracking (breaks many protocols):
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# Proper stateful approach:
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

Rules may apply to wrong interfaces:

# Explicit interface specification
iptables -A INPUT -i eth0 -p tcp --dport 443 -j ACCEPT

# Specific source IP range
iptables -A INPUT -s 192.168.1.0/24 -j ACCEPT

Strategic logging helps diagnose issues:

# Create logging chain
iptables -N LOGGING
iptables -A INPUT -j LOGGING

# Log and continue processing
iptables -A LOGGING -m limit --limit 2/min -j LOG --log-prefix "IPTables-Dropped: " --log-level 4
iptables -A LOGGING -j DROP

# View logs in real-time
tail -f /var/log/kern.log | grep IPTables

Common NAT issues and solutions:

# Check if NAT is applied
iptables -t nat -L -n -v

# Typical port forwarding example
iptables -t nat -A PREROUTING -p tcp --dport 8080 -j DNAT --to-destination 192.168.1.10:80
iptables -A FORWARD -p tcp -d 192.168.1.10 --dport 80 -j ACCEPT

# Enable IP forwarding
sysctl -w net.ipv4.ip_forward=1

When using abstraction layers:

# UFW debugging
ufw status verbose
ufw show raw

# FirewallD troubleshooting
firewall-cmd --list-all-zones
firewall-cmd --get-active-zones
journalctl -u firewalld --no-pager -n 50

For deep diagnosis:

# Enable debug logging
echo 'module nf_log_ipv4 +p' > /sys/kernel/debug/dynamic_debug/control
dmesg -wH

# Check packet traversal
iptables -t raw -A PREROUTING -j TRACE
iptables -t raw -A OUTPUT -j TRACE

# Monitor via syslog
grep TRACE /var/log/syslog