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
- Check if rules exist:
iptables -L -n | grep 22
- Verify chain order:
iptables -L INPUT -n --line-numbers
- Test with temporary rule:
iptables -I INPUT 1 -p tcp --dport 22 -j ACCEPT
- 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