Firewall log rules emit kernel messages, so by default they flood kern.log/messages and the journal. The usual goal is to tag them with a recognizable prefix and send them to their own file.
Generate the log messages¶
nftables (default backend on current distros):
# Log and drop everything not otherwise accepted on input, rate-limited
sudo nft add rule inet filter input limit rate 10/second log prefix \"nft-drop: \" level warn
sudo nft add rule inet filter input drop
Or in /etc/nftables.conf:
chain input {
type filter hook input priority 0; policy drop;
ct state established,related accept
iif lo accept
tcp dport 22 accept
limit rate 10/second log prefix "nft-drop: " level warn
}
iptables (legacy):
sudo iptables -N LOGDROP
sudo iptables -A LOGDROP -m limit --limit 10/min -j LOG --log-prefix "ipt-drop: " --log-level 4
sudo iptables -A LOGDROP -j DROP
sudo iptables -A INPUT -j LOGDROP # as the last INPUT rule
firewalld:
sudo firewall-cmd --set-log-denied=all # all | unicast | broadcast | multicast | off
sudo firewall-cmd --get-log-denied
firewalld uses prefixes such as filter_IN_public_REJECT: (exact text varies by version).
UFW logs with the prefix [UFW BLOCK] and already ships an rsyslog rule (/etc/rsyslog.d/20-ufw.conf) writing to /var/log/ufw.log:
sudo ufw logging medium # off | low | medium | high | full
Route them to their own file with rsyslog¶
/etc/rsyslog.d/10-firewall.conf (the 10- prefix makes it run before the default rules):
if ($msg contains "nft-drop: " or $msg contains "ipt-drop: " or $msg contains "filter_IN_") then {
action(type="omfile" file="/var/log/firewall.log")
stop
}
sudo rsyslogd -N1 && sudo systemctl restart rsyslog
sudo tail -F /var/log/firewall.log
Add /var/log/firewall.log to logrotate (see logrotate).
Without rsyslog¶
journalctl -k -g 'nft-drop: ' --since "10 min ago"
journalctl -k -g 'nft-drop: ' -o cat | grep -oE 'SRC=[0-9.]+' | sort | uniq -c | sort -rn | head
Always rate-limit firewall log rules. An unlimited LOG rule on an internet-facing host is an easy way to fill a disk.