When debugging iptables rules, it's crucial to understand the packet traversal order through the chains:
INPUT → PREROUTING → FORWARD → POSTROUTING → OUTPUT
Each packet is evaluated against rules sequentially until it matches a terminating target (ACCEPT/DROP/REJECT).
The simplest way to track dropped packets is using iptables' built-in counters:
# List all rules with packet/byte counters
sudo iptables -L -n -v
# Example output:
Chain INPUT (policy DROP 12 packets, 1204 bytes)
pkts bytes target prot opt in out source destination
15 1344 ACCEPT all -- eth0 * 192.168.1.0/24 0.0.0.0/0
2 144 DROP all -- * * 10.0.0.0/8 0.0.0.0/0
For more detailed debugging, insert logging rules before critical targets:
# Log dropped packets in INPUT chain
sudo iptables -A INPUT -j LOG --log-prefix "IPTABLES-DROP: " --log-level 4
# Log accepted packets in OUTPUT chain
sudo iptables -I OUTPUT 1 -j LOG --log-prefix "IPTABLES-ACCEPT: " --log-level 6
View logs using:
sudo tail -f /var/log/syslog | grep IPTABLES
For kernel-level tracing (requires kernel 2.6.24+):
# Load the trace module
sudo modprobe nf_log_ipv4
# Enable tracing for specific rule
sudo iptables -t raw -A PREROUTING -p tcp --dport 80 -j TRACE
# Monitor trace output
sudo dmesg -w | grep TRACE
This bash script helps verify rule effectiveness:
#!/bin/bash
RULES=$(sudo iptables -L -n --line-numbers)
echo "Current iptables rules:"
echo "$RULES"
echo -e "\nTesting rule effectiveness..."
for chain in INPUT FORWARD OUTPUT; do
echo "Chain $chain packet counts:"
sudo iptables -L $chain -n -v | grep -E 'ACCEPT|DROP|REJECT'
done
Case 1: Port blocking mystery
# Add logging before your port rule
sudo iptables -I INPUT -p tcp --dport 8080 -j LOG --log-prefix "8080-Access: "
# Then check which process might be interfering
sudo netstat -tulnp | grep 8080
Case 2: Tracking NAT issues
# Enable logging for NAT table
sudo iptables -t nat -L -v -n
# Add trace for NAT operations
sudo iptables -t nat -A PREROUTING -j TRACE
When debugging iptables behavior, it's crucial to understand the rule evaluation flow. Packets traverse chains sequentially until they match a rule with terminating target (ACCEPT/DROP/REJECT). The key debugging commands are:
# View all rules with packet/byte counters
iptables -L -n -v
# Check specific chain (e.g., INPUT)
iptables -L INPUT -n -v --line-numbers
# Reset counters to zero for fresh monitoring
iptables -Z
For real-time debugging, insert LOG rules before critical rules:
# Log UDP packets on port 53 before processing
iptables -I INPUT -p udp --dport 53 -j LOG --log-prefix "[DNS-INPUT] "
# View logs (systemd)
journalctl -k -f | grep DNS-INPUT
Modern kernels support packet tracing:
# Enable tracing module
modprobe nf_log_ipv4
sysctl net.netfilter.nf_log.2=nf_log_ipv4
# Add trace rule
iptables -t raw -A PREROUTING -p tcp --dport 80 -j TRACE
# View trace (requires debugfs)
mount -t debugfs none /sys/kernel/debug
tail -f /sys/kernel/debug/tracing/trace_pipe
For complex rule sets, create a dedicated debug chain:
# Create chain
iptables -N DEBUG
# Redirect specific traffic
iptables -A INPUT -s 192.168.1.100 -j DEBUG
# Add debug rules
iptables -A DEBUG -j LOG --log-prefix "DEBUG-IN: "
iptables -A DEBUG -j RETURN
This Bash script monitors dropped packets hourly:
#!/bin/bash
LOG_FILE="/var/log/iptables_drops.log"
while true; do
date >> $LOG_FILE
iptables -L INPUT -n -v | grep DROP >> $LOG_FILE
iptables -L OUTPUT -n -v | grep DROP >> $LOG_FILE
sleep 3600
done