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 )