bash - Capturing packets from iptables chains
iptables chains are complex and sometime we need to capture packets from a specific chain to troubleshoot issues. For this, we can use the iptables NFLOG
module that allow us to create a kernel interface and pass the traffic through it.
The magic in all of this is that we can present the interface to tcpdump
and generate packet captures to analyse with the famous and favourite WireShark.
You can use iptables rules to create all sorts of filters or capture all the packets and instead filter with tcpdump while capturing. The example below adds two rules to captures all packets in the filter chain INPUT and OUTPUT.
[root@arch-linux ~]# sfilter
-P INPUT ACCEPT -c 412565 28586119
-P FORWARD ACCEPT -c 0 0
-P OUTPUT ACCEPT -c 214258 11015559
-A INPUT -c 537797 40661282 -j NFLOG --nflog-group 13
-A FORWARD -i ip_vti1 -c 0 0 -j ACCEPT
-A FORWARD -o ip_vti1 -c 0 0 -j ACCEPT
-A OUTPUT -c 381965 35284758 -j NFLOG --nflog-group 10
[root@arch-linux ~]# lfilter
Chain INPUT (policy ACCEPT 413K packets, 29M bytes)
num pkts bytes target prot opt in out source destination
1 538K 41M NFLOG all -- any any anywhere anywhere nflog-group 13
Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num pkts bytes target prot opt in out source destination
1 0 0 ACCEPT all -- ip_vti1 any anywhere anywhere
2 0 0 ACCEPT all -- any ip_vti1 anywhere anywhere
Chain OUTPUT (policy ACCEPT 215K packets, 11M bytes)
num pkts bytes target prot opt in out source destination
1 382K 35M NFLOG all -- any any anywhere anywhere nflog-group 10
We can now use tcpdump to capture packets from the interface nflog:10
and nflog:13
.
tcpdump -vv -s 0 -n -i nflog:10 -w capture-nflog10-filter-OUTPUT.pcap
To simplify the capture process, I have created a simple script to run captures over all the NFLOG hooks installed added to iptables.
#!/bin/sh
# USAGE Example
# script.sh 10
# The first argument passed is the number of seconds to run the capture.
# Default is 30 seconds.
NFLOG_CLEAR_ALL='echo "" > ~/capture-nflog10-filter-OUTPUT.pcap ; echo "" > ~/capture-nflog11-raw-PREROUTING.pcap ; echo "" > ~/capture-nflog12-raw-OUTPUT.pcap ; echo "" > ~/capture-nflog13-filter-INPUT.pcap ; echo "" > ~/capture-nflog5-mangle-PREROUTING.pcap ; echo "" > ~/capture-nflog6-mangle-INPUT.pcap ; echo "" > ~/capture-nflog7-mangle-OUTPUT.pcap ; echo "" > ~/capture-nflog8-mangle-POSTROUTING.pcap ; echo "" > ~/capture-ip_vti1.pcap'
# Aliases
#NFLOG10='tcpdump -vv -s 0 -n -i nflog:10 -w ~/capture-nflog10-filter-OUTPUT.pcap'
#NFLOG11='tcpdump -vv -s 0 -n -i nflog:11 -w ~/capture-nflog11-raw-PREROUTING.pcap'
#NFLOG12='tcpdump -vv -s 0 -n -i nflog:12 -w ~/capture-nflog12-raw-OUTPUT.pcap'
#NFLOG13='tcpdump -vv -s 0 -n -i nflog:13 -w ~/capture-nflog13-filter-INPUT.pcap'
#NFLOG5='tcpdump -vv -s 0 -n -i nflog:5 -w ~/capture-nflog5-mangle-PREROUTING.pcap'
#NFLOG6='tcpdump -vv -s 0 -n -i nflog:6 -w ~/capture-nflog6-mangle-INPUT.pcap'
#NFLOG7='tcpdump -vv -s 0 -n -i nflog:7 -w ~/capture-nflog7-mangle-OUTPUT.pcap'
#NFLOG8='tcpdump -vv -s 0 -n -i nflog:8 -w ~/capture-nflog8-mangle-POSTROUTING.pcap'
#NFVTI1='tcpdump -vv -s 0 -n -i ip_vti1 -w ~/capture-ip_vti1.pcap'
# Set Session Name
SESSION="nflog"
CAPTUREPOINTS="nfvti1 nflog5 nflog6 nflog7 nflog8 nflog10 nflog11 nflog12 nflog13"
# Check if the session passed as argument exists.
# return: false(0) | true(1)
function SESSIONEXISTS {
local SESSIONEXISTS=$(tmux list-sessions 2>/dev/null | grep $1)
if [ "$SESSIONEXISTS" = "" ]
then
echo "0"
else
echo "1"
fi
}
# Destroy the nflog session if it exists.
if [ $(SESSIONEXISTS $SESSION) -eq 1 ]
then
tmux kill-session -t $SESSION
echo "Session ${SESSION} destroied."
echo
fi
# Clear all the capture files.
bash -c $NFLOG_CLEAR_ALL
echo "All capture files were cleared."
echo
# Create the capture windows
for LOGPOINT in $CAPTUREPOINTS; do
# Create a new session and name the first window with the first capture point.
tmux new-session -s nflog -n $LOGPOINT -d 2>/dev/null
# if the session exists.
if [ $? -ne 0 ]
then
# Create onyl a new window with the capture point name.
tmux new-window -n $LOGPOINT -d
fi
# if a session or window was created succesfully.
if [ $? -eq 0 ]
then
echo "Starting the capture for ${LOGPOINT} ..."
tmux send-keys -t $SESSION:$LOGPOINT "${LOGPOINT}" Enter
fi
done
echo
# Capture countdown
SECS=$1
# if a time was not passed it defaults to 30 seconds.
if [ "$SECS" = "" ]
then
SECS=30
fi
while [ $SECS -ne 0 ]; do
echo -ne "Capturing iptables chains for $SECS\033[0K\r"
sleep 1
: $((SECS--))
done
echo
echo
##################
# Stopping the captures
for LOGPOINT in $CAPTUREPOINTS; do
# Sending an interrupt to the tmux session.
tmux send-keys -t $SESSION:$LOGPOINT C-c
done
echo "All captures have been stopped ..."
echo
tmux kill-session -t $SESSION
echo "The session ${SESSION} was destroied."
echo
Make sure to have tmux
installed in your Linux machine before running it.
In a few words, the script loops through a list of nflog entry points and creates a tmux windows for each, runs the capture for a number of seconds and destroys everything after completion.