216 lines
6.5 KiB
Bash
Executable file
216 lines
6.5 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
set -euo pipefail
|
|
IFS=$'\n\t'
|
|
|
|
source settings.env
|
|
|
|
FAILURE_LOG="${TEST_FILE%.csv}-failures.log"
|
|
|
|
# Check if email recipient is set
|
|
if [ -z "$RECIPIENT" ]; then
|
|
echo "[!] Please set the RECIPIENT variable in settings.env."
|
|
exit 1
|
|
fi
|
|
|
|
sudo -v
|
|
|
|
while true; do sudo -n true; sleep 60; done 2>/dev/null &
|
|
SUDO_KEEPALIVE_PID=$!
|
|
|
|
echo "Starting kismet..."
|
|
|
|
sudo systemctl start kismet
|
|
|
|
echo "Saturating the capture..."
|
|
|
|
sleep $LEAD_TIME
|
|
|
|
# Function to get current TX failed count
|
|
get_tx_failed() {
|
|
iw dev $INTERFACE station dump | awk '/tx failed/ {print $3}'
|
|
}
|
|
|
|
freq_to_channel() {
|
|
local freq=$1
|
|
local channel=0
|
|
|
|
if [ "$freq" -ge 2412 ] && [ "$freq" -le 2472 ]; then
|
|
channel=$(( (freq - 2407) / 5 ))
|
|
elif [ "$freq" -eq 2484 ]; then
|
|
channel=14
|
|
elif [ "$freq" -ge 5180 ] && [ "$freq" -le 5825 ]; then
|
|
channel=$(( (freq - 5000) / 5 ))
|
|
else
|
|
channel="Unknown"
|
|
fi
|
|
|
|
echo "$channel"
|
|
}
|
|
|
|
# Start test email
|
|
echo -e "Subject: Test ${BOOT_ID} Started\n\nThis is to inform you that the tests have commenced for test ${BOOT_ID}." | msmtp $RECIPIENT
|
|
|
|
COUNTER=0
|
|
FAILED_START=$(get_tx_failed)
|
|
|
|
# Create CSV header if needed
|
|
if [ ! -f "$TEST_FILE" ]; then
|
|
echo "StartTimestamp,EndTimestamp,Link,Level,Noise,BSSID,TX Bitrate,RX Bitrate,$(speedtest --csv-header),TX Failures,Channel,Frequency,Packet Loss,Jitter,LocalTCPUp,LocalTCPDown,LocalUDPUp,LocalUDPDown,RemoteTCPUp,RemoteTCPDown,RemoteUDPUp,RemoteUDPDown" > "$TEST_FILE"
|
|
fi
|
|
|
|
while [ "$COUNTER" -lt "$NUM_TESTS" ]; do
|
|
COUNTER=$((COUNTER + 1))
|
|
echo "Executing test $COUNTER of $NUM_TESTS..."
|
|
|
|
|
|
for ((i=1; i<=NUM_SAMPLES; i++)); do
|
|
echo " Gathering sample $i of $NUM_SAMPLES..."
|
|
START_TIME=$(date -Iseconds)
|
|
|
|
# Wireless stats
|
|
link_level_noise=$(awk 'NR==3 {gsub(/\./, "", $3); gsub(/\./, "", $4); gsub(/\./, "", $5); print $3","$4","$5}' /proc/net/wireless)
|
|
bssid_and_bitrate=$(iw dev $INTERFACE link | awk '/Connected/ {bssid=$3} /tx bitrate/ {tx=$3} /rx bitrate/ {rx=$3} END {print bssid","tx","rx}')
|
|
|
|
speed_results=""
|
|
for ((retry=1; retry<=MAX_RETRIES; retry++)); do
|
|
echo " Attempting speed test (try $retry)..."
|
|
speed_results=$(speedtest --secure --csv 2>/dev/null)
|
|
|
|
if [[ -n "$speed_results" ]]; then
|
|
break
|
|
fi
|
|
|
|
echo " [!] Speedtest failed at $(date -Iseconds). Retrying in $RETRY_DELAY seconds..."
|
|
sleep $RETRY_DELAY
|
|
done
|
|
|
|
if [[ -z "$speed_results" ]]; then
|
|
TIMESTAMP=$(date -Iseconds)
|
|
echo " [!] Speedtest permanently failed at $TIMESTAMP. Skipping sample $i of test $COUNTER."
|
|
|
|
# Optionally log failure to a sidecar file for later nerd rage
|
|
echo "$TIMESTAMP,Test $COUNTER,Sample $i" >> "${TEST_FILE%.csv}-failures.log"
|
|
|
|
continue # Skip this sample
|
|
fi
|
|
|
|
|
|
# TX failure delta
|
|
FAILED_NOW=$(get_tx_failed)
|
|
FAILED_DELTA=$((FAILED_NOW - FAILED_START))
|
|
FAILED_START=$FAILED_NOW # Update for next sample
|
|
|
|
freq=$(iw dev $INTERFACE link | awk '/freq:/ {print $2}')
|
|
channel=$(freq_to_channel "$freq")
|
|
|
|
packet_loss=$(ping -c $PING_COUNT -q $PING_TARGET | grep -oP '\d+(?=% packet loss)')
|
|
jitter=$(ping -c $PING_COUNT $PING_TARGET | grep "time=" | awk '{print $(NF-1)}' | sed 's/time=//g' | awk '{sum+=$1; sumsq+=$1*$1} END {if (NR>1) print sqrt(sumsq/NR - (sum/NR)**2); else print 0}')
|
|
|
|
# iperf3 function
|
|
run_iperf() {
|
|
local target="$1"
|
|
local mode="$2"
|
|
local direction="$3"
|
|
local args=("-c" "$target" "-J" "-t" "10")
|
|
|
|
if [ "$mode" = "udp" ]; then
|
|
args+=("-u")
|
|
fi
|
|
|
|
if [ "$direction" = "down" ]; then
|
|
args+=("--reverse")
|
|
fi
|
|
|
|
iperf3 "${args[@]}" 2>/dev/null | jq -r '
|
|
if .error then "0" else
|
|
if .end then
|
|
if .end.sum_received then .end.sum_received.bits_per_second
|
|
elif .end.sum then .end.sum.bits_per_second
|
|
else "0" end
|
|
else "0" end
|
|
end' || echo "0"
|
|
}
|
|
|
|
echo " Running iperf3 tests..."
|
|
|
|
# Run them all. These are in bits per second, convert as needed later.
|
|
LocalTCPUp=$(run_iperf "$IPERF_LOCAL_TARGET" tcp up)
|
|
LocalTCPDown=$(run_iperf "$IPERF_LOCAL_TARGET" tcp down)
|
|
LocalUDPUp=$(run_iperf "$IPERF_LOCAL_TARGET" udp up)
|
|
LocalUDPDown=$(run_iperf "$IPERF_LOCAL_TARGET" udp down)
|
|
|
|
RemoteTCPUp=$(run_iperf "$IPERF_REMOTE_TARGET" tcp up)
|
|
RemoteTCPDown=$(run_iperf "$IPERF_REMOTE_TARGET" tcp down)
|
|
RemoteUDPUp=$(run_iperf "$IPERF_REMOTE_TARGET" udp up)
|
|
RemoteUDPDown=$(run_iperf "$IPERF_REMOTE_TARGET" udp down)
|
|
|
|
END_TIME=$(date -Iseconds)
|
|
|
|
# Log everything
|
|
echo "$START_TIME,$END_TIME,$link_level_noise,$bssid_and_bitrate,$speed_results,$FAILED_DELTA,$channel,$freq,$packet_loss,$jitter,$LocalTCPUp,$LocalTCPDown,$LocalUDPUp,$LocalUDPDown,$RemoteTCPUp,$RemoteTCPDown,$RemoteUDPUp,$RemoteUDPDown" >> "$TEST_FILE"
|
|
done
|
|
|
|
if [ "$COUNTER" -lt "$NUM_TESTS" ]; then
|
|
echo "Dozing off for $TIME_BETWEEN..."
|
|
sleep $TIME_BETWEEN
|
|
fi
|
|
done
|
|
|
|
echo "Stopping kismet..."
|
|
|
|
sudo systemctl stop kismet
|
|
|
|
# Let's enrich the data with passive metrics.
|
|
|
|
echo "Enriching the data..."
|
|
|
|
KISMET_LOG=$(find ~/kismet_logs -type f -name "*.pcapng" -printf "%T@ %p\n" | sort -n | tail -1 | cut -d' ' -f2-)
|
|
|
|
if [ -z "$KISMET_LOG" ] || [ ! -f "$KISMET_LOG" ]; then
|
|
echo "[!] Packet capture not found."
|
|
exit 1
|
|
fi
|
|
|
|
python3 "$SCRIPT_DIRECTORY/enrich.py" --csv "$TEST_FILE" --pcapng "$KISMET_LOG" --output "$ENRICHED_FILE"
|
|
|
|
# Final email with attachment(s)
|
|
EMAIL_BODY="The test with UID ${BOOT_ID} is complete. Please collect the probe. Data is attached."
|
|
EMAIL_SUBJECT="Test ${BOOT_ID} Complete"
|
|
|
|
# Construct list of attachments safely
|
|
ATTACHMENTS=()
|
|
if [ -f "$ENRICHED_FILE" ]; then
|
|
ATTACHMENTS+=("$ENRICHED_FILE")
|
|
fi
|
|
|
|
if [ -f "$FAILURE_LOG" ]; then
|
|
ATTACHMENTS+=("$FAILURE_LOG")
|
|
echo "[+] Attaching failure log: $FAILURE_LOG"
|
|
fi
|
|
|
|
if [ -f "$SSID_METRICS_FILE" ]; then
|
|
ATTACHMENTS+=("$SSID_METRICS_FILE")
|
|
echo "[+] Attaching SSID metrics file: $SSID_METRICS_FILE"
|
|
fi
|
|
|
|
# Check if there's at least one file to send
|
|
if [ ${#ATTACHMENTS[@]} -eq 0 ]; then
|
|
echo "[!] No files to attach. Email not sent."
|
|
else
|
|
# Print attachments for debugging
|
|
for file in "${ATTACHMENTS[@]}"; do
|
|
echo "[DEBUG] Attaching: '$file'"
|
|
done
|
|
|
|
# Safely quote and attach
|
|
ATTACHMENT_FLAGS=()
|
|
for file in "${ATTACHMENTS[@]}"; do
|
|
ATTACHMENT_FLAGS+=("-a" "$file")
|
|
done
|
|
|
|
echo "$EMAIL_BODY" | mutt -s "$EMAIL_SUBJECT" "${ATTACHMENT_FLAGS[@]}" -- "$RECIPIENT"
|
|
fi
|
|
echo "[+] Email sent to $RECIPIENT with attachments: ${ATTACHMENTS[*]}"
|
|
|
|
sudo kill $SUDO_KEEPALIVE_PID
|