Dzisiaj rzutem na taśmę skaner do
Ubiquiti. W odróżnieniu od Mikrotika, Ubiquiti odpowiada na adres z którego zostało wysłane zapytanie. Ale w tym skrypcie nasłuchujemy na dowolnym adresie, tak jak w skanerze dla Mikrotików.
No i miały być szczegóły techniczne. Skaner rozsyła z portu 50122 na port 10001 paczkę
0x01000000
po broadcaście. Urządzenie wysyła odpowiedź na port 50122.
Trochę dłubaniny było przy zmiennym formacie ramki ale dość łatwo było ominąć ten problem. Pierwszy rodzaj ramki:
@s = unpack("H6H2H6H12NH6H12H8(H2n/a*)*", $ramka);
$s[0] sygnatura (0x010000)
$s[1] nie pamiętam :)
$s[2] ??
$s[3] adres MAC
$s[4] ??
$s[5] ??
$s[6] ??
$s[7] ??
(
$s[8] typ pola
X długość łańcucha (automatycznie wchłaniane przez unpack)
$s[9] łańcuch
)
...
Drugi rodzaj ramki:
@s = unpack("H6H2H6H12NH6H12H14(H2n/a*)*", $ramka);
$s[0] sygnatura (0x010000)
$s[1] nie pamiętam :)
$s[2] ??
$s[3] adres MAC
$s[4] ??
$s[5] ??
$s[6] ??
$s[7] ?? (tutaj długość jest większa o 3 bajty)
(
$s[8] typ pola
X długość łańcucha (automatycznie wchłaniane przez unpack)
$s[9] łańcuch
)
...
Zidentyfikowane typy pól:
0x03 - wersja softu
0x0a - uptime
0x0b - nadana nazwa dla urządzenia
0x0c - model urządzenia
0x0d - SSID do którego jest podpięte urządzenie gdy pracuje w trybie klienta
No i skrypt:
#!/usr/bin/perl
###############################################################################
#
# scan-ubiquiti.pl v1.2.0
#
# scan utility for ubiquiti
#
# 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 v1.2.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);
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("%2d. %17s %-16s %-16s %-4s %6s %-24s %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 H6 H12 H8 (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;
shift @header;
shift @header;
shift @header;
if ( $header[0] ne '01' ) {
$template = "H6 H2 H6 H12 N H6 H12 H14 (H2n/a*)*";
@header = unpack($template, $frame);
$signature = shift @header;
return undef if $signature ne '010000';
$t = shift @header;
shift @header;
$mac = shift @header;
shift @header;
shift @header;
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 @s = split /\./,$sw;
$s[2] = $s[2] || '';
$s[3] = $s[3] || '';
$s[2] =~ s/v//g;
my $out = {
board => $s[0] || '',
chipset => uc $s[1] || '',
build => $s[4] || '',
date => $s[5] || '',
unkn => $s[6] || ''
};
$out->{sw_version} = $s[2].".".$s[3] if $s[2] && $s[3];
return $out;
}
sub models {
my $m = shift;
return 'NanoBridgeM' if $m eq 'NB5';
return 'WISPStation5' if $m eq 'MS5';
return 'RocketM' if $m eq 'R5N';
return 'AirGridM5' if $m eq 'AG5';
return $m;
};
Brak komentarzy:
Prześlij komentarz