22 sierpnia 2012

Ubiquiti cz.3

Dzisiaj coś mi nie pasowało w moim skanerze, okazało się że za bardzo zakombinowałem z formatem ramki.
Poprawny format ramki:
@s = unpack("H6 H2 H6 H12 N (H2n/a*)*", $ramka);
No i sam scanner:
#!/usr/bin/perl

###############################################################################
#
# scan-ubiquiti.pl v2.1.0
#
# scan utility for ubiquiti
#
# 2012-08-24
# dodano rozpoznawanie kodow hardware'u: 'NS3','B2N','BS2'
#
# 2012-08-22
# poprawiono parsowanie odbieranego pakietu
# poprawiono parsowanie wersji software
#
# 2011-06-11
# przepisano engine na klasyczne sockety
#
# mindc.net
# 2011-03-20
###############################################################################

use strict;
use warnings;
use Socket;
use Time::HiRes qw(gettimeofday);

print "scan-ubiquiti.pl v2.0.0
     hw                 ip               board            sw     uptime name                             ssid
--------------------------------------------------------------------------------------------------------
";

my %dev;
open my $ph, "-|","ip a";
while ( <$ph> ) {
        $dev{$2} = $1 if m@\s(\S+)/\d+\s.*(eth\d+)@;
}
close $ph;

my $data = {};

foreach my $saddr ( values %dev ) {
        my $socket;
        socket($socket,PF_INET,SOCK_DGRAM,17);
        setsockopt($socket, SOL_SOCKET, SO_BROADCAST, 1 );
        my $sin = sockaddr_in(50122,inet_aton($saddr));
        bind($socket,$sin);
        my $sout = sockaddr_in(10001,INADDR_BROADCAST);
        send($socket,pack("H8","01000000"),0,$sout);
        send($socket,pack("H8","01000000"),0,$sout);
        send($socket,pack("H8","01000000"),0,$sout);
        close $socket;
}

my $socket;
socket($socket,PF_INET,SOCK_DGRAM,17) or die "socket error - $!";
my $sin = sockaddr_in(50122,INADDR_ANY);
bind($socket,$sin);
setsockopt($socket, SOL_SOCKET, SO_BROADCAST, 0 );


my $rin = "";
vec($rin,fileno($socket),1) = 1;

my $end = gettimeofday() + 3;
my $timeout = $end - gettimeofday();

my $i = 0;
while ( select(my $rout = $rin,undef,undef,$timeout) ) {
        $timeout = $end - gettimeofday();
        my $rtime = "";
        my $his = recv($socket,$rtime,1500,0) || die "recv: $!";
        my ($port,$hisaddr) = sockaddr_in($his);
        next if length($rtime) < 8; #skip self
        my $o = ubiquiti_header(inet_ntoa($hisaddr),$rtime);

        if ( not exists($data->{$o->{mac}})) {
            my $sw = parse_sw($o->{sw});
            printf("%3d. %17s  %-16s %-16s %-6s %6s %-32s %s\n",
            ++$i,
            $o->{mac} || '',
            $o->{ip} || '',
            models($o->{board}) || '',
            $sw->{sw_version} || '',
            sec2human($o->{uptime}) || '',
            $o->{name} || '',
            $o->{ssid} || ''
        );
        }
        $data->{$o->{mac}}++;
}
close $socket;
print "\n" if keys %$data;
exit;

sub ubiquiti_header {
    my $ip = shift;
    my $frame = shift;

    my $template = "H6 H2 H6 H12 N (H2n/a*)*";
    my @header = unpack($template,$frame);
    my $signature = shift @header;
    return undef if $signature ne '010000';
    my $t = shift @header;
    shift @header;
    my $mac = shift @header;
    shift @header;

    my $out = {};
    @{$out}{qw(ip mac sw board key uptime ssid)} = ($ip,'','','','',0,'');

    for ( my $i = 0; $i < @header ; $i += 2 ) {
        my $type = $header[$i];
        my $value = $header[$i+1];

        $out->{sw} = $value if $type eq '03';
        $out->{board} = $value if $type eq '0c';
        $out->{name} = $value if $type eq '0b';
        $out->{uptime} = unpack("N",$value) if $type eq '0a';
        $out->{ssid} = $value if $type eq '0d';

    }

    $out->{mac} = uc join(":",unpack("(H2)6",pack("H*",$mac)));
    $out->{frame} = $frame;
    $out->{structure} = \@header;
    return $out;

}

sub sec2human {
    my $sec = shift;

    return "" if $sec <= 0;

    my $w = int($sec / 60 / 60 / 24 / 7);
    my $d = int($sec / 60 / 60 / 24 % 7);
    my $h = int($sec / 60 / 60 % 24);
    my $m = int($sec / 60 % 60);
    my $s = int($sec % 60);
    if ( $w ) {
        return sprintf("%dw%dd",$w,$d);
    } elsif ( $d ) {
        return sprintf("%dd%dh",$d,$h);
    } elsif ( $h ) {
        return sprintf("%dh%dm",$h,$m);
    } elsif ( $m ) {
        return sprintf("%dm%ds",$m,$s);
    } else {
        return "${s}s";
    }
}

sub parse_sw {
    my $sw = shift;
    return {} unless $sw;

    my @d = $sw =~ m/(\S{2,3})\.(ar\d+)\.v(\S+)\.(\d{4,5})\.(\d{6})\.(\d{4})/;

    my $out = {
    board => $d[0] || '',
    chipset => uc $d[1] || '',
    sw_version => $d[2],
    build => $d[3] || '',
    date => $d[4] || '',
    unkn => $d[5] || ''
    };
    return $out;
}

sub models {
    my $m = shift;
    return 'NanoBridge M5' if $m eq 'NB5';
    return 'WispStation5' if $m eq 'MS5';
    return 'Rocket M5' if $m eq 'R5N';
    return 'AirGrid M5' if $m eq 'AG5';
    return 'NanoStation M3' if $m eq 'NS3';
    return 'Bullet M2' if $m eq 'B2N';
    return 'Bullet 2' if $m eq 'BS2';
    return $m;
};