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.

Resources

Conditions in bash scripting (if statements)
This tutorial aims to help the reader understanding conditions in bash, and provides a comprehensive list of the possibilities.
Scripting A Tmux Work-space Start-up -- λ ryan. himmelwright. net
tmux(1) - Linux manual page