Skip to content

📝 Logging and Analysis

Why Log?

A firewall silently drops packets, but you want to know exactly what was dropped. A firewall without logs is like a factory without surveillance — when something goes wrong, all you can do is guess.

iptables' LOG target can record packet information to /var/log/kern.log or /var/log/messages before dropping.

LOG Target In-Depth

bash
# Basic logging
iptables -A INPUT -j LOG --log-prefix "IPT-INPUT-DROP: " --log-level 4

# Common log levels
# 0 = emerg    1 = alert   2 = crit    3 = err
# 4 = warning  5 = notice  6 = info    7 = debug

# Only log traffic for specific ports (don't log everything or logs will explode)
iptables -A INPUT -p tcp --dport 22 -m state --state NEW \
  -j LOG --log-prefix "SSH-NEW: " --log-level 4

# Rate-limit logging (prevent log storms from killing the system!)
iptables -A INPUT -m limit --limit 5/min --limit-burst 10 \
  -j LOG --log-prefix "IPT-DROP: " --log-level 4

# Log invalid packets
iptables -A INPUT -m state --state INVALID \
  -j LOG --log-prefix "INVALID: " --log-level 4

# Log rejections for different services separately (easier troubleshooting)
iptables -A INPUT -p tcp --dport 3306 -j LOG --log-prefix "MYSQL-BLOCKED: "
iptables -A INPUT -p tcp --dport 6379 -j LOG --log-prefix "REDIS-BLOCKED: "
iptables -A INPUT -p tcp --dport 27017 -j LOG --log-prefix "MONGO-BLOCKED: "

> ⚠️ Warning: > ⚠️ Important: Don't follow LOG with DROP/REJECT! LOG only "records" — it doesn't terminate rule chain processing. The correct approach is to match before LOG, and rules after LOG continue to match (typically followed by a DROP).

Viewing and Analyzing Logs

bash
# Real-time firewall log viewing
tail -f /var/log/kern.log | grep IPT

# View last 100 rejected connections
journalctl -k --since "1 hour ago" | grep "IPT-DROP" | tail -100

# Count most rejected IPs (Top 10 attackers)
journalctl -k | grep "IPT-DROP" | \
  grep -oP 'SRC=\K[0-9.]+' | sort | uniq -c | sort -rn | head -10
  15234 185.220.101.34
   8921 45.155.205.12
   3201 192.168.1.200
   ...

# Analyze which ports are scanned most
journalctl -k | grep "IPT-DROP" | \
  grep -oP 'DPT=\K[0-9]+' | sort | uniq -c | sort -rn | head -10
  23001 445
  18923 3389
   5421 22
   2100 3306
   ...

# View all logs for a specific IP
journalctl -k | grep "185.220.101.34" | tail -20

# One-click export analysis report
echo "=== iptables Log Analysis Report ===" > /tmp/ipt-report.txt
echo "Time: $(date)" >> /tmp/ipt-report.txt
echo "" >> /tmp/ipt-report.txt
echo "--- Top 10 Rejected IPs ---" >> /tmp/ipt-report.txt
journalctl -k --since "24 hours ago" | grep "IPT-DROP" | \
  grep -oP 'SRC=\K[0-9.]+' | sort | uniq -c | sort -rn | head -10 >> /tmp/ipt-report.txt
echo "" >> /tmp/ipt-report.txt
echo "--- Top 10 Scanned Ports ---" >> /tmp/ipt-report.txt
journalctl -k --since "24 hours ago" | grep "IPT-DROP" | \
  grep -oP 'DPT=\K[0-9]+' | sort | uniq -c | sort -rn | head -10 >> /tmp/ipt-report.txt
cat /tmp/ipt-report.txt

Using rsyslog for Categorized Storage

Having trouble finding iptables logs mixed in with system logs? Use rsyslog to store them in a separate file:

bash
# Create rsyslog rule
cat > /etc/rsyslog.d/iptables.conf << 'EOF'
:msg, contains, "IPT-" /var/log/iptables.log
& stop
EOF

# Restart rsyslog
systemctl restart rsyslog

# Configure logrotate to prevent logs from filling the disk
cat > /etc/logrotate.d/iptables << 'EOF'
/var/log/iptables.log {
    daily
    rotate 7
    compress
    missingok
    notifempty
    postrotate
        systemctl restart rsyslog
    endscript
}
EOF