Asynchronous NBTstat

This commit is contained in:
Eric A. Miller
2014-07-20 21:51:20 -04:00
parent b86ff6580e
commit e7803caa59
7 changed files with 381 additions and 47 deletions

View File

@@ -5,11 +5,11 @@ use Dancer::Plugin::DBIC 'schema';
use App::Netdisco::Util::Node 'check_mac';
use NetAddr::IP::Lite ':lower';
use Net::NBName;
use App::Netdisco::AnyEvent::Nbtstat;
use base 'Exporter';
our @EXPORT = ();
our @EXPORT_OK = qw/ do_nbtstat store_nbt /;
our @EXPORT_OK = qw/ nbtstat_resolve_async store_nbt /;
our %EXPORT_TAGS = (all => \@EXPORT_OK);
=head1 NAME
@@ -25,42 +25,64 @@ subroutines.
=head1 EXPORT_OK
=head2 do_nbtstat( $node )
=head2 nbtstat_resolve_async( $ips )
Connects to node and gets NetBIOS information. Then adds entries to
node_nbt table.
This method uses an asynchronous AnyEvent NetBIOS node status requester
C<App::Netdisco::AnyEvent::Nbtstat>.
Returns whether a node is answering netbios calls or not.
Given a reference to an array of hashes will connects to the C<IPv4> of a
node and gets NetBIOS node status information.
Returns the supplied reference to an array of hashes with MAC address,
NetBIOS name, NetBIOS domain/workgroup, NetBIOS user, and NetBIOS server
service status for addresses which responded.
=cut
sub do_nbtstat {
my ($host, $now) = @_;
my $ip = NetAddr::IP::Lite->new($host) or return;
sub nbtstat_resolve_async {
my $ips = shift;
unless ( $ip->version() == 4 ) {
debug ' nbtstat only supports IPv4, invalid ip %s', $ip->addr;
return;
my $timeout = setting('nbtstat_timeout') || 1;
my $interval = setting('nbtstat_interval') || 0.02;
my $stater = App::Netdisco::AnyEvent::Nbtstat->new(
timeout => $timeout,
interval => $interval
);
# Set up the condvar
my $cv = AE::cv;
$cv->begin( sub { shift->send } );
foreach my $hash_ref (@$ips) {
my $ip = $hash_ref->{'ip'};
$cv->begin;
$stater->nbtstat(
$ip,
sub {
my $res = shift;
_filter_nbname( $ip, $hash_ref, $res );
$cv->end;
}
);
}
my $nb = Net::NBName->new;
my $ns = $nb->node_status( $ip->addr );
# Decrement the cv counter to cancel out the send declaration
$cv->end;
# Check for NetBIOS Info
return unless $ns;
# Wait for the resolver to perform all resolutions
$cv->recv;
my $nbname = _filter_nbname( $ip->addr, $ns );
# Close sockets
undef $stater;
if ($nbname) {
store_nbt($nbname, $now);
}
return 1;
return $ips;
}
# filter nbt names / information
sub _filter_nbname {
my $ip = shift;
my $hash_ref = shift;
my $node_status = shift;
my $server = 0;
@@ -68,10 +90,10 @@ sub _filter_nbname {
my $domain = '';
my $nbuser = '';
for my $rr ( $node_status->names ) {
my $suffix = defined $rr->suffix ? $rr->suffix : -1;
my $G = defined $rr->G ? $rr->G : '';
my $name = defined $rr->name ? $rr->name : '';
for my $rr ( @{$node_status->{'names'}} ) {
my $suffix = defined $rr->{'suffix'} ? $rr->{'suffix'} : -1;
my $G = defined $rr->{'G'} ? $rr->{'G'} : '';
my $name = defined $rr->{'name'} ? $rr->{'name'} : '';
if ( $suffix == 0 and $G eq "GROUP" ) {
$domain = $name;
@@ -88,11 +110,11 @@ sub _filter_nbname {
}
unless ($nbname) {
debug ' nbtstat no computer name found for %s', $ip;
debug sprintf ' nbtstat no computer name found for %s', $ip;
return;
}
my $mac = $node_status->mac_address || '';
my $mac = $node_status->{'mac_address'} || '';
unless ( check_mac( $ip, $mac ) ) {
@@ -101,23 +123,23 @@ sub _filter_nbname {
->single( { ip => $ip, -bool => 'active' } );
if ( !defined $node_ip ) {
debug ' no MAC for %s returned by nbtstat or in DB', $ip;
debug sprintf ' no MAC for %s returned by nbtstat or in DB', $ip;
return;
}
$mac = $node_ip->mac;
}
return {
ip => $ip,
mac => $mac,
nbname => $nbname,
domain => $domain,
server => $server,
nbuser => $nbuser
};
$hash_ref->{'ip'} = $ip;
$hash_ref->{'mac'} = $mac;
$hash_ref->{'nbname'} = $nbname;
$hash_ref->{'domain'} = $domain;
$hash_ref->{'server'} = $server;
$hash_ref->{'nbuser'} = $nbuser;
return;
}
=head2 store_nbt($nb_hash_ref, $now?)
=item store_nbt($nb_hash_ref, $now?)
Stores entries in C<node_nbt> table from the provided hash reference; MAC
C<mac>, IP C<ip>, Unique NetBIOS Node Name C<nbname>, NetBIOS Domain or