11 czerwca 2011

MNDP cz.4

Zaczął mnie irytować ten tcpdump. Ogarnąłem się trochę i przepisałem część kodu w zwykłych socketach.
#!/usr/bin/perl

###############################################################################
#
# scan-mikrotik.pl v2.8.0
#
# scan utility for mikrotik
#
# 2011-06-11
# przepisano engine na klasyczne sockety
#
# 2011-03-27
# dodano uptime
#
# mindc.net
# 2011-03-20
###############################################################################

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

print "scan-mikrotik.pl v2.8.0
    hw                 ip               board      sw      uptime identity
--------------------------------------------------------------------------------
";

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(5678,inet_aton($saddr));
    bind($socket,$sin);
    my $sout = sockaddr_in(5678,INADDR_BROADCAST);
    send($socket,pack("H8",0),0,$sout);
    send($socket,pack("H8",0),0,$sout);
    send($socket,pack("H8",0),0,$sout);
    close $socket;
}

my $socket;
socket($socket,PF_INET,SOCK_DGRAM,17) or die "socket error - $!";
my $sin = sockaddr_in(5678,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) < 5; #skip self
    my $o = mikrotik_header(inet_ntoa($hisaddr),$rtime);
    if ( not exists($data->{$o->{mac}})) {
        printf("%2d. %17s  %-16s %-10s %-7s %6s %s\n",
            ++$i,
            $o->{mac},
            $o->{ip},
            $o->{board},
            $o->{sw},
            sec2human($o->{uptime}),
            $o->{identity}
        );
    }
    $data->{$o->{mac}}++;
}
close $socket;
print "\n" if keys %$data;
exit;

sub mikrotik_header {
    my $ip = shift;
    my $buffer = shift;

    my @header = unpack("H2H2S(H4n/a*)*", $buffer);

    shift @header; #?
    shift @header; #?
    shift @header; #age?

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

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

        $out->{mac} = uc join(":",unpack("(H2)6",$value)) if $type eq '0001';
        $out->{identity} = $value if $type eq '0005';
        $out->{vendor} = $value if $type eq '0008';
        $out->{sw} = $value if $type eq '0007';
        $out->{board} = $value if $type eq '000c';
        $out->{key} = $value if $type eq '000b';
        $out->{uptime} = unpack("L",$value) if $type eq '000a';
#       $out->{unknown2} = $value if $type eq '000d';
    }
    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";
    }
}

Brak komentarzy: