ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/wvsniff/wvsniff
Revision: 1.7
Committed: Fri Apr 26 23:42:09 2002 UTC (22 years, 1 month ago) by root
Branch: MAIN
Changes since 1.6: +9 -3 lines
Log Message:
*** empty log message ***

File Contents

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