iptables & nftables Cheatsheet
Logging and Rate Limiting
Use this iptables & nftables reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
LOG and NFLOG
LOG is non-terminating. The packet keeps going through the chain after the log
entry is written, so a log rule sits above the rule that actually acts.
sudo iptables -A INPUT -p tcp --dport 22 -j LOG --log-prefix "ssh-in: " --log-level info sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT
| Option | Effect |
|---|---|
--log-prefix "text: " | tag, up to 29 characters, keep the trailing space |
--log-level | emerg … debug, warning and info are the usual choices |
--log-tcp-options | include TCP options |
--log-ip-options | include IP options |
--log-tcp-sequence | include sequence numbers, avoid on shared logs |
--log-uid | include the owning uid for locally generated packets |
# NFLOG hands packets to userspace, which is what ulogd and tcpdump read sudo iptables -A INPUT -j NFLOG --nflog-group 1 --nflog-prefix "dropped" sudo tcpdump -i nflog:1 -n # watch logged packets as packets
| Target | Destination | Pick it when |
|---|---|---|
LOG | kernel log, dmesg, journal, syslog | quick diagnosis, small volume |
NFLOG | a netlink group, read by ulogd or tcpdump | structured logs, full packets, high volume |
TRACE | kernel log, every table and chain the packet visits | debugging rule order, never in production |
Reading firewall logs
sudo dmesg -w | grep -i 'ssh-in' sudo journalctl -k -f sudo journalctl -k --since '10 min ago' | grep 'iptables-drop' sudo grep 'iptables-drop' /var/log/kern.log # Debian and Ubuntu sudo tail -f /var/log/messages # RHEL family
kernel: iptables-drop: IN=eth0 OUT= MAC=52:54:00:12:34:56:52:54:00:ab:cd:ef:08:00 SRC=198.51.100.9 DST=10.0.0.5 LEN=60 TOS=0x00 PREC=0x00 TTL=54 ID=41928 DF PROTO=TCP SPT=44122 DPT=3306 WINDOW=29200 RES=0x00 SYN URGP=0
| Field | Meaning |
|---|---|
IN / OUT | interfaces, an empty OUT means the packet was destined here |
MAC | destination MAC, source MAC, ethertype, concatenated |
SRC / DST | addresses after any NAT that already happened |
PROTO, SPT, DPT | protocol and ports |
TTL | remaining hops, a rough hint at how far away the sender is |
SYN, ACK, RST | the TCP flags that were set |
# top talkers hitting your drop rule sudo journalctl -k --since today | grep 'iptables-drop' \ | grep -oP 'SRC=\K[0-9.]+' | sort | uniq -c | sort -rn | head # most probed ports sudo journalctl -k --since today | grep 'iptables-drop' \ | grep -oP 'DPT=\K[0-9]+' | sort -n | uniq -c | sort -rn | head
Keeping logs from filling the disk
An unthrottled log rule on an internet-facing host will write gigabytes during a scan and can wedge the box before the firewall ever fails.
# a log chain that throttles, then drops sudo iptables -N logdrop sudo iptables -A logdrop -m limit --limit 5/min --limit-burst 10 \ -j LOG --log-prefix "iptables-drop: " --log-level info sudo iptables -A logdrop -j DROP sudo iptables -A INPUT -j logdrop
| Guard | Command fragment |
|---|---|
| Global cap | -m limit --limit 5/min --limit-burst 10 |
| Per source cap | -m hashlimit --hashlimit-above 1/min --hashlimit-mode srcip |
| Skip the noisiest traffic | an -j RETURN rule above the log for broadcast and multicast |
| Keep it out of the console | --log-level debug plus a syslog rule, or NFLOG |
| Rate-limit the kernel itself | sysctl net.core.message_cost, net.core.message_burst |
# do not log the usual LAN chatter at all sudo iptables -I logdrop -m addrtype --dst-type BROADCAST -j DROP sudo iptables -I logdrop -d 224.0.0.0/4 -j DROP # send firewall logs to their own file, rsyslog echo ':msg, contains, "iptables-drop:" -/var/log/firewall.log' \ | sudo tee /etc/rsyslog.d/10-firewall.conf echo '& stop' | sudo tee -a /etc/rsyslog.d/10-firewall.conf sudo systemctl restart rsyslog
Rate limiting traffic, not just logs
| Module | Scope | Best for |
|---|---|---|
limit | one bucket for the whole rule | logs, ICMP, anything where a global cap is fine |
hashlimit | one bucket per key, such as source address | per-client fairness and abuse control |
connlimit | concurrent connections per host or prefix | slowloris style connection hoarding |
recent | address history with a time window | brute-force lockouts |
# ICMP echo: 2 a second overall sudo iptables -A INPUT -p icmp --icmp-type echo-request \ -m limit --limit 2/second --limit-burst 5 -j ACCEPT sudo iptables -A INPUT -p icmp --icmp-type echo-request -j DROP # new SMTP connections: 30 a minute per source sudo iptables -A INPUT -p tcp --dport 25 -m conntrack --ctstate NEW \ -m hashlimit --hashlimit-above 30/min --hashlimit-burst 40 \ --hashlimit-mode srcip --hashlimit-name smtp -j DROP # no more than 15 open HTTP connections per client sudo iptables -A INPUT -p tcp --dport 80 \ -m connlimit --connlimit-above 15 --connlimit-mask 32 \ -j REJECT --reject-with tcp-reset
# inspect the hashlimit buckets
sudo cat /proc/net/ipt_hashlimit/smtpThe token bucket is worth understanding: --limit 5/min refills five tokens a
minute, --limit-burst 10 sets the bucket size. Ten packets can match back to
back, then the rule matches at the refill rate, and quiet time refills the
bucket. A burst of 1 makes the rule match strictly at the average rate.
SYN floods and connection abuse
# cap new connection attempts per second, globally sudo iptables -A INPUT -p tcp --syn -m limit --limit 100/second \ --limit-burst 200 -j ACCEPT sudo iptables -A INPUT -p tcp --syn -j DROP # SYN cookies do more than any rule here sudo sysctl -w net.ipv4.tcp_syncookies=1 sudo sysctl -w net.ipv4.tcp_max_syn_backlog=4096 sudo sysctl -w net.ipv4.tcp_synack_retries=2
| Defence | What it actually helps with |
|---|---|
tcp_syncookies | real SYN floods, this is the primary mitigation |
--syn -m limit | small floods and scans, and it also limits legitimate bursts |
hashlimit per source | one abusive client, not a distributed flood |
connlimit | connection hoarding by a small number of hosts |
recent | repeated login attempts from the same address |
| Upstream scrubbing | volumetric attacks, nothing on the host helps once the link is full |
A rule that drops SYNs above a global rate also drops legitimate traffic during a launch or a cache flush. Set the threshold from measured peak load, not from a blog post, and prefer syncookies as the first line.
An audit-friendly logging layout
sudo iptables -N logaccept sudo iptables -A logaccept -m limit --limit 10/min \ -j LOG --log-prefix "fw-accept: " --log-level info sudo iptables -A logaccept -j ACCEPT sudo iptables -N logreject sudo iptables -A logreject -m limit --limit 5/min \ -j LOG --log-prefix "fw-reject: " --log-level warning sudo iptables -A logreject -j REJECT --reject-with icmp-admin-prohibited # rules then read as intent, and every decision is labelled sudo iptables -A INPUT -p tcp --dport 22 -s 10.0.0.0/8 -j logaccept sudo iptables -A INPUT -j logreject
| Practice | Payoff |
|---|---|
| One log chain per decision | every rule ends in a labelled, throttled outcome |
Distinct --log-prefix per chain | grep and alerting become trivial |
warning for denies, info for accepts | severity filtering works without parsing |
| Its own log file plus rotation | firewall noise does not bury other kernel messages |
-m comment on the rules | the log prefix says what, the comment says why |