ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/wvsniff/wvsniff
Revision: 1.3
Committed: Fri Apr 26 21:52:55 2002 UTC (22 years, 1 month ago) by root
Branch: MAIN
Changes since 1.2: +3 -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.2 use GPS;
8    
9     my $GPS = eval { new GPS };
10 root 1.1
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     my $refresh = Event->idle(nice => -5, parked => 1, min => 0.01, max => 1, repeat => 0, cb => sub {
46     @menu = ();
47     &$curmenu;
48    
49     $menu_idx += @menu if $menu_idx < 0;
50     $menu_idx -= @menu if $menu_idx >= @menu;
51    
52     erase;
53    
54 root 1.2 my $data = $GPS->data;
55    
56 root 1.1 move 0, 0;
57 root 1.3 addstr $frame++ . ": " . localtime($data->{time}) . " $data->{lat} $data->{long} $data->{alt}m";
58 root 1.1
59     for my $idx (0 .. $#menu) {
60 root 1.3 move 2 + $idx, 0;
61 root 1.1 standout if $idx == $menu_idx;
62     addstr $menu[$idx][0];
63     standend if $idx == $menu_idx;
64     }
65    
66 root 1.3 move 3 + scalar@menu, 0;
67 root 1.1 eval {
68     $menu[$menu_idx][1]->();
69     };
70    
71     refresh;
72     });
73    
74     Event->io(fd => \*STDIN, poll => 'r', cb => sub {
75     my $ch = getch;
76     if ($ch eq "\x1b" or $ch eq "q") {
77     Event::unloop;
78     } elsif ($ch eq KEY_DOWN or $ch eq "j") {
79     $menu_idx++;
80     } elsif ($ch eq KEY_UP or $ch eq "k") {
81     $menu_idx--;
82     } else {
83     eval {
84     $menu[$menu_idx][2]->($ch);
85     };
86     }
87     $refresh->start;
88     });
89    
90     END {
91     end_win;
92     config "Mode: adhoc\n";
93     }
94    
95     sub decode_tags {
96     my $pkt = shift;
97     my %tag;
98    
99     while ($pkt) {
100     my ($id, $len) = unpack "C C", $pkt;
101     my $data = substr $pkt, 2, $len;
102     $pkt = substr $pkt, 2 + $len;
103    
104     $id = ({
105     0 => SSID,
106     1 => rates,
107     2 => FH,
108     3 => DS,
109     4 => CF,
110     5 => TIM,
111     6 => IBSS,
112     16 => challenge,
113     })->{$id};
114     $tag{$id} = $data;
115     }
116    
117     %tag;
118     }
119    
120     sub PF_PACKET (){ 17 }
121     sub SOCK_RAW (){ 3 }
122     sub ETH_P_ALL (){ 0x0003 }
123     sub SIOCGIFINDEX (){ 0x000008933 }
124    
125     sub open_pcap_socket {
126     socket my $cap, PF_PACKET, SOCK_RAW, (unpack "s", pack "n", ETH_P_ALL)
127     or die "unable to open packet socket: $!";
128    
129     my $ifidx = pack "a16 I", $RAWDEV;
130     ioctl $cap, SIOCGIFINDEX, $ifidx
131     or die "can't get index of interface $RAWDEV: $!";
132     $ifidx = unpack "x16 I", $ifidx;
133    
134     bind $cap, pack "S! S! I S! C C a8", PF_PACKET, (unpack "s", pack "n", ETH_P_ALL), $ifidx
135     or die "unable to bind to interface: $!";
136    
137     $cap;
138     }
139    
140     sub e2h($) {
141     join ":", map unpack("H*", $_), split //, $_[0];
142     }
143    
144     sub add_menu {
145     my ($title, $display, $select) = @_;
146     push @menu, [$title, $display, $select];
147     }
148    
149     $curmenu = \&menu_bss_list;
150    
151     sub bss2string {
152     my $bss = shift;
153    
154     my $s = "AGE(" . int(time - $bss->{ts}) . ") "
155     . "IP($bss->{ip}) "
156     . "ARP($bss->{arp}) ";
157     while (my ($k, $v) = each %{$bss->{ap}}) {
158     $s .= "(" . e2h($k) . " $v->{mode} '$v->{essid}') ";
159     }
160     $s;
161     }
162    
163     sub display_bss {
164     my $bss = shift;
165    
166     addstr "TS: $bss->{ts}\n";
167     addstr "ARP/IP packets received: $bss->{arp}/$bss->{ip}\n";
168    
169     addstr "\naccess points\n";
170    
171     while (my ($k, $v) = each %{$bss->{ap}}) {
172     addstr " " . e2h($k) . "\n";
173     addstr " mode $v->{mode}, channel $v->{channel}, essid '$v->{essid}'\n";
174     addstr " beacon frames received $v->{beacon}\n";
175     }
176    
177     addstr "\nstations\n";
178    
179     while (my ($k, $v) = each %{$bss->{station}}) {
180     addstr " " . e2h($k);
181     while (my ($k, $v) = each %$v) {
182     addstr " " . (inet_ntoa $k) . "($v)";
183     }
184     addstr "\n";
185     }
186     }
187    
188     sub menu_bss_list {
189     my @menu;
190     while (my ($k, $v) = each %$db) {
191     add_menu e2h($k) . " " . bss2string($v),
192     sub { display_bss $v },
193     sub {
194     if ($_[0] eq KEY_LEFT or $_[0] eq "h") {
195     Event::unloop;
196     } elsif ($_[0] eq KEY_RIGHT or $_[0] eq "l") {
197     #$curmenu = sub { display_bss $k };
198     }
199     } for 1..3;
200     }
201     }
202    
203     sub activity {
204     $db->{$_[0]}->{ts} = time;
205     #print "activity ", e2h $_[0]; print "\n";
206     $refresh->start;
207     }
208    
209     sub reg_ip {
210     my ($bssid, $ip, $ether) = @_;
211     $db->{$bssid}{station}{$ether}{$ip}++;
212     activity $bssid;
213     }
214    
215     {
216     my $cap = open_pcap_socket;
217     my $pkt;
218    
219     Event->io(fd => $cap, poll => 'r', cb => sub {
220     sysread $$cap, $pkt, 120;
221    
222     my ($fc1, $fc2, $sid, $a1, $a2, $a3, $sc, $pkt)
223     = unpack "C C n a6 a6 a6 S a*", $pkt;
224    
225     $pkt = substr $pkt, 6 if $fc2 & 0x03 == 0x03; # skip A4
226    
227     if ($fc1 == 0x80 or $fc1 == 0x50) {
228     my ($ts1, $ts2, $bi, $cf, $pkt)
229     = unpack "L L S S a*", $pkt;
230    
231     my %tag = decode_tags $pkt;
232    
233     my $ap = $db->{$a3}{ap}{$a2} ||= {};
234     $ap->{mode} = ($cf & 3) == 1 ? "AP" : "adhoc";
235     $ap->{essid} = $tag{SSID};
236     $ap->{channel} = ord $tag{DS};
237     $ap->{beacon}++;
238    
239     activity $a3;
240     } elsif ($fc1 == 0x08) {
241     my $bssid = ($a3, $a2, $a1)[$fc2 & 3];
242    
243     my ($llc, $et, $pkt) = unpack "a6 n a*", $pkt;
244     if ($llc eq "\xaa\xaa\x03\x00\x00\x00") { # SNAP/UI/ENCAP_ETHER
245     if ($et == 0x0800) {
246     my ($vhl, $tos, $len, $id, $off, $ttl, $prot, $sum, $src, $dst, $pkt)
247     = unpack "C C n n n C C n a4 a4 a*", $pkt;
248     if ($vhl & 0x40 == 0x40) {
249     $db->{$bssid}{ip}++;
250     reg_ip $bssid, $src, $a2;
251     reg_ip $bssid, $dst, $a1;
252     0 &&
253     printf "IP: %02x %02x %04x %04x: %s %s> %s %s %02x \n",
254     $fc1, $fc2, $sid, $sc,
255     (unpack "H*", $a2), (inet_ntoa $src),
256     (unpack "H*", $a1), (inet_ntoa $dst),
257     $prot;
258     }
259     } elsif ($et == 0x0806) {
260     my ($hrd, $pro, $hln, $pln, $op, $src_hw, $src, $dst_hw, $dst)
261     = unpack "n n C C n a6 a4 a6 a4", $pkt;
262     if ($hrd == 1 and $hln == 6 and $pln == 4) {
263     reg_ip $bssid, $src, $src_hw;
264     reg_ip $bssid, $dst, $dst_hw if $op != 1;
265     $db->{$bssid}{arp}++;
266     0 &&
267     printf "ARP: %04x> %s %s : %s %s\n",
268     $op,
269     (unpack "H*", $src_hw), (inet_ntoa $src),
270     (unpack "H*", $dst_hw), (inet_ntoa $dst);
271     }
272     }
273     } else {
274     0 &&
275     printf "?? %02x %02x %04x %04x: %s.%s \n", $fc1, $fc2, $sid, $sc, (unpack "H*", $llc), unpack "H*", $pkt;
276     }
277     } elsif ($fc1 != 0x40 and $fc1 != 0x10 and $fc1 != 0x00 and $fc1 != 0xb0) {
278     0 &&
279     printf "%02x %02x %04x %04x: %s \n", $fc1, $fc2, $sid, $sc, unpack "H*", $pkt;
280     }
281     });
282     }
283    
284     Event::loop;
285    
286