Prototype arp-recon
[khome.git] / home / bin / arp-recon
1 #! /bin/bash
2
3 set -e
4 #set -u # Error on unset var
5 set -o pipefail
6
7 # commands:
8 # - log (to stdout or file):
9 # run arp-scan and convert output to our log format
10 # - options
11 # - interval
12 # - file
13 # - status (from stdin or file):
14 # read log and report
15 # - seen devices, sorted by last-seen
16 # - ip changes?
17 # - options
18 # - file
19 #
20 # TODO
21 # - [ ] Gather more info on each device. How? nmap?
22 # ...
23 #
24
25 _debug=''
26
27 _log() {
28 local -r level="$1"; shift
29 local -r fmt="$1\n"; shift
30 local -r args="$*"
31
32 printf '%s [%s] ' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" >&2
33 printf "$fmt" $args >&2
34 }
35
36 error() {
37 _log 'error' "$@"
38 }
39
40 debug() {
41 if [[ -n "$_debug" ]]; then
42 _log 'debug' "$@"
43 fi
44 }
45
46 log() {
47 local -r interval="$1"
48 local -r log_file="$2"
49
50 while :; do
51 debug '(>) scan'
52 sudo arp-scan --localnet;
53 debug '(.) scan'
54 sleep "$interval";
55 done \
56 | stdbuf -o L awk '
57 /^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/ {
58 ip = $1
59 mac = $2
60 print mac, ip
61 }' \
62 | ts '%.s' \
63 >> "$log_file"
64 }
65
66 status() {
67 local -r log_file="$1"
68
69 (
70 echo 'mac ip last first freq dist'
71 echo '--- -- ---- ----- ---- ----'
72 sort -n -k 1 "$log_file" \
73 | awk -v now="$(date '+%s')" \
74 '
75 {
76 ts = $1
77 mac = $2
78 ip = $3
79
80 freq[mac, ip]++
81 if (!seen_last[mac, ip] || ts > seen_last[mac, ip] ) seen_last[mac, ip] = ts
82 if (!seen_first[mac, ip] || ts < seen_first[mac, ip]) seen_first[mac, ip] = ts
83 }
84
85 END {
86 for (key in freq) {
87 split(key, macip, SUBSEP)
88 mac = macip[1]
89 ip = macip[2]
90 last = now - seen_last[mac, ip]
91 first = now - seen_first[mac, ip]
92 dist = 100 * (freq[mac, ip] / NR)
93 print \
94 mac, \
95 ip, \
96 sprintf("%d", last), \
97 sprintf("%d", first), \
98 freq[mac, ip], \
99 sprintf("%d", dist)
100 }
101 }
102 ' \
103 | sort -n -k 3 \
104 ) \
105 | column -t
106 }
107
108 main() {
109 local cmd
110 local interval
111 local log_file
112
113 case "$1" in
114 '-d')
115 _debug='yes'
116 shift
117 ;;
118 esac
119 cmd="$1"
120 case "$cmd" in
121 'log')
122 interval=60
123 log_file='/dev/stdout'
124
125 if [[ -n "$2" ]]; then
126 interval="$2"
127 if [[ -n "$3" ]]; then
128 log_file="$3"
129 fi
130 fi
131 debug '(>) log | interval:"%s" log_file:"%s"' "$interval" "$log_file"
132 log "$interval" "$log_file"
133 debug '(.) log | interval:"%s" log_file:"%s"' "$interval" "$log_file"
134 ;;
135 'status')
136 log_file='/dev/stdin'
137 if [[ -n "$2" ]]; then
138 log_file="$2"
139 fi
140 debug '(>) status | log_file:"%s"' "$log_file"
141 status "$log_file"
142 debug '(.) status | log_file:"%s"' "$log_file"
143 ;;
144 *)
145 error 'Unknown command: "%s"' "$cmd"
146 exit 1
147 ;;
148 esac
149 }
150
151 main "$@"
This page took 0.090834 seconds and 5 git commands to generate.