ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/wvsniff/wvsniff
Revision: 1.8
Committed: Sun Apr 28 02:49:33 2002 UTC (22 years, 1 month ago) by root
Branch: MAIN
Changes since 1.7: +22 -18 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #!/usr/bin/perl
2
3 use Event;
4 use Time::HiRes qw(time);
5 use Curses;
6 use Socket;
7 use Storable;
8 use GPS;
9
10 my $GPS = eval { new GPS };
11
12 $DEV = "eth1";
13 $RAWDEV = "wifi0";
14 $PROC = "/proc/driver/aironet/$DEV";
15 $STOREFILE = "/tmp/wvsniff.dat";
16
17 $SIG{INT} =
18 $SIG{TERM} =
19 $SIG{HUP} = sub { exit };
20
21 sub config {
22 open my $config, ">$PROC/Config"
23 or die "$PROC/Config: $!";
24 print $config $_[0];
25 }
26
27 config "Mode: yna\n";
28 system "ifconfig", $DEV, "up";
29 system "ifconfig", $RAWDEV, "up";
30
31 my $initscr;
32 sub init_screen {
33 initscr;
34 $initscr = 1;
35 start_color;
36 cbreak; noecho;
37 immedok 0; nonl; raw; intrflush 0; keypad 1;
38 idlok 1; scrollok 0; leaveok 0;
39 }
40
41 sub end_win {
42 endwin if $initscr--;
43 }
44
45 init_screen;
46
47 sub signal_quality {
48 open my $stats, "<", "$PROC/Status"
49 or return 0;
50 sysread $stats, $buf, 1024;
51 $buf =~ /Signal Quality: (\d+)/ && $1;
52 }
53
54 my $refresh = Event->idle(nice => -5, parked => 1, min => 0.01, max => 1, repeat => 0, cb => sub {
55 @menu = ();
56 &$curmenu;
57
58 $menu_idx += @menu if $menu_idx < 0;
59 $menu_idx -= @menu if $menu_idx >= @menu;
60
61 erase;
62
63 my $data = $GPS ? $GPS->data : {};
64
65 move 0, 0;
66 addstr $frame++ . ": " . signal_quality . " " . localtime($data->{time}) . " $data->{lat} $data->{long} $data->{alt}m";
67
68 for my $idx (0 .. $#menu) {
69 move 2 + $idx, 0;
70 standout if $idx == $menu_idx;
71 addstr $menu[$idx][0];
72 standend if $idx == $menu_idx;
73 }
74
75 move 3 + scalar@menu, 0;
76 eval {
77 $menu[$menu_idx][1]->();
78 };
79
80 refresh;
81 });
82
83 Event->timer(after => 0, interval => 2, cb => sub { $refresh->start });
84
85 Event->io(fd => \*STDIN, poll => 'r', cb => sub {
86 my $ch = getch;
87 if ($ch eq "\x1b" or $ch eq "q") {
88 Event::unloop;
89 } elsif ($ch eq KEY_DOWN or $ch eq "j") {
90 $menu_idx++;
91 } elsif ($ch eq KEY_UP or $ch eq "k") {
92 $menu_idx--;
93 } else {
94 eval {
95 $menu[$menu_idx][2]->($ch);
96 };
97 }
98 $refresh->start;
99 });
100
101 -r $STOREFILE and
102 $db = Storable::retrieve $STOREFILE;
103
104 END {
105 $db->{version} = 0;
106 Storable::store $db, $STOREFILE;
107 end_win;
108 config "Mode: adhoc\n";
109 }
110
111 sub decode_tags {
112 my $pkt = shift;
113 my %tag;
114
115 while ($pkt) {
116 my ($id, $len) = unpack "C C", $pkt;
117 my $data = substr $pkt, 2, $len;
118 $pkt = substr $pkt, 2 + $len;
119
120 $id = ({
121 0 => SSID,
122 1 => rates,
123 2 => FH,
124 3 => DS,
125 4 => CF,
126 5 => TIM,
127 6 => IBSS,
128 16 => challenge,
129 })->{$id};
130 $tag{$id} = $data;
131 }
132
133 %tag;
134 }
135
136 sub PF_PACKET (){ 17 }
137 sub SOCK_RAW (){ 3 }
138 sub ETH_P_ALL (){ 0x0003 }
139 sub SIOCGIFINDEX (){ 0x000008933 }
140
141 sub open_pcap_socket {
142 socket my $cap, PF_PACKET, SOCK_RAW, (unpack "s", pack "n", ETH_P_ALL)
143 or die "unable to open packet socket: $!";
144
145 my $ifidx = pack "a16 I", $RAWDEV;
146 ioctl $cap, SIOCGIFINDEX, $ifidx
147 or die "can't get index of interface $RAWDEV: $!";
148 $ifidx = unpack "x16 I", $ifidx;
149
150 bind $cap, pack "S! S! I S! C C a8", PF_PACKET, (unpack "s", pack "n", ETH_P_ALL), $ifidx
151 or die "unable to bind to interface: $!";
152
153 $cap;
154 }
155
156 sub e2h($) {
157 join ":", map unpack("H*", $_), split //, $_[0];
158 }
159
160 sub add_menu {
161 my ($title, $display, $select) = @_;
162 push @menu, [$title, $display, $select];
163 }
164
165 $curmenu = \&menu_bss_list;
166
167 sub bss2string {
168 my $bss = shift;
169
170 my $s = "AGE(" . int(time - $bss->{ts}) . ") "
171 . "IP($bss->{ip}) "
172 . "ARP($bss->{arp}) ";
173 while (my ($k, $v) = each %{$bss->{ap}}) {
174 $s .= "(" . e2h($k) . " $v->{mode} '$v->{essid}') ";
175 }
176 $s;
177 }
178
179 sub show_map {
180 my ($map, $w, $h) = @_;
181
182 my $data = $GPS->data;
183
184 local $map->{"$data->{lat};$data->{long}"} = 0;
185
186 my @data = (("-" x $w) x $h);
187
188 my ($x1, $y1, $x2, $y2) = (1e6, 1e6, 1e-6, 1e-6);
189 my $level = 1;
190
191 while (my ($k, $v) = each %$map) {
192 my ($y, $x) = split /;/, $k;
193 $x1 = $x if $x1 > $x;
194 $x2 = $x if $x2 < $x;
195 $y1 = $y if $y1 > $y;
196 $y2 = $y if $y2 < $y;
197 $level = $v if $level < $v;
198 }
199
200 $x2 = ($w - 1) / (($x2 - $x1) || 1e-6);
201 $y2 = ($h - 1) / (($y2 - $y1) || 1e-6);
202
203 while (my ($k, $v) = each %$map) {
204 my ($y, $x) = split /;/, $k;
205
206 $y = ($y - $y1) * $y2;
207 $x = ($x - $x1) * $x2;
208
209 substr $data[$y], $x, 1, int($map->{$k} * 9 / $level);
210 }
211
212 for (@data) {
213 addstr $_ . "\n";
214 }
215 }
216
217 sub display_bss {
218 my $bss = shift;
219
220 addstr "TS: $bss->{ts}\n";
221 addstr "WEP/Weak packets received: $bss->{wep}/$bss->{weak}\n";
222 addstr "ARP/IP packets received: $bss->{arp}/$bss->{ip}\n";
223
224 addstr "\naccess points\n";
225
226 while (my ($k, $v) = each %{$bss->{ap}}) {
227 addstr " " . e2h($k) . "\n";
228 addstr " mode $v->{mode}; channel $v->{channel}; essid '$v->{essid}'; beacon frames $v->{beacon}\n";
229 }
230
231 addstr "\nstations\n";
232
233 while (my ($k, $v) = each %{$bss->{station}}) {
234 addstr " " . e2h($k);
235 while (my ($k, $v) = each %$v) {
236 addstr " " . (inet_ntoa $k) . "($v)";
237 }
238 addstr "\n";
239 }
240
241 if ($bss->{gps}) {
242 my ($x, $y); getyx $y, $x;
243 addstr "\nmap\n";
244 my $h = (&getmaxy - $y) - 3;
245 show_map $bss->{gps}, int($h*1.8), $h;
246 }
247 }
248
249 sub menu_bss_list {
250 my @menu;
251 for my $k (sort { int $db->{$b}{ts} <=> int $db->{$a}{ts} } keys %$db) {
252 my $v = $db->{$k};
253 add_menu e2h($k) . " " . bss2string($v),
254 sub { display_bss $v },
255 sub {
256 if ($_[0] eq KEY_LEFT or $_[0] eq "h") {
257 Event::unloop;
258 } elsif ($_[0] eq KEY_RIGHT or $_[0] eq "l") {
259 #$curmenu = sub { display_bss $k };
260 }
261 };
262 }
263 }
264
265 sub activity {
266 if ($GPS) {
267 my $data = $GPS->data;
268 $db->{$_[0]}{gps}{"$data->{lat};$data->{long}"} = signal_quality;
269 }
270 $db->{$_[0]}->{ts} = time;
271 $refresh->start;
272 }
273
274 sub reg_ip {
275 my ($bssid, $ip, $ether) = @_;
276 $db->{$bssid}{station}{$ether}{$ip}++;
277 activity $bssid;
278 }
279
280 {
281 my $cap = open_pcap_socket;
282 my $pkt;
283 open LOG, ">/tmp/log";#d#
284
285 Event->io(fd => $cap, poll => 'r', cb => sub {
286 sysread $$cap, $pkt, 120;
287
288 printf LOG "%s\n", unpack "H*", $pkt;
289
290 my ($fc1, $fc2, $sid, $a1, $a2, $a3, $sc, $pkt)
291 = unpack "C C n a6 a6 a6 S a*", $pkt;
292
293 my $a4;
294
295 if ($fc2 & 0x03 == 0x03) {
296 $a4 = substr $pkt, 0, 6;
297 $pkt = substr $pkt, 6;
298 }
299
300 if ($fc1 == 0x80 or $fc1 == 0x50) {
301 my ($ts1, $ts2, $bi, $cf, $pkt)
302 = unpack "L L S S a*", $pkt;
303
304 my %tag = decode_tags $pkt;
305
306 my $ap = $db->{$a3}{ap}{$a2} ||= {};
307 $ap->{mode} = ($cf & 3) == 1 ? "AP" : "adhoc";
308
309 # ESSID ' ' workaround for wep-nets(?)
310 $ap->{essid} = $tag{SSID} unless $ap->{essid} && $tag{SSID} eq " ";
311 $ap->{channel} = ord $tag{DS};
312 $ap->{beacon}++;
313
314 activity $a3;
315 } elsif ($fc1 == 0x08) {
316 my $bssid = ($a3, $a1, $a2, $a2)[$fc2 & 3];
317
318 if ($fc2 & 0x40) {
319 my ($iv1, $iv2, $iv3, $ivopt, $byte) = unpack "C C C C C", $pkt;
320 $db->{$bssid}{wep}++;
321 if ($iv1 > 2 and $iv1 < 14 and $iv2 == 255) {
322 $db->{$bssid}{weak}++;
323 }
324 } else {
325 my ($llc, $et, $pkt) = unpack "a6 n a*", $pkt;
326 if ($llc eq "\xaa\xaa\x03\x00\x00\x00"
327 or $llc eq "\xaa\xaa\x03\x00\x00\xf8") { # SNAP/UI/{ENCAP_ETHER,CISCO}
328 if ($et == 0x0800) {
329 my ($vhl, $tos, $len, $id, $off, $ttl, $prot, $sum, $src, $dst, $pkt)
330 = unpack "C C n n n C C n a4 a4 a*", $pkt;
331 if ($vhl & 0x40 == 0x40) {
332 $db->{$bssid}{ip}++;
333 reg_ip $bssid, $src, ($a2, $a2, $a3, $a4)[$fc2 & 3];
334 reg_ip $bssid, $dst, ($a1, $a3, $a1, $a3)[$fc2 & 3];
335 }
336 } elsif ($et == 0x0806) {
337 my ($hrd, $pro, $hln, $pln, $op, $src_hw, $src, $dst_hw, $dst)
338 = unpack "n n C C n a6 a4 a6 a4", $pkt;
339 if ($hrd == 1 and $hln == 6 and $pln == 4) {
340 reg_ip $bssid, $src, $src_hw;
341 reg_ip $bssid, $dst, $dst_hw if $op != 1;
342 $db->{$bssid}{arp}++;
343 }
344 }
345 } else {
346 0 &&
347 printf "?? %02x %02x %04x %04x: %s.%s \n", $fc1, $fc2, $sid, $sc, (unpack "H*", $llc), unpack "H*", $pkt;
348 }
349 }
350 } elsif ($fc1 != 0x40 and $fc1 != 0x10 and $fc1 != 0x00 and $fc1 != 0xb0) {
351 0 &&
352 printf "%02x %02x %04x %04x: %s \n", $fc1, $fc2, $sid, $sc, unpack "H*", $pkt;
353 }
354 });
355 }
356
357 Event::loop;
358
359