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