mirror of https://github.com/aredn/aredn.git
336 lines
8.8 KiB
Perl
Executable File
336 lines
8.8 KiB
Perl
Executable File
#!/usr/bin/perl -w
|
|
=for comment
|
|
Part of AREDN -- Used for creating Amateur Radio Emergency Data Networks
|
|
Copyright (C) 2015 Conrad Lara
|
|
See Contributors file for additional contributors
|
|
|
|
Copyright (c) 2013 David Rivenburg et al. BroadBand-HamNet
|
|
|
|
2015-04-01 AE6XE update to display neighbor nodes, replace vendor with mode
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation version 3 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
Additional Terms:
|
|
|
|
Additional use restrictions exist on the AREDN(TM) trademark and logo.
|
|
See AREDNLicense.txt for more info.
|
|
|
|
Attributions to the AREDN Project must be retained in the source code.
|
|
If importing this code into a new or existing project attribution
|
|
to the AREDN project must be added to the source code.
|
|
|
|
You must not misrepresent the origin of the material contained within.
|
|
|
|
Modified versions must be modified to attribute to the original source
|
|
and be marked in reasonable ways as differentiate it from the original
|
|
version.
|
|
|
|
=cut
|
|
|
|
sub usage
|
|
{
|
|
print "usage: wscan [-1abnor] [-i iface]\n";
|
|
print " -1 run once and quit\n";
|
|
print " -a average mode\n";
|
|
print " -b batch mode\n";
|
|
print " -n <num> number of times to scan\n";
|
|
print " -o show only open access points\n";
|
|
print " -r raw mode\n";
|
|
print " -w produce html output\n";
|
|
exit;
|
|
}
|
|
|
|
sub freq_to_chan
|
|
{
|
|
my ($freq) = @_;
|
|
|
|
if ($freq < 256 )
|
|
{
|
|
return $freq;
|
|
}
|
|
elsif ($freq == 2484)
|
|
{
|
|
return "14";
|
|
}
|
|
elsif ($freq == 2407)
|
|
{
|
|
return 0;
|
|
}
|
|
elsif ($freq < 2484)
|
|
{
|
|
return ($freq-2407)/5;
|
|
}
|
|
elsif ($freq < 5000)
|
|
{
|
|
return $freq ; # stay in freq, no ch #s
|
|
}
|
|
elsif ($freq < 5380) # these are 5Ghz channels 75 and below
|
|
{
|
|
return ($freq-5000)/5 ;
|
|
}
|
|
elsif ($freq < 5500) # ch 76 to 99 can only be 3Ghz freq, no part 15 here
|
|
{
|
|
return ($freq-2000); # return 3ghz freq (5ghz boards with -2Ghz transverter)
|
|
}
|
|
elsif ($freq < 6000)
|
|
{
|
|
return ($freq-5000)/5;
|
|
}
|
|
else
|
|
{
|
|
return $freq;
|
|
}
|
|
}
|
|
|
|
sub pushAP
|
|
{
|
|
my($signal, $freq, $key, $ssid, $host, $mac, $mode) = @_;
|
|
|
|
return if $mac eq "";
|
|
return if $openap and ($key ne "");
|
|
|
|
$chan=freq_to_chan($freq);
|
|
|
|
if($ssid eq "") { $ssid = "(hidden)" }
|
|
if($chan eq "") { $chan = "?" }
|
|
|
|
if($key eq "") { $key = " " }
|
|
else { $key = "*" }
|
|
|
|
if($avg)
|
|
{
|
|
$avgs{"$mac total"} += $signal;
|
|
$avgs{"$mac num"} += 1;
|
|
$aphash{$mac} = sprintf "% 3d %s %-32s\t%s\t%s\t%s\n",
|
|
$chan, $key, $ssid, $host, $mac, $mode;
|
|
}
|
|
elsif($web)
|
|
{
|
|
push @list, sprintf "% 3d|%d|%s|%s|%s|%s|%s",
|
|
$signal, $chan, $key, sprintf("&#x%*vX", '&#x',$ssid), $host, $mac, $mode;
|
|
}
|
|
else
|
|
{
|
|
push @list, sprintf "% 3d %2d %s %-32s\t%s\t%s\t%s\n",
|
|
$signal, $chan, $key, $ssid, $host, $mac, $mode;
|
|
}
|
|
}
|
|
|
|
###################################################
|
|
|
|
$avg = 0; # average mode
|
|
$batch = 0; # batch mode
|
|
$loops = 0; # number of times to run 0=inf
|
|
$raw = 0; # raw mode
|
|
$openap = 0; # show open ap's
|
|
$iface = `uci -q get 'network.wifi.ifname'`; # wireless interface
|
|
chomp $iface;
|
|
|
|
$iters = 0; # number of iterations
|
|
%avgs = (); # average statistics
|
|
%aphash = (); # list of ap's for avg mode
|
|
|
|
$mychan = `iwinfo $iface info | grep -i channel`;
|
|
$mychan =~ /Channel:\s+(-*\d+)/;
|
|
$mychan = ( ! defined $1 || ! int($1) || ! ($1 >= -2 && $1 <= 185) ) ? 0 : $1;
|
|
|
|
# ch 76 - 99 are 3ghz since no part 15 usage (5ghz board with -2ghz transverter)
|
|
if ($mychan >= 76 and $mychan <= 99)
|
|
{
|
|
$mychan = ($mychan*5+3000);
|
|
}
|
|
|
|
while(defined ($arg = shift))
|
|
{
|
|
if ($arg eq "-h") { usage() }
|
|
elsif($arg eq "-1") { $loops = 1 }
|
|
elsif($arg eq "-a") { $avg = 1 }
|
|
elsif($arg eq "-b") { $batch = 1 }
|
|
elsif($arg eq "-o") { $openap = 1 }
|
|
elsif($arg eq "-r") { $raw = 1 }
|
|
elsif($arg eq "-i") { $iface = shift }
|
|
elsif($arg eq "-n") { $loops = shift }
|
|
elsif($arg eq "-w") { $web = 1 }
|
|
else { die "bad arg $arg\n" }
|
|
}
|
|
|
|
die "bad interface" if not defined $iface;
|
|
|
|
if($raw)
|
|
{
|
|
system("iw dev $iface scan");
|
|
system("iw dev $iface station dump");
|
|
exit;
|
|
}
|
|
|
|
while(1)
|
|
{
|
|
$line = `egrep "['\\"].*-(5|10|20)-v[3456]" /etc/config/wireless | head -1`;
|
|
$line =~ /['"](.*-(5|10|20)-v[3456])/;
|
|
$myssid = $1;
|
|
|
|
open(FILE, "iw dev $iface scan 2>&1 |") or die "iw scan failed";
|
|
$mac = "";
|
|
$host = "N/A";
|
|
$lastseen = 0;
|
|
@list = ();
|
|
|
|
while($line = <FILE>)
|
|
{
|
|
if($line =~ /BSS\s+(([[:xdigit:]]{2}:){5}[[:xdigit:]]{2})/)
|
|
{
|
|
if ( $lastseen < 10000 ) { pushAP($signal, $chan, $key, $ssid, $host, $mac, $mode) }
|
|
$mac = uc $1;
|
|
|
|
$mode = "AP";
|
|
$ssid = "";
|
|
$signal = 0;
|
|
$chan = "";
|
|
$key = "";
|
|
$lastseen = 0;
|
|
|
|
}
|
|
|
|
if($line =~ /BSS(\s+)([[:xdigit:]]{2}:){5}[[:xdigit:]]{2}.*joined/)
|
|
{
|
|
$mode = "My Ad-Hoc Network";
|
|
$chan = $mychan;
|
|
}
|
|
if($line =~ /\bSSID: (.*)/) { $ssid = $1 }
|
|
if($line =~ /\bSSID: unknown/) { $ssid = "unknown" }
|
|
if($line =~ /\bcapability: (IBSS)/ and $mode eq "AP")
|
|
{ $mode = "Foreign Ad-Hoc Network" }
|
|
if($line =~ /\bfreq: (\d+)/) { $chan = $1 }
|
|
if($line =~ /\bsignal: ([\d-]+)/) { $signal = $1 }
|
|
if($line =~ /\bGroup cipher:(.+)/) { $key = $1 }
|
|
if($line =~ /\blast seen: (\d+)/) { $lastseen = $1 }
|
|
}
|
|
|
|
close(FILE);
|
|
|
|
if ( $lastseen < 10000 ) { pushAP($signal, $chan, $key, $ssid, $host, $mac, $mode) }
|
|
sleep 1 if not scalar @list and $loops != 1;
|
|
|
|
$mac = "";
|
|
$mode = "Connected Ad-Hoc Station";
|
|
$signal = 0;
|
|
$key = "";
|
|
$lastseen = 0;
|
|
++$iters;
|
|
|
|
open(FILE, "iw dev $iface station dump 2>&1 |") or die "iw failed";
|
|
|
|
while($line = <FILE>)
|
|
{
|
|
if($line =~ /Station (\S+) \(on $iface\)/)
|
|
{
|
|
if ( $lastseen < 10000 ) { pushAP($signal, $mychan, $key, $myssid, $host, $mac, $mode) }
|
|
|
|
$lastseen = 0;
|
|
$mac = $1;
|
|
$ip = `grep $mac /proc/net/arp | egrep "^10.*\$" | tail -1`;
|
|
$mac = uc $mac;
|
|
if ( $ip ne "" )
|
|
{
|
|
$ip =~ s/[ \t].*$// ;
|
|
chomp($ip);
|
|
$host = $ip;
|
|
if( $ip ne "")
|
|
{
|
|
$reverse_ip=join ".",reverse(split /\./,$ip);
|
|
foreach(`nslookup $ip`)
|
|
{
|
|
last if ($host) = /^$reverse_ip\.in-addr\.arpa[ \t]+name[ \t]+=[ \t]+(\S+)\.local\.mesh/;
|
|
}
|
|
if ( $host eq "" ) { $host = $ip }
|
|
}
|
|
}
|
|
else { $host = "????" }
|
|
}
|
|
|
|
if($line =~ /signal avg:[ \t]+([-\d]+)/) { $signal = $1 }
|
|
if($line =~ /inactive time:\t(\d+) ms/) { $lastseen = $1 }
|
|
}
|
|
|
|
close(FILE);
|
|
if ( $lastseen < 10000 ) { pushAP($signal, $mychan, $key, $myssid, $host, $mac, $mode) }
|
|
|
|
sleep 1 if not scalar @list and $loops != 1;
|
|
|
|
if(not $batch)
|
|
{
|
|
if($avg)
|
|
{
|
|
system "clear";
|
|
printf "Sig Rel Ch E SSID Hostname MAC/BSSID 802.11 Mode %6d\n", $iters;
|
|
print "--- --- -- - -------------------------------- ----------------- ------------- -----------\n";
|
|
}
|
|
elsif($web)
|
|
{
|
|
print "<table class=sortable border=1 cellpadding=5>\n";
|
|
print "<tr><th>Sig</th><th>Chan</th><th>Enc</th><th>SSID</th><th>Hostname</th><th>MAC/BSSID</th><th>802.11 Mode</th></tr>\n";
|
|
}
|
|
else
|
|
{
|
|
#system "clear";
|
|
printf "Sig Ch E SSID Hostname MAC/BSSID 802.11 Mode %6d\n", $iters;
|
|
print "--- -- - -------------------------------- --------------------- ------------- ------------\n";
|
|
}
|
|
}
|
|
|
|
if($avg)
|
|
{
|
|
open(FILE, "| sort -nr");
|
|
foreach $mac (keys %aphash)
|
|
{
|
|
printf FILE "%3d %3d %s",
|
|
($avgs{"$mac total"} - $avgs{"$mac num"} + 1)/$avgs{"$mac num"},
|
|
100*$avgs{"$mac num"}/$iters,
|
|
$aphash{$mac};
|
|
}
|
|
close(FILE);
|
|
print "\n";
|
|
}
|
|
elsif($web)
|
|
{
|
|
foreach $line (sort { $b <=> $a } @list)
|
|
{
|
|
|
|
# Match "AREDN"
|
|
if ( $line =~ /AREDN/) { print "<tr class=\"wscan-row-node\">"}
|
|
else { print "<tr>"}
|
|
|
|
my $i = 0;
|
|
foreach $val (split /\|/, $line)
|
|
{
|
|
$val = " " unless $val =~ /\S/;
|
|
if($i++ == 3) { print "<td>$val</td>" }
|
|
else { print "<td align=center>$val</td>" }
|
|
}
|
|
print "<td> </td>" if $i < 7;
|
|
print "</tr>\n";
|
|
}
|
|
print "</table>\n";
|
|
exit;
|
|
}
|
|
else
|
|
{
|
|
open(FILE, "| sort -nr");
|
|
print FILE @list;
|
|
close(FILE);
|
|
print "\n";
|
|
}
|
|
|
|
last if --$loops == 0;
|
|
}
|