Skip to content

Instantly share code, notes, and snippets.

@lunarthegrey
Last active February 14, 2025 19:44
Show Gist options
  • Select an option

  • Save lunarthegrey/085b509418ca3af311d71e8cc96d065c to your computer and use it in GitHub Desktop.

Select an option

Save lunarthegrey/085b509418ca3af311d71e8cc96d065c to your computer and use it in GitHub Desktop.
multi-tcpdump.sh

Script:

#!/bin/bash
#
# multi-tcpdump.sh
#
# Usage:
#   ./multi-tcpdump.sh --hosts "host1 host2 ..." --filter "<tcpdump filter>"
#
# This script SSHs (as root) into each host provided in the --hosts argument and
# runs tcpdump with the specified filter.
#
# Features:
#  - Forces pseudo-terminal allocation with ssh's -tt option.
#  - Uses tcpdump's -l for line-buffered output.
#  - Each output line is prefixed with the originating host name.
#  - Both stdout and stderr are captured.
#  - When you press CTRL+C, the entire process group (all SSH/tcpdump sessions) is killed.
#

usage() {
    echo "Usage: $0 --hosts \"host1 host2 ...\" --filter \"<tcpdump filter>\""
    exit 1
}

# Set up a trap that kills the entire process group when CTRL+C is pressed.
# The 'kill -- -$$' sends the signal to all processes in the current process group.
trap 'echo; echo "CTRL+C pressed. Terminating all sessions..."; kill -- -$$; exit 1' SIGINT

# Ensure that at least 4 arguments (2 options with values) are provided.
if [ "$#" -lt 4 ]; then
    usage
fi

# Parse command-line arguments.
while [[ "$#" -gt 0 ]]; do
    case "$1" in
        --hosts)
            if [ -n "$2" ]; then
                IFS=' ' read -r -a HOSTS <<< "$2"
                shift 2
            else
                echo "Error: --hosts requires a non-empty value."
                usage
            fi
            ;;
        --filter)
            if [ -n "$2" ]; then
                FILTER="$2"
                shift 2
            else
                echo "Error: --filter requires a non-empty value."
                usage
            fi
            ;;
        *)
            echo "Unknown parameter: $1"
            usage
            ;;
    esac
done

# Function to run tcpdump on a given host.
run_tcpdump() {
    local host="$1"
    ssh -tt root@"$host" "tcpdump -n -i any -l '$FILTER'" 2>&1 | \
        awk -v h="[$host]" '{ print h, $0; fflush(); }'
}

# Start a tcpdump session on each host in the background.
for host in "${HOSTS[@]}"; do
    echo "Starting tcpdump on $host with filter:"
    echo "  $FILTER"
    run_tcpdump "$host" &
done

# Wait for all background processes.
wait

Example command:

./multi-tcpdump.sh \
  --hosts "host1 host2" \
  --filter "host 1.1.1.1"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment