The LOG target in iptables doesn’t actually log anything itself; it just passes the packet to the kernel’s logging subsystem, which then uses syslog to write the message to a file.

Let’s see iptables in action, logging dropped packets on my development server. I’m running a simple setup: a web server on port 80 and SSH on port 22. I want to log any traffic that isn’t destined for these ports, or traffic coming from a specific internal subnet that I don’t want to talk to my web server.

# First, allow established connections and loopback
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT

# Allow SSH and HTTP
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j ACCEPT

# Block and log traffic from a specific internal subnet that shouldn't reach the web server
iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 80 -j LOG --log-prefix "BLOCKED_INTERNAL_WEB: " --log-level 4

# Drop all other incoming traffic and log it
iptables -A INPUT -j LOG --log-prefix "DROPPED_INBOUND: " --log-level 4
iptables -A INPUT -j DROP

# Optionally, log outgoing traffic that isn't related to established connections
# iptables -A OUTPUT -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j ACCEPT
# iptables -A OUTPUT -j LOG --log-prefix "DROPPED_OUTBOUND: " --log-level 4
# iptables -A OUTPUT -j DROP

Now, if I try to access my web server from that blocked subnet:

curl http://192.168.1.100

Or if I try to access an unallowed port from anywhere:

curl http://192.168.1.100:8080

I won’t get a response, but I will see logs. The key here is that iptables doesn’t write to files directly. It hands off the packet information to the kernel’s logging daemon. On most Linux systems, this is rsyslog.

The LOG target itself has a few important options. --log-prefix is crucial for distinguishing between different types of logged traffic. I’ve used "BLOCKED_INTERNAL_WEB: " and "DROPPED_INBOUND: " to make it obvious in the logs. --log-level corresponds to the standard syslog levels (0-7), with 4 (warning) being a common choice for general logging.

Here’s what the log entries might look like in /var/log/syslog or /var/log/kern.log (depending on your rsyslog configuration):

Oct 26 10:30:01 my-server kernel: [12345.678901] BLOCKED_INTERNAL_WEB: IN=eth0 OUT= MAC=00:11:22:33:44:55:00:aa:bb:cc:dd:ee:08:00 SRC=192.168.1.100 DST=192.168.1.100 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=12345 DF PROTO=TCP SPT=54321 DPT=80 WINDOW=0 RES=0x00 SYN URGP=0
Oct 26 10:30:05 my-server kernel: [12345.678901] DROPPED_INBOUND: IN=eth0 OUT= MAC=00:11:22:33:44:55:00:aa:bb:cc:dd:ee:08:00 SRC=192.168.1.100 DST=192.168.1.100 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=12346 DF PROTO=TCP SPT=54322 DPT=8080 WINDOW=0 RES=0x00 SYN URGP=0

Notice how the LOG target appears before the DROP target. This is essential. If you put DROP first, the packet is discarded without being logged. The LOG target doesn’t stop the packet; it just records it before the packet continues to the next rule, which in this case is DROP.

The iptables LOG target is a powerful debugging and auditing tool, but it’s crucial to remember that it relies on the system’s syslog daemon to actually persist the logs. Without rsyslog (or a similar service) running and configured to capture kernel messages, your iptables LOG rules will be silent.

The next step in a robust firewall setup is often to centralize these logs, perhaps by sending them to a dedicated log server using rsyslog’s network capabilities.

Want structured learning?

Take the full Iptables course →