App-Netdisco
view release on metacpan or search on metacpan
lib/App/Netdisco/Util/Nbtstat.pm view on Meta::CPAN
package App::Netdisco::Util::Nbtstat;
use Dancer qw/:syntax :script/;
use Dancer::Plugin::DBIC 'schema';
use App::Netdisco::Util::Node 'check_mac';
use App::Netdisco::AnyEvent::Nbtstat;
use Encode;
use base 'Exporter';
our @EXPORT = ();
our @EXPORT_OK = qw/ nbtstat_resolve_async store_nbt /;
our %EXPORT_TAGS = (all => \@EXPORT_OK);
=head1 NAME
App::Netdisco::Util::Nbtstat
=head1 DESCRIPTION
Helper subroutines to support parts of the Netdisco application.
There are no default exports, however the C<:all> tag will export all
subroutines.
=head1 EXPORT_OK
=head2 nbtstat_resolve_async( $ips )
This method uses an asynchronous AnyEvent NetBIOS node status requester
C<App::Netdisco::AnyEvent::Nbtstat>.
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 nbtstat_resolve_async {
my $ips = shift;
my $timeout = (setting('nbtstat_response_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;
}
);
}
# Decrement the cv counter to cancel out the send declaration
$cv->end;
# Wait for the resolver to perform all resolutions
$cv->recv;
# Close sockets
undef $stater;
return $ips;
}
# filter nbt names / information
sub _filter_nbname {
my $ip = shift;
my $hash_ref = shift;
my $node_status = shift;
my $server = 0;
my $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'} : '';
if ( $suffix == 0 and $G eq "GROUP" ) {
$domain = $name;
}
if ( $suffix == 3 and $G eq "UNIQUE" ) {
$nbuser = $name;
}
if ( $suffix == 0 and $G eq "UNIQUE" ) {
$nbname = $name unless $name =~ /^IS~/;
}
if ( $suffix == 32 and $G eq "UNIQUE" ) {
$server = 1;
}
}
unless ($nbname) {
debug sprintf ' nbtstat no computer name found for %s', $ip;
return;
}
my $mac = $node_status->{'mac_address'} || '';
unless ( check_mac( $mac, $ip ) ) {
( run in 0.702 second using v1.01-cache-2.11-cpan-39bf76dae61 )