From 29e5f1be54dd3206aeb5b7c22a9808d14a3c8b44 Mon Sep 17 00:00:00 2001 From: Siraaj Khandkar Date: Wed, 6 Oct 2021 15:09:42 -0400 Subject: [PATCH] Prototype arp-recon --- home/bin/arp-recon | 151 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100755 home/bin/arp-recon diff --git a/home/bin/arp-recon b/home/bin/arp-recon new file mode 100755 index 0000000..bee996d --- /dev/null +++ b/home/bin/arp-recon @@ -0,0 +1,151 @@ +#! /bin/bash + +set -e +#set -u # Error on unset var +set -o pipefail + +# commands: +# - log (to stdout or file): +# run arp-scan and convert output to our log format +# - options +# - interval +# - file +# - status (from stdin or file): +# read log and report +# - seen devices, sorted by last-seen +# - ip changes? +# - options +# - file +# +# TODO +# - [ ] Gather more info on each device. How? nmap? +# ... +# + +_debug='' + +_log() { + local -r level="$1"; shift + local -r fmt="$1\n"; shift + local -r args="$*" + + printf '%s [%s] ' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" >&2 + printf "$fmt" $args >&2 +} + +error() { + _log 'error' "$@" +} + +debug() { + if [[ -n "$_debug" ]]; then + _log 'debug' "$@" + fi +} + +log() { + local -r interval="$1" + local -r log_file="$2" + + while :; do + debug '(>) scan' + sudo arp-scan --localnet; + debug '(.) scan' + sleep "$interval"; + done \ + | stdbuf -o L awk ' + /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ { + ip = $1 + mac = $2 + print mac, ip + }' \ + | ts '%.s' \ + >> "$log_file" +} + +status() { + local -r log_file="$1" + + ( + echo 'mac ip last first freq dist' + echo '--- -- ---- ----- ---- ----' + sort -n -k 1 "$log_file" \ + | awk -v now="$(date '+%s')" \ + ' + { + ts = $1 + mac = $2 + ip = $3 + + freq[mac, ip]++ + if (!seen_last[mac, ip] || ts > seen_last[mac, ip] ) seen_last[mac, ip] = ts + if (!seen_first[mac, ip] || ts < seen_first[mac, ip]) seen_first[mac, ip] = ts + } + + END { + for (key in freq) { + split(key, macip, SUBSEP) + mac = macip[1] + ip = macip[2] + last = now - seen_last[mac, ip] + first = now - seen_first[mac, ip] + dist = 100 * (freq[mac, ip] / NR) + print \ + mac, \ + ip, \ + sprintf("%d", last), \ + sprintf("%d", first), \ + freq[mac, ip], \ + sprintf("%d", dist) + } + } + ' \ + | sort -n -k 3 \ + ) \ + | column -t +} + +main() { + local cmd + local interval + local log_file + + case "$1" in + '-d') + _debug='yes' + shift + ;; + esac + cmd="$1" + case "$cmd" in + 'log') + interval=60 + log_file='/dev/stdout' + + if [[ -n "$2" ]]; then + interval="$2" + if [[ -n "$3" ]]; then + log_file="$3" + fi + fi + debug '(>) log | interval:"%s" log_file:"%s"' "$interval" "$log_file" + log "$interval" "$log_file" + debug '(.) log | interval:"%s" log_file:"%s"' "$interval" "$log_file" + ;; + 'status') + log_file='/dev/stdin' + if [[ -n "$2" ]]; then + log_file="$2" + fi + debug '(>) status | log_file:"%s"' "$log_file" + status "$log_file" + debug '(.) status | log_file:"%s"' "$log_file" + ;; + *) + error 'Unknown command: "%s"' "$cmd" + exit 1 + ;; + esac +} + +main "$@" -- 2.20.1