fiwi_monitor/test_monitor_tshark.sh

223 lines
7.2 KiB
Bash
Executable File

#!/bin/bash
# Test script to verify monitor mode works with tshark
# Usage: ./test_monitor_tshark.sh [interface] [channel] [duration_seconds] [--keep-pcap]
# Or: KEEP_PCAP=1 sudo -E ./test_monitor_tshark.sh [interface] [channel] [duration_seconds]
set -e
# Parse arguments
KEEP_PCAP_FLAG=""
ARGS=()
for arg in "$@"; do
if [ "$arg" = "--keep-pcap" ] || [ "$arg" = "-k" ]; then
KEEP_PCAP_FLAG="1"
else
ARGS+=("$arg")
fi
done
INTERFACE="${ARGS[0]:-wlan0}"
CHANNEL="${ARGS[1]:-36}"
DURATION="${ARGS[2]:-10}" # Default 10 seconds, minimum 1 second
# Check for KEEP_PCAP environment variable or flag
if [ -n "$KEEP_PCAP_FLAG" ]; then
KEEP_PCAP="1"
elif [ -z "${KEEP_PCAP:-}" ]; then
KEEP_PCAP=""
fi
# Ensure minimum 1 second
if [ "$DURATION" -lt 1 ]; then
DURATION=1
fi
echo "=== Testing Monitor Mode with tshark ==="
echo "Interface: $INTERFACE"
echo "Channel: $CHANNEL"
echo "Duration: $DURATION seconds"
echo ""
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo "Please run as root (use sudo)"
exit 1
fi
# Check if tshark is installed
if ! command -v tshark &> /dev/null; then
echo "tshark is not installed. Installing..."
if command -v apt-get &> /dev/null; then
sudo apt-get update
sudo apt-get install -y tshark
elif command -v dnf &> /dev/null; then
sudo dnf install -y wireshark-cli
else
echo "Please install tshark manually"
exit 1
fi
fi
# Unmanage from NetworkManager
if command -v nmcli &> /dev/null; then
echo "Unmanaging interface from NetworkManager..."
nmcli device set "$INTERFACE" managed no 2>/dev/null || true
fi
# Unblock WiFi
rfkill unblock wifi 2>/dev/null || true
# Bring down interface
echo "Bringing down interface..."
ip link set "$INTERFACE" down 2>/dev/null || true
sleep 0.5
# Set monitor mode
echo "Setting monitor mode..."
if ! iw dev "$INTERFACE" set type monitor; then
echo "Error: Failed to set monitor mode"
exit 1
fi
sleep 0.5
# Bring up interface
echo "Bringing up interface..."
ip link set "$INTERFACE" up || echo "Warning: Failed to bring interface up"
sleep 0.5
# Set channel
echo "Setting channel to $CHANNEL..."
iw dev "$INTERFACE" set channel "$CHANNEL" || echo "Warning: Failed to set channel"
# Verify monitor mode
echo ""
echo "Verifying monitor mode..."
iw dev "$INTERFACE" info | grep -E "(type|channel)" || echo "Could not verify"
# Check DLT with tshark (capture for 1 second)
echo ""
echo "Checking Data Link Type (1 second test capture)..."
echo "(This may take up to 2 seconds if no packets are present)"
# Use timeout with -c to limit packets and avoid hanging
# Capture both stdout and stderr
# Fields: frame.number, wlan.ra (Receiver Address), wlan.ta (Transmitter Address), radiotap.present
# Note: wlan.ra and wlan.ta may not be available for all frame types, but are correct for monitor mode
TEST_OUTPUT=$(timeout 2 tshark -i "$INTERFACE" -c 100 -T fields \
-e frame.number \
-e wlan.ra \
-e wlan.ta \
-e radiotap.present \
2>&1 || true)
TEST_EXIT_CODE=${PIPESTATUS[0]}
# Show any warnings/errors from tshark (but not packet data)
echo "$TEST_OUTPUT" | grep -E "(Running as|tshark:|Warning|Error|Capturing)" || true
# Count packets (lines starting with a number, excluding error messages)
PACKET_LINES=$(echo "$TEST_OUTPUT" | grep -E '^[0-9]+' || true)
PACKET_COUNT=$(echo "$PACKET_LINES" | wc -l || echo "0")
# Count lines with radiotap.present (4th field) set to 1
PLCP_COUNT=$(echo "$PACKET_LINES" | awk -F'\t' 'NF >= 4 && $1 != "" && $4 != "" && $4 != "0" && $4 != "-" {count++} END {print count+0}' || echo "0")
# Show sample output with better formatting
if [ "$PACKET_COUNT" -gt 0 ]; then
echo "Sample packets:"
echo "$PACKET_LINES" | head -5 | awk -F'\t' '{
ra = ($2 != "" && $2 != "-") ? $2 : "N/A"
ta = ($3 != "" && $3 != "-") ? $3 : "N/A"
radiotap = ($4 == "1" || $4 == "1.0") ? "yes" : "no"
printf " Frame %s: RA=%s, TA=%s, PLCP=%s\n", $1, ra, ta, radiotap
}'
fi
echo ""
echo "Test capture results:"
echo " Packets captured: $PACKET_COUNT"
echo " PLCP headers: $PLCP_COUNT"
if [ "$PLCP_COUNT" -eq 0 ] && [ "$PACKET_COUNT" -gt 0 ]; then
echo " Note: Packets captured but no radiotap headers (may be using DLT_IEEE802_11 instead of DLT_IEEE802_11_RADIO)"
fi
echo ""
echo "=== Starting tshark capture ($DURATION seconds) ==="
echo "Press Ctrl+C to stop early"
echo ""
# Capture for specified duration and count packets
echo "Capturing packets for $DURATION seconds..."
# Use a temporary pcap file to avoid field extraction errors during capture
# Capture to file first, then parse it - this prevents tshark from exiting early
TEMP_PCAP=$(mktemp /tmp/tshark_capture_XXXXXX.pcap)
echo "Capturing to temporary file: $TEMP_PCAP"
set +e # Temporarily disable exit on error
# Capture to pcap file - this won't error on missing fields
# Use -b filesize:100000 to rotate files if needed, but we'll only use the first
timeout "$DURATION" tshark -q -i "$INTERFACE" -n -w "$TEMP_PCAP" 2>/dev/null
CAPTURE_EXIT_CODE=$?
set -e # Re-enable exit on error
# Force sync to ensure file is written
sync
# Exit code 124 means timeout occurred (expected), 0 means command completed normally
if [ "$CAPTURE_EXIT_CODE" -ne 0 ] && [ "$CAPTURE_EXIT_CODE" -ne 124 ]; then
echo "Warning: tshark capture exited with code $CAPTURE_EXIT_CODE"
fi
# Check if pcap file exists and get its size
if [ -f "$TEMP_PCAP" ]; then
PCAP_SIZE=$(stat -c%s "$TEMP_PCAP" 2>/dev/null || stat -f%z "$TEMP_PCAP" 2>/dev/null || echo "0")
echo "Pcap file size: $PCAP_SIZE bytes"
# Count packets in raw pcap file using capinfos or tshark
if command -v capinfos &> /dev/null; then
RAW_PACKET_COUNT=$(capinfos -c "$TEMP_PCAP" 2>/dev/null | grep "^Number of packets:" | awk '{print $4}' || echo "0")
echo "Raw packets in pcap file: $RAW_PACKET_COUNT"
else
# Fallback: use tshark to count packets
RAW_PACKET_COUNT=$(tshark -q -r "$TEMP_PCAP" -n -T fields -e frame.number 2>/dev/null | tail -1 || echo "0")
if [ "$RAW_PACKET_COUNT" != "0" ] && [ -n "$RAW_PACKET_COUNT" ]; then
echo "Raw packets in pcap file: $RAW_PACKET_COUNT"
else
echo "Raw packets in pcap file: (could not determine)"
fi
fi
else
echo "ERROR: Pcap file was not created: $TEMP_PCAP"
exit 1
fi
# Now parse the pcap file using Python script (more robust than bash parsing)
# The Python script handles missing fields gracefully and provides detailed statistics
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PARSE_SCRIPT="${SCRIPT_DIR}/parse_tshark_pcap.py"
# Check if Python script exists
if [ ! -f "$PARSE_SCRIPT" ]; then
echo "Error: Python parser script not found: $PARSE_SCRIPT"
echo " Falling back to basic tshark output"
exit 1
fi
# Clean up temp file (unless KEEP_PCAP is set)
if [ -z "$KEEP_PCAP" ]; then
echo "Cleaning up temporary pcap file: $TEMP_PCAP"
rm -f "$TEMP_PCAP"
else
echo "Keeping temporary pcap file: $TEMP_PCAP"
echo " (Use: tshark -r $TEMP_PCAP to analyze)"
fi
# Force output flush
sync
# Parse pcap file using Python script (more robust than bash/awk parsing)
echo ""
python3 "$PARSE_SCRIPT" "$TEMP_PCAP" "$DURATION" "$RAW_PACKET_COUNT"