When setting up iptables as a router with MASQUERADE/NAT, many administrators face this logging behavior where incoming WAN traffic appears to terminate at the router's IP rather than showing the actual LAN destination. This occurs because the DNAT (Destination NAT) translation happens after the logging point in the packet flow.
Here's what happens to incoming packets:
1. Packet arrives at WAN interface (src=WAN_IP, dst=ROUTER_WAN_IP) 2. PREROUTING chain (logging happens here if enabled) 3. DNAT translation occurs (dst changes to LAN_IP) 4. Packet gets routed to LAN interface
To capture the post-NAT destination, we need to log either:
- In the FORWARD chain (after NAT translation)
- Using the NFLOG target to capture complete connection tracking
Here's the optimal iptables configuration:
# Log outgoing (LAN→WAN) connections in POSTROUTING iptables -t nat -A POSTROUTING -o eth0 -j LOG --log-prefix "OUTBOUND: " # Log incoming (WAN→LAN) connections in FORWARD chain iptables -A FORWARD -i eth0 -j LOG --log-prefix "INBOUND: " --log-ip-options
For more detailed logging including NAT translations:
iptables -A FORWARD -j NFLOG --nflog-group 1 --nflog-prefix "FWD: " iptables -t nat -A POSTROUTING -j NFLOG --nflog-group 1 --nflog-prefix "NAT: " # Then monitor with: ulogd -d
Here's a complete working configuration for a router with eth0 (WAN) and eth1 (LAN):
# Enable routing sysctl -w net.ipv4.ip_forward=1 # Basic NAT iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE # Logging rules iptables -A FORWARD -i eth0 -m conntrack --ctstate NEW -j LOG \ --log-prefix "NEW INBOUND: " --log-ip-options --log-tcp-sequence iptables -A FORWARD -o eth0 -m conntrack --ctstate NEW -j LOG \ --log-prefix "NEW OUTBOUND: " --log-ip-options
Sample log output after configuration:
NEW OUTBOUND: IN=eth1 OUT=eth0 SRC=192.168.1.100 DST=8.8.8.8 NEW INBOUND: IN=eth0 OUT=eth1 SRC=8.8.8.8 DST=192.168.1.100
Key parameters to include in logs for better analysis:
- --log-ip-options (shows full IP headers)
- --log-tcp-sequence (for TCP analysis)
- --log-tcp-options (shows TCP flags)
When implementing iptables NAT (Network Address Translation) with masquerading on a Linux router, you'll notice an important logging limitation: incoming WAN-to-LAN connections get logged with the router's internal IP as the destination rather than the true LAN host IP. This breaks end-to-end flow visibility in your logs.
The sequence looks like this in raw logs:
# Outbound (correctly logged):
[OUT] SRC=192.168.32.10 DST=60.242.67.190
# Inbound (problematic logging):
[IN] SRC=60.242.67.190 DST=192.168.32.199 (router WAN IP)
[IN] SRC=192.168.32.199 DST=192.168.32.10 (router LAN IP)
This occurs because iptables processes the DNAT (destination NAT) translation before logging occurs in the PREROUTING chain.
The key is to capture packets in the raw PREROUTING chain before NAT translation occurs:
# For IPv4:
iptables -t raw -I PREROUTING -i eth0 -j TRACE
# For IPv6 (if needed):
ip6tables -t raw -I PREROUTING -i eth0 -j TRACE
Here's a production-ready configuration that preserves original IPs:
# Enable connection tracking logging
modprobe nf_conntrack
echo 1 > /proc/sys/net/netfilter/nf_conntrack_acct
# Log before NAT processing
iptables -t raw -A PREROUTING -j LOG --log-prefix "RAW-PRE: " --log-level 6
iptables -t raw -A OUTPUT -j LOG --log-prefix "RAW-OUT: " --log-level 6
# Main logging rules (post-NAT)
iptables -A FORWARD -j LOG --log-prefix "FWD: " --log-level 6
iptables -A INPUT -j LOG --log-prefix "IN: " --log-level 6
iptables -A OUTPUT -j LOG --log-prefix "OUT: " --log-level 6
For high-traffic routers, consider ULOG which sends logs to userspace:
iptables -A PREROUTING -t raw -j ULOG --ulog-nlgroup 1 --ulog-prefix "PRE-NAT: "
iptables -A POSTROUTING -t mangle -j ULOG --ulog-nlgroup 2 --ulog-prefix "POST-NAT: "
Your syslog will now contain both pre-and-post NAT information. Use this awk script to correlate flows:
awk '/RAW-PRE:/ { pre_src=$6; pre_dst=$8 }
/FWD:/ { if($6==pre_dst) print "Full flow:", pre_src, "->", $8, "via", $6 }' /var/log/syslog
- Ensure conntrack is enabled (
lsmod | grep conntrack
) - Verify logging chain order (
iptables -t raw -vnL
) - Check kernel ring buffer if logs don't appear (
dmesg | grep TRACE
)
For persistent configuration, add these rules to your network init scripts or use iptables-persistent package.