#!/bin/sh # # capture-sample.sh, Copyright © 2011 Matteo Cypriani # ######################################################################## # This program is licensed under the terms of the Expat license. # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ######################################################################## # # Captures a few packets on a Wi-Fi interface, using Tcpdump, and # writes them to a Pcap file along with some information about the # system. A tarball containing all these files is finally created. #set -x set -e ## Parameters (tune them if you want) ## # Number of packet to capture: NB_PKT=10 # Maximal time of a capture on a given channel: TIMEOUT=15 # Temporary directory: TMP=/tmp # Name of the capture file: FILE=capture.pcap # First channel to scan: CHANNEL=1 ## Functions ## # Displays the message in argument on the error output and exits error() { printf '%s\n' "$1" >&2 clean exit 1 } # Deletes the temporary files clean() { rm -fr "$DESTDIR" } # Verifies the presence of the needed programs check_dependencies() { command -v tcpdump >/dev/null \ || error "tcpdump is required to run this program!" if [ "$OS" = Linux ] ; then [ -x /sbin/iwconfig ] \ || error "iwconfig is required to run this program on Linux!" fi } # Switches the capture interface to monitor mode, on the channel in # argument iface_set_channel() { echo "Setting interface $IFACE on channel $1..." case "$OS" in Linux) iface_down iwconfig "$IFACE" mode managed iface_up iwconfig "$IFACE" channel "$1" ;; NetBSD | OpenBSD) iface_down ifconfig "$IFACE" media autoselect chan "$1" iface_up ;; *) error "Your OS is not supported." ;; esac \ || error "Cannot set the channel!" echo "Channel set." iface_monitor } # Switches the capture interface to monitor mode iface_monitor() { iface_down printf 'Switching interface %s to monitor mode... ' "$IFACE" case "$OS" in Linux) iwconfig "$IFACE" mode monitor ;; NetBSD | OpenBSD) ifconfig "$IFACE" media autoselect mediaopt monitor ;; *) error "Your OS is not supported." ;; esac \ || error "Cannot switch the interface to monitor mode!" echo "OK." iface_up } # Shuts down the capture interface iface_down() { printf 'Shuting down interface %s... ' "$IFACE" ifconfig "$IFACE" down \ || error "Cannot shut down the interface!" echo "OK." } # Turns on the capture interface iface_up() { printf 'Turning up interface %s... ' "$IFACE" ifconfig "$IFACE" up \ || error "Cannot turn the interface up!" echo "OK." } # Invokes tcpdump and displays the number of packets captured invoke_tcpdump() { NCAP=$(tcpdump -i "$IFACE" -c "$NB_PKT" -w "$FILE" 2>&1 \ | sed -nr 's/([[:digit:]]+) packets received by filter$/\1/p') [ -z "$NCAP" ] \ && error "Error parsing the tcpdump messages! (NCAP=\"$NCAP\")" echo "$NCAP" } # Waits for a number of seconds, then kills any tcpdump process wait_tcpdump() { sleep "$1" echo "$1 seconds passed, killing all tcpdump processes..." pkill tcpdump } # Gets some information about the running system gather_system_information() { printf "Gathering system information... " # Kernel & other information: uname -a >"$DESTDIR"/uname-a # Wi-Fi interface information: ifconfig "$IFACE" >"$DESTDIR/ifconfig_$IFACE" [ "$OS" = Linux ] \ && iwconfig "$IFACE" >"$DESTDIR/iwconfig_$IFACE" # PCI devices: command -v lspci >/dev/null \ && lspci >"$DESTDIR"/lspci \ || echo "lspci not available! Please install pciutils. " # USB devices: gather_usb_devices # Loaded kernel modules: gather_kernel_modules echo "OK." } # Gets information about the plugged usb devices gather_usb_devices() { case "$OS" in Linux) command -v lsusb >/dev/null \ && lsusb >"$DESTDIR"/lsusb \ || echo "lsusb not available! Please install usbutils. " ;; NetBSD | OpenBSD | DragonFly) command -v usbstats >/dev/null \ && usbstats >"$DESTDIR"/usbstats \ || echo "usbstats not available! Please install usbutil. " ;; esac } # Gets information about the loaded kernel modules gather_kernel_modules() { case "$OS" in Linux) lsmod >"$DESTDIR"/lsmod ;; NetBSD | OpenBSD) modstat >"$DESTDIR"/modstat ;; DragonFly) kldstat >"$DESTDIR"/kldstat ;; esac } # Compresses the destination directory to a tarball create_archive() { TARBALL="${DESTDIR}.tar.gz" DIR=$(basename "$DESTDIR") tar -C "$TMP" -czf "$TARBALL" "$DIR" echo "Archive \"$TARBALL\" created." } ## Main program ## [ $# -eq 1 ] \ || error "Usage: $0 " # Interface to capture from: IFACE=$1 # Machine information: OS=$(uname) OS_RELEASE=$(uname -r) HOSTNAME=$(uname -n) # Current date: DATE=$(date +%FT%H%M%S) # Temporary destination directory: DESTDIR=$(mktemp -d \ "$TMP/capture_${OS}-${OS_RELEASE}_${IFACE}_${HOSTNAME}_${DATE}_XXX") # Update capture file with full path: FILE="$DESTDIR/$FILE" check_dependencies echo "Trying to capture $NB_PKT packets..." CAPTURED=0 while [ "$CAPTURED" -eq 0 ] && [ "$CHANNEL" -le 14 ] ; do echo iface_set_channel "$CHANNEL" wait_tcpdump "$TIMEOUT" & CAPTURED=$(invoke_tcpdump) [ "$CAPTURED" -eq 0 ] \ && echo "No packet captured on channel $CHANNEL." \ || echo "$CAPTURED packets captured on channel $CHANNEL." CHANNEL=$((CHANNEL + 1)) done echo [ "$CAPTURED" -gt 0 ] \ || error "Failed to capture any packet!" echo "Capture file \"$FILE\" created." gather_system_information create_archive clean printf '\nYou can now shut down the interface %s if you would like:\n' "$IFACE" printf '\tifconfig %s down\n' "$IFACE"