App-Netdisco

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

  [NEW FEATURES]

  * Finally we have a discover/refresh/arpnip/macsuck daemon jobs :)
  * Also... a Scheduler which removes need for crontab installation
  * The netdisco-do script can queue any one-off job
  * Select MAC Address display format on Node and Device Port search
  * Helper script to import the Netdisco 1.x Topology file to the database
  * Support for pseudo devices (useful for dummy device links)
  * Manual Topology editing via the web
  * Job Queue view and delete page
  * Empty device table prompts initial discover on homepage
  * Support for App::NetdiscoX::Web::Plugin namespace
  * Plugins can add columns to Device Ports display
  * Observium Sparklines port column plugin
  * Plugins can have CSS and Javascript loaded within <head>

  [ENHANCEMENTS]

  * SNMP connection now uses cached info if available
  * Better handling of MIBs home location in deploy script
  * Port filter in device port display is now highlighted green

Changes  view on Meta::CPAN


  [ENHANCEMENTS]

  * Device Port filter by vlan includes both tagging and untagged (closes #37)
  * Change colour and name of Port Control toggle option in Device Port View
  * Incorporate latest DB schema changes from upstream
  * Add some doc clarifcations

  [BUG FIXES]

  * No longer prompt for demo/demo credentials (closes #38) (J. Binks)
  * Display IP in Vlan search if device has no DNS (closes #36) (J. Binks)

2.004000 - 2013-01-14

  [BUG FIXES]

  * Very naughty typo in netmap code, which I forgot to merge a fix for.
  * Typo in installation docs (S. Gupta)

2.002000 - 2013-01-06

bin/netdisco-deploy  view on Meta::CPAN

say 'https://github.com/netdisco/netdisco/wiki/Release-Notes';
say 'There you will find required and incompatible changes';
say 'which are not covered by this script.';
say '';
say 'You will be asked to confirm all changes to your system.';
say '';
print color 'reset';

my $term = Term::ReadLine->new('netdisco');
my $bool = $term->ask_yn(
  prompt => 'So, is all of the above in place?', default => 'n',
);

exit(0) unless $bool;

say '';
$bool = $term->ask_yn(
  prompt => 'Would you like to deploy the database schema?', default => 'n',
);
deploy_db() if $bool;

say '';
$bool = $term->ask_yn(
  prompt => 'Download and update vendor MAC prefixes (OUI data)?', default => 'n',
);
deploy_oui() if $bool;

say '';
my $default_mibhome = dir($home, 'netdisco-mibs');
if (setting('mibhome') and setting('mibhome') ne $default_mibhome) {
    my $mibhome = $term->get_reply(
      print_me => "MIB home options:",
      prompt   => "Download and update MIB files to...?",
      choices  => [setting('mibhome'), $default_mibhome, 'Skip this.'],
      default  => 'Skip this.',
    );
    deploy_mibs($mibhome) if $mibhome and $mibhome ne 'Skip this.';
}
else {
    $bool = $term->ask_yn(
      prompt => "Download and update MIB files?", default => 'n',
    );
    deploy_mibs($default_mibhome) if $bool;
}

sub deploy_db {
  system('netdisco-db-deploy') == 0 or die "\n";
  print color 'bold blue';
  say 'DB schema update complete.';
  print color 'reset';

bin/netdisco-deploy  view on Meta::CPAN


  # set initial dancer web session cookie key
  schema('netdisco')->resultset('Session')->find_or_create(
    {id => 'dancer_session_cookie_key', a_session => \'md5(random()::text)'},
    {key => 'primary'},
  );
}

sub get_userpass {
  my $upterm = shift;
  my $name = $upterm->get_reply(prompt => 'Username: ');
  my $pass = $upterm->get_reply(prompt => 'Password: ');

  unless ($name and $pass) {
    say 'username and password cannot be empty, please try again.';
    ($name, $pass) = get_userpass($upterm);
  }

  return ($name, $pass);
}

sub deploy_oui {

bin/netdisco-sshcollector  view on Meta::CPAN


or automated via Expect - this is mostly useful for non-Linux appliances which
don't support command execution via ssh:

 my ($pty, $pid) = $ssh->open2pty;
 unless ($pty) {
   debug "unable to run remote command [$hostlabel] " . $ssh->error;
   return ();
 }
 my $expect = Expect->init($pty);
 my $prompt = qr/#/;
 my ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
 $expect->send("terminal length 0\n");
 # etc...

The returned IP and MAC addresses should be in a format that the respective
B<inetaddr> and B<macaddr> datatypes in PostgreSQL can handle.   

=head1 COMMAND LINE OPTIONS

=over 4

lib/App/Netdisco/SSHCollector/Platform/ACE.pm  view on Meta::CPAN

    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt = qr/#/;

    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    $expect->send("terminal length 0\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

    $expect->send("show context | include Name\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

    my @ctx;
    my @arpentries;

    for (split(/\n/, $before)){
        if (m/Name: (\S+)/){
            push(@ctx, $1);
            $expect->send("changeto $1\n");
            ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);
            $expect->send("show arp\n");
            ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);
            for (split(/\n/, $before)){
                my ($ip, $mac) = split(/\s+/);
                if ($ip =~ m/(\d{1,3}\.){3}\d{1,3}/ && $mac =~ m/[0-9a-f.]+/i) {
                    push(@arpentries, { ip => $ip, mac => $mac });
                }
            }

        }
    }

lib/App/Netdisco/SSHCollector/Platform/ASA.pm  view on Meta::CPAN

    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt;

    if ($args->{enable_password}) {
       $prompt = qr/>/;
       ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

       $expect->send("enable\n");

       $prompt = qr/Password:/;
       ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

       $expect->send( $args->{enable_password} ."\n" );
    }

    $prompt = qr/#\s*$/;
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    $expect->send("terminal pager 2147483647\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

    $expect->send("show names\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
    my @names = split(m/\n/, $before);

    $expect->send("show arp\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
    my @lines = split(m/\n/, $before);

    my @arpentries = ();

    # ifname 192.0.2.1 0011.2233.4455 123
    my $linereg = qr/[A-z0-9\-\.]+\s([A-z0-9\-\.]+)\s
                     ([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4})/x;

    foreach my $line (@lines) {
        if ($line =~ $linereg) {

lib/App/Netdisco/SSHCollector/Platform/ASA.pm  view on Meta::CPAN

                }
            }
            if ($ip =~ m/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) {
                push @arpentries, { mac => $mac, ip => $ip };
            }
        }
    }

    # start ipv6
    $expect->send("show ipv6 neighbor\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);

    @lines = split(m/\n/, $before);

    # IPv6 age MAC state ifname
    $linereg = qr/([0-9a-fA-F\:]+)\s+[0-9]+\s
                     ([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4})/x;

    foreach my $line (@lines) {
        if ($line =~ $linereg) {
            my ($ip, $mac) = ($1, $2);

lib/App/Netdisco/SSHCollector/Platform/ASAContext.pm  view on Meta::CPAN

    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt;

    if ($args->{enable_password}) {
        $prompt = qr/>/;
        ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

        $expect->send("enable\n");

        $prompt = qr/Password:/;
        ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

        $expect->send( $args->{enable_password} ."\n" );
    }

    $prompt = qr/#\s*$/;
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    $expect->send("terminal pager 2147483647\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

    $expect->send("changeto system\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    $expect->send("show run | include ^context\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
    my @contexts = split(m/\n/, $before);


    my @arpentries = ();
    for (my $i = 1; $i < scalar @contexts; $i++) {
        $contexts[$i] =~ s/context //;
        debug "$hostlabel/$contexts[$i]";
        $expect->send("changeto context $contexts[$i]\n");
        ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

        $expect->send("show names\n");
        ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);

        my @names = split(m/\n/, $before);

        $expect->send("terminal pager 2147483647\n");
        ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

        $expect->send("show arp\n");
        ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);

        my @lines = split(m/\n/, $before);

        # ifname 192.0.2.1 0011.2233.4455 123
        my $linereg = qr/[A-z0-9\-\.]+\s([A-z0-9\-\.]+)\s
            ([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4})/x;

        foreach my $line(@lines) {
            if ($line =~ $linereg) {
                my ($ip, $mac) = ($1, $2);

lib/App/Netdisco/SSHCollector/Platform/ASAContext.pm  view on Meta::CPAN

                    }
                }
                if ($ip =~ m/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) {
                    push @arpentries, { mac => $mac, ip => $ip };
                }
            }
        }

        # start ipv6
        $expect->send("show ipv6 neighbor\n");
        ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);

        @lines = split(m/\n/, $before);

        # IPv6 age MAC state ifname
        $linereg = qr/([0-9a-fA-F\:]+)\s+[0-9]+\s
            ([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4})/x;

        foreach my $line (@lines) {
            if ($line =~ $linereg) {
                my ($ip, $mac) = ($1, $2);

lib/App/Netdisco/SSHCollector/Platform/ArubaCX.pm  view on Meta::CPAN


    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);

    my $prompt = qr/#/;
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    $expect->send("no page\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    $expect->send("show arp all-vrfs\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
    my @lines= split(m/\n/,$before);

    $expect->send("exit\n");
    $expect->soft_close();

    my @arpentries = ();

    # Example output from 'show arp':
    #
    # IPv4 Address     MAC                Port         Physical Port                                      State

lib/App/Netdisco/SSHCollector/Platform/ArubaCont.pm  view on Meta::CPAN

    debug "$hostlabel arpnip() - Starting ARP collection for Aruba Controller";

    # Open pseudo-terminal
    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }

    my $expect = Expect->init($pty);
    my $prompt = qr/#/;  # Adjust to match the Aruba controller prompt

    # Log into the controller and disable paging
    $expect->expect(10, -re, $prompt);
    $expect->send("no paging\n");
    $expect->expect(10, -re, $prompt);

    # Send 'show arp' command
    $expect->send("show arp\n");
    my ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    # Parse the ARP output
    my @data = split "\n", $before;
    my @arpentries;

    # Example regex matching for controller ARP output
    foreach my $line (@data) {
        if ($line =~ /(\d+\.\d+\.\d+\.\d+)\s+([\da-f:]+)\s+(vlan\d+)/) {
            push @arpentries, { ip => $1, mac => $2, port => $3 };
            debug "$hostlabel - Parsed ARP entry: IP=$1, MAC=$2, Port=$3";

lib/App/Netdisco/SSHCollector/Platform/CPVSX.pm  view on Meta::CPAN

    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt;

    $prompt = qr/>/;
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    # TODO: check CP os/version via "cpstat os" and VSX status via "show vsx"
    # $expect->send("show vsx\n");
    # ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
    # debug "$hostlabel $$ show vsx: $before";

    # Enumerate virtual systems
    # Virtual systems list
    # VS ID       VS NAME
    # 0           0
    # 1           BACKUP-VSX_xxxxxx_Context
    # ...

    $expect->send("show virtual-system all\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    my @vsxentries = ();
    my @lines = split(m/\n/, $before);

    my $linereg = qr/(\d+)\s+([A-Za-z0-9_-]+)/;
    foreach my $line (@lines) {
        if ($line =~ $linereg) {
            my ($vsid, $vsname) = ($1, $2);
            push @vsxentries, { vsid => $vsid,  vsname=> $vsname };
            debug "$hostlabel $$ $vsid, $vsname";

lib/App/Netdisco/SSHCollector/Platform/CPVSX.pm  view on Meta::CPAN

    }

    # TODO:
    # Expert mode should be used only for pre-R77.30 versions
    # For R77.30 and later we can use:
    # set virtual-system $vsid
    # show arp dynamic all

    $expect->send("expert\n");

    $prompt = qr/Enter expert password:/;
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    $expect->send( $args->{expert_password} ."\n" );

    $prompt = qr/#/;
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    foreach (@vsxentries) {
        my $vsid = $_->{vsid};
        debug "$hostlabel $$ arpnip VSID: $vsid";

        $expect->send("vsenv $vsid\n");
        ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

        $expect->send("arp -n | tail -n +2\n");
        ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

        @lines = split(m/\n/, $before);

        # 192.168.1.1 ether 00:b6:aa:f5:bb:6e C eth1
        $linereg = qr/([0-9\.]+)\s+ether\s+([a-fA-F0-9:]+)/;

        foreach my $line (@lines) {
            if ($line =~ $linereg) {
                my ($ip, $mac) = ($1, $2);
                push @arpentries, { mac => $mac, ip => $ip };
                debug "$hostlabel $$ arpnip VSID: $vsid IP: $ip MAC: $mac";
            }
        }

    }

    $expect->send("exit\n");

    $prompt = qr/>/;
    ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

    $expect->send("exit\n");

    $expect->soft_close();

    return @arpentries;
}

1;

lib/App/Netdisco/SSHCollector/Platform/FTD.pm  view on Meta::CPAN

    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt;

    if ($args->{enable_password}) {
       $prompt = qr/>/;
       ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

       $expect->send("enable\n");

       $prompt = qr/Password:/;
       ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

       $expect->send( $args->{enable_password} ."\n" );
    }

    $prompt = qr/>\s*$/;
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

#    $expect->send("terminal pager 2147483647\n");
#    ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

#    $expect->send("show names\n");
#    ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
#    my @names = split(m/\n/, $before);

    $expect->send("show arp\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
    my @lines = split(m/\n/, $before);

    my @arpentries = ();

    # ifname 192.0.2.1 0011.2233.4455 123
    my $linereg = qr/[A-z0-9\-\.]+\s([A-z0-9\-\.]+)\s
                     ([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4})/x;

    foreach my $line (@lines) {
        if ($line =~ $linereg) {

lib/App/Netdisco/SSHCollector/Platform/FTD.pm  view on Meta::CPAN

#                }
            }
            if ($ip =~ m/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) {
                push @arpentries, { mac => $mac, ip => $ip };
            }
        }
    }

    # start ipv6
    $expect->send("show ipv6 neighbor\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);

    @lines = split(m/\n/, $before);

    # IPv6 age MAC state ifname
    $linereg = qr/([0-9a-fA-F\:]+)\s+[0-9]+\s
                     ([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4})/x;

    foreach my $line (@lines) {
        if ($line =~ $linereg) {
            my ($ip, $mac) = ($1, $2);

lib/App/Netdisco/SSHCollector/Platform/FortiOS.pm  view on Meta::CPAN

of the device. C<$ssh> is a Net::OpenSSH connection to the device.

If a post-login banner needs to be accepted, please set C<$banner> to true.

Returns a list of hashrefs in the format C<< { mac => MACADDR, ip => IPADDR } >>.

=back

=cut

my $prompt = qr/ [\$#] +$/;
my $more_pattern = qr/--More--/;
my $timeout = 10;

sub get_paginated_output {
    my ($command, $expect) = @_;
    my $more_flag = 0;
    my @lines = undef;
    my @alllines = undef;
    $expect->send($command."\n");
    while (1) {
        my ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt, -re, $more_pattern);
        if ($match) {
            if ($match =~ $more_pattern) {
                $more_flag = 1;
                @lines = split(/\R/, $before);
                push(@alllines, grep {$_ =~ /\S/} @lines);
                debug("skipping through --More-- pagination");
                $expect->send(" ");
            } elsif ($match =~ $prompt) {
                $more_flag = 0;
                @lines = split(/\R/, $before);
                push(@alllines, grep {$_ =~ /\S/} @lines);
                foreach my $line (@alllines) {
                    debug("output collected: $line") if $line;
                }
                last;
            }
        }
    }

    return @alllines;
}

sub arpnip_context {
    my ($expect, $prompt, $timeout, $arpentries) = @_;

    # IPv4 ARP
    ##########

    my @data = get_paginated_output("get system arp", $expect);

    # fortigate # get system arp
    # Address           Age(min)   Hardware Addr      Interface
    # 2.6.0.5     0          00:40:46:f9:63:0f PLAY-0400
    # 1.2.9.7      2          00:30:59:bc:f6:94 DEAD-3550

lib/App/Netdisco/SSHCollector/Platform/FortiOS.pm  view on Meta::CPAN

    $expect->raw_pty(1);

    my ($pos, $error, $match, $before, $after);

    if ($args->{banner}) {
        my $banner = qr/^\(Press 'a' to accept\):/;
        ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $banner);

        $expect->send("a");
    }
    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    my @data = get_paginated_output("get system status", $expect);
    my $multi_vdom = 0;
    foreach (@data) {
        if ($_ && /^Virtual domain configuration: (multiple|split-task)$/) {
            $multi_vdom = 1;
        last;
        }
    }
    my $arpentries = [];
    if ($multi_vdom) {
        $expect->send("config global\n");
        $expect->expect($timeout, -re, $prompt);

        my @data = get_paginated_output("get system vdom-property", $expect);
        my $vdoms = [];
        foreach (@data) {
            push(@$vdoms, $1) if $_ && (/^==\s*\[\s*(\S+)\s*\]$/);
        }

        $expect->send("end\n");
        $expect->expect($timeout, -re, $prompt);

        foreach (@$vdoms) {
            $expect->send("config vdom\n");
            $expect->expect($timeout, -re, $prompt);
            $expect->send("edit $_\n");
            debug ("switched to config vdom; edit $_");
            $expect->expect($timeout, -re, $prompt);
            arpnip_context($expect, $prompt, $timeout, $arpentries);
            $expect->send("end\n");
            $expect->expect($timeout, -re, $prompt);
        }
    } else {
        arpnip_context($expect, $prompt, $timeout, $arpentries);
    }
    $expect->send("exit\n");
    $expect->soft_close();

    return @$arpentries;
}

1;

lib/App/Netdisco/SSHCollector/Platform/FreeBSD.pm  view on Meta::CPAN

    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt = qr/\$/;

    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    my $command = ($args->{arp_command} || 'arp');
    $expect->send("$command -n -a\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

    my @arpentries = ();
    my @lines = split(m/\n/, $before);

    # ? (192.0.2.1) at fe:ed:de:ad:be:ef on igb0_vlan2 expires in 658 seconds [vlan]
    my $linereg = qr/\s+\((\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\)\s+at\s+([a-fA-F0-9:]{17})\s+on/;

    foreach my $line (@lines) {
        if ($line =~ $linereg) {
            my ($ip, $mac) = ($1, $2);

lib/App/Netdisco/SSHCollector/Platform/GAIAEmbedded.pm  view on Meta::CPAN

    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt = qr/>/;

    ($pos, $error, $match, $before, $after) = $expect->expect(30, -re, $prompt);

    my $command = ($args->{arp_command} || 'arp');
    $expect->send("$command -n \n");
    ($pos, $error, $match, $before, $after) = $expect->expect(30, -re, $prompt);

    my @arpentries = ();
    my @lines = split(m/\n/, $before);

#   ? (192.168.17.178) at 5C:F9:DD:71:1F:08 [ether] on LAN1
# https://github.com/netdisco/netdisco/issues/365
    my $linereg = qr/([0-9.]+)\s+ether\s+([a-fA-F0-9:]+).+/;
    foreach my $line (@lines) {
        if ($line =~ $linereg) {
            my ($ip, $mac) = ($1, $2);

lib/App/Netdisco/SSHCollector/Platform/IOSXE.pm  view on Meta::CPAN


  my ($pty, $pid) = $ssh->open2pty;
  unless ($pty) {
    warn "unable to run remote command [$hostlabel] " . $ssh->error;
    return;
  }

  my $exp = Expect->init($pty);
  $exp->raw_pty(1);

  my $prompt  = qr/[>#]\s*$/;  # IOS-XE exec/enable prompt
  my $timeout = ($args && $args->{timeout}) ? $args->{timeout} : 30;

  my ($pos, $err, $match, $before, $after) = $exp->expect($timeout, -re => $prompt);
  unless (defined $pos) {
    info "$hostlabel $$ $purpose() unable to reach CLI prompt";
    $exp->hard_close();
    return;
  }

  # Disable paging so Expect sees complete command output
  $exp->send("terminal length 0\n");
  ($pos, $err, $match, $before, $after) = $exp->expect($timeout, -re => $prompt);

  debug "$hostlabel $$ $purpose() cli session ready";
  return ($exp, $prompt, $timeout);
}

sub _parse_vrfs {
  my ($text) = @_;
  my @vrfs;

  # "show vrf" includes a Platform iVRF section on some builds; stop before that.
  for my $line (split /\r?\n/, ($text // '')) {
    last if $line =~ /^\s*Platform iVRF Name/i;
    next if $line =~ /^\s*$/;

lib/App/Netdisco/SSHCollector/Platform/IOSXE.pm  view on Meta::CPAN

    ++$added;
  }

  return (\@entries, $added);
}

sub arpnip {
  my ($self, $hostlabel, $ssh, $args) = @_;
  debug "$hostlabel $$ arpnip()";

  my ($exp, $prompt, $timeout) = _open_expect($hostlabel, $ssh, $args, 'arpnip');
  return () unless $exp;

  my @arpentries;
  my %seen;

  # Stats are only for one end-of-run summary line
  my %stats = ( global => 0, vrf => {} );

  my ($pos, $err, $match, $before, $after);

  debug "$hostlabel $$ arpnip() collecting ARP from [global]";
  $exp->send("show ip arp\n");
  ($pos, $err, $match, $before, $after) = $exp->expect($timeout, -re => $prompt);

  my ($g_entries, $g_added) = _parse_arp($before, \%seen);
  push @arpentries, @$g_entries;
  $stats{global} += $g_added;

  # VRF enumeration; failures here should not block global ARP.
  $exp->send("show vrf\n");
  ($pos, $err, $match, $before, $after) = $exp->expect($timeout, -re => $prompt);

  my @vrfs = _parse_vrfs($before);
  debug "$hostlabel $$ arpnip() detected " . scalar(@vrfs) . " VRFs";

  for my $vrf (@vrfs) {
    debug "$hostlabel $$ arpnip() collecting ARP from [vrf:$vrf]";
    $exp->send("show ip arp vrf $vrf\n");
    ($pos, $err, $match, $before, $after) = $exp->expect($timeout, -re => $prompt);

    my ($v_entries, $v_added) = _parse_arp($before, \%seen);
    push @arpentries, @$v_entries;
    $stats{vrf}{$vrf} = ($stats{vrf}{$vrf} || 0) + $v_added;
  }

  $exp->send("exit\n");
  $exp->hard_close();

  my $total = scalar(@arpentries);

lib/App/Netdisco/SSHCollector/Platform/IOSXE.pm  view on Meta::CPAN

  }
  debug "$hostlabel $$ arpnip() summary: total=$total (" . join(', ', @parts) . ")";

  return @arpentries;
}

sub macsuck {
  my ($self, $hostlabel, $ssh, $args) = @_;
  debug "$hostlabel $$ macsuck()";

  my ($exp, $prompt, $timeout) = _open_expect($hostlabel, $ssh, $args, 'macsuck');
  return unless $exp;

  my ($pos, $err, $match, $before, $after);

  $exp->send("show mac address-table\n");
  ($pos, $err, $match, $before, $after) = $exp->expect($timeout, -re => $prompt);

  my @lines = split /\r?\n/, ($before // '');
  $exp->send("exit\n");
  $exp->hard_close();

  my $macentries = {};

  # Tolerant line match: grab VLAN + MAC + final port token
  # Handles variants with extra columns (age/secure/ntfy/etc).
  my $re_line = qr{

lib/App/Netdisco/SSHCollector/Platform/IOSXR.pm  view on Meta::CPAN

    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        warn "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt = qr/# +$/;
    my $timeout = 10;

    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    $expect->send("terminal length 0\n");
    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    $expect->send("show arp vrf all\n");
    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    my @arpentries = ();
    my @data = split(m/\n/, $before);

    foreach (@data) {
        my ($ip, $age, $mac, $state, $t, $iface) = split(/\s+/);

        if ($ip =~ m/(\d{1,3}\.){3}\d{1,3}/
            && $mac =~ m/([0-9a-f]{4}\.){2}[0-9a-f]{4}/i) {
              push(@arpentries, { ip => $ip, mac => $mac });

lib/App/Netdisco/SSHCollector/Platform/Linux.pm  view on Meta::CPAN

    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt = qr/\$/;

    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    my $command = ($args->{arp_command} || 'arp');
    $expect->send("$command -n | tail -n +2\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

    my @arpentries = ();
    my @lines = split(m/\n/, $before);

    # 192.168.1.1 ether 00:b6:aa:f5:bb:6e C eth1
    my $linereg = qr/([0-9\.]+)\s+ether\s+([a-fA-F0-9:]+)/;

    foreach my $line (@lines) {
        if ($line =~ $linereg) {
            my ($ip, $mac) = ($1, $2);

lib/App/Netdisco/SSHCollector/Platform/NXOS.pm  view on Meta::CPAN

        return ();
    }

    #$Expect::Debug = 1;
    #$Expect::Exp_Internal = 1;

    my $expect = Expect->init($pty);
    $expect->raw_pty(1);

    my ($pos, $error, $match, $before, $after);
    my $prompt = qr/# +$/;
    my $timeout = 10;

    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    # we filter on the : in Age as the output header of the command may contain prompt chars, e.g.
    # Flags:   # - Adjacencies Throttled for Glean
    $expect->send("show ip arp vrf all | inc ^[1-9] | no-more\n");
    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    my @arpentries;
    my @data = split(/\R/, $before);

    #IP ARP Table for all contexts
    #Total number of entries: 5
    #Address         Age       MAC Address     Interface
    #192.168.228.1   00:00:43  0000.abcd.1111  mgmt0
    #192.168.228.9   00:05:24  cccc.7777.1b1b  mgmt0

    foreach (@data) {
        my ($ip, $age, $mac, $iface) = split(/\s+/);

        if ($ip && $ip =~ m/(\d{1,3}\.){3}\d{1,3}/
            && $mac =~ m/([0-9a-f]{4}\.){2}[0-9a-f]{4}/i) {
              push(@arpentries, { ip => $ip, mac => $mac });
        }
    }

    $expect->send("show ipv6 neighbor vrf all | exclude Flags: | no-more\n");
    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    my @data6 = split(/\R/, $before);

    #IPv6 neighbors use this two-line format
    #IPv6 Adjacency Table for all VRFs
    #Total number of entries: 65
    #Address         Age       MAC Address     Pref Source     Interface
    #bff:a90:c405:120::3
    #                00:01:46  5c71.0d42.df3f  50   icmpv6     Vlan376
    #bff:a90:c405:120::52

lib/App/Netdisco/SSHCollector/Platform/NXOS.pm  view on Meta::CPAN

        return ();
    }

    #$Expect::Debug = 1;
    #$Expect::Exp_Internal = 1;

    my $expect = Expect->init($pty);
    $expect->raw_pty(1);

    my ($pos, $error, $match, $before, $after);
    my $prompt = qr/# +$/;
    my $timeout = 10;

    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    #    IP Route Table for VRF "xyz"
    #'*' denotes best ucast next-hop
    #'**' denotes best mcast next-hop
    #'[x/y]' denotes [preference/metric]
    #'%<string>' in via output denotes VRF <string>
    #
    #0.0.0.0/0, ubest/mbest: 1/0 time
    #    *via 10.255.254.17, [1/0], 7w1d, static
    #10.1.1.0/24, ubest/mbest: 1/0 time, attached
    #    *via 10.1.1.2, Vlan1234, [0/0], 1y13w, direct
    #10.1.1.1/32, ubest/mbest: 1/0 time, attached
    #    *via 10.1.1.1, Vlan1234, [0/0], 1y13w, hsrp

    # include only lines with "attached" and exclude /32 subnets
    $expect->send("show ip route vrf all | inc attached | exc /32 | no-more \n");
    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    my @subnets;
    my @data = split(/\R/, $before);
    foreach (@data) {
        # subnet cidr is the first part before the comma and space
        my ($cidr, $rest) = split(/,\s+/);
        if ($cidr && $cidr =~ m/(\d{1,3}\.){3}\d{1,3}\/\d{1,2}/) {
              push(@subnets, $cidr);
        }
    }

lib/App/Netdisco/SSHCollector/Platform/OS10.pm  view on Meta::CPAN

        return ();
    }

    # $Expect::Debug = 1;
    # $Expect::Exp_Internal = 1;

    my $expect = Expect->init($pty);
    $expect->raw_pty(1);

    my ($pos, $error, $match, $before, $after);
    my $prompt = qr/# +$/;
    my $timeout = 60;

    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);

    # Get all VRFs, skip header line
    $expect->send("show ip vrf | except VRF-Name | no-more \n");
    ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);
    my @vrfs = split(/\R/, $before);

    # Regex for VRF name
    my $vrf_re = qr/^([a-z\-_0-9\.]+)\s+.+$/i;

    # IP ARP match
    my $iparp_re = qr/^((\d{1,3}\.){3}\d{1,3})\s*(([0-9a-f]{2}[:-]){5}[0-9a-f]{2})\s+.+$/i;

    # Will hold results
    my @arpentries;

lib/App/Netdisco/SSHCollector/Platform/OS10.pm  view on Meta::CPAN

        my $vrf_name ;
        # Get the VRF name
        if ($vrf_line && $vrf_line =~ m/$vrf_re/) {
            $vrf_name = $1;
        } else {
            next ;
        }
        # Get IP ARP entries for this VRF
        my $vrf_cmd = sprintf("show ip arp vrf %s | no-more \n", $vrf_name) ;
        $expect->send($vrf_cmd);
        ($pos, $error, $match, $before, $after) = $expect->expect($timeout, -re, $prompt);
        my @iparps = split(/\R/, $before);

        foreach my $iparp_line (@iparps) {
            if($iparp_line && $iparp_line =~ m/$iparp_re/) {
                push(@arpentries, { ip => $1, mac => $3 });
            }
        }
    }

    return @arpentries;

lib/App/Netdisco/SSHCollector/Platform/PaloAlto.pm  view on Meta::CPAN


    debug "$hostlabel $$ arpnip()";

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);
    my ($pos, $error, $match, $before, $after);
    my $prompt = qr/> \r?$/;

    ($pos, $error, $match, $before, $after) = $expect->expect(20, -re, $prompt);
    $expect->send("set cli scripting-mode on\n");

    # The PAN cli echos stuff back at us, causing us to see the prompt 3 extra times.
    # Fortunately, the previous command disables this, so we only deal with it once.
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    $expect->send("show arp all\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);

    my @arpentries;
    for (split(/\r\n/, $before)){
        next unless $_ =~ m/(\d{1,3}\.){3}\d{1,3}/;
        my ($tmp, $ip, $mac) = split(/\s+/);
        if ($ip =~ m/(\d{1,3}\.){3}\d{1,3}/ && $mac =~ m/([0-9a-f]{2}:){5}[0-9a-f]{2}/i) {
             push(@arpentries, { ip => $ip, mac => $mac });
        }
    }

    $expect->send("show neighbor interface all\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
    for (split(/\r\n/, $before)){
        next unless $_ =~ m/([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}/;
        my ($tmp, $ip, $mac) = split(/\s+/);
        if ($ip =~ m/([0-9a-f]{0,4}:){2,7}[0-9a-f]{0,4}/ && $mac =~ m/([0-9a-f]{2}:){5}[0-9a-f]{2}/i) {
             push(@arpentries, { ip => $ip, mac => $mac });
        }
    }
    $expect->send("exit\n");
    $expect->soft_close();

lib/App/Netdisco/SSHCollector/Platform/VOSS.pm  view on Meta::CPAN

    }

    my ($pty, $pid) = $ssh->open2pty;
    unless ($pty) {
        debug "unable to run remote command [$hostlabel] " . $ssh->error;
        return ();
    }
    my $expect = Expect->init($pty);

    my ($pos, $error, $match, $before, $after);
    my $prompt;

    $prompt = qr/>/;
    ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt);
    
    $expect->send("terminal more disable\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt);

    if ($before =~ m/% Invalid input detected/) {
        debug "invalid command [$hostlabel]";
        return ();
    }

    $expect->send("show ip arp vrfids $vrflist\n");
    ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt);
    my @lines = split(m/\n/, $before);

    if ($before =~ m/% Invalid input detected/) {
        debug "invalid command [$hostlabel]";
        return ();
    }

    if ($before =~ m/Error : ([^\n]+)/) {
        my $errormsg = $1;
        if ($errormsg =~ m/Invalid VRF ID/ || $errormsg =~ m/vrfId should be/) {

share/contrib/raddb/dictionary.cisco  view on Meta::CPAN


VENDOR		Cisco		9

#
#	Attributes Sent ftom Radius Server to the Voice Gateway
#
ATTRIBUTE	h323-ivr-in			1	avpair		Cisco
ATTRIBUTE       h323-credit-amount		101	avpair		Cisco
ATTRIBUTE       h323-credit-time		102	avpair		Cisco
ATTRIBUTE       h323-return-code		103	avpair		Cisco
ATTRIBUTE       h323-prompt-id			104	avpair		Cisco
ATTRIBUTE       h323-time-and-day		105	avpair		Cisco
ATTRIBUTE       h323-redirect-number		106	avpair		Cisco
ATTRIBUTE       h323-preferred-lang		107	avpair		Cisco
ATTRIBUTE       h323-redirect-ip-address	108	avpair		Cisco
ATTRIBUTE       h323-billing-model		109	avpair		Cisco
ATTRIBUTE       h323-currency			110	avpair		Cisco

#
#	Extra voice attributes sent by the Cisco, if you configure
#	"radius-server vsa accounting" (requires IOS11.2+ for non-VoIP

share/contrib/raddb/dictionary.quintum  view on Meta::CPAN


VENDOR		Quintum		6618

#
#	Attributes Sent ftom Radius Server to the Voice Gateway
#
ATTRIBUTE	h323-ivr-in			1	avpair		Quintum
ATTRIBUTE       h323-credit-amount		101	avpair		Quintum
ATTRIBUTE       h323-credit-time		102	avpair		Quintum
ATTRIBUTE       h323-return-code		103	avpair		Quintum
ATTRIBUTE       h323-prompt-id			104	avpair		Quintum
ATTRIBUTE       h323-time-and-day		105	avpair		Quintum
ATTRIBUTE       h323-redirect-number		106	avpair		Quintum
ATTRIBUTE       h323-preferred-lang		107	avpair		Quintum
ATTRIBUTE       h323-redirect-ip-address	108	avpair		Quintum
ATTRIBUTE       h323-billing-model		109	avpair		Quintum
ATTRIBUTE       h323-currency			110	avpair		Quintum

#
#	Extra voice attributes sent by the Cisco, if you configure
#	"radius-server vsa accounting" (requires IOS11.2+ for non-VoIP

share/contrib/raddb/dictionary.usr  view on Meta::CPAN

VALUE	USR-Connect-Term-Reason	v42BadSetup			28
VALUE	USR-Connect-Term-Reason	v42InvalidCodeWord		29
VALUE	USR-Connect-Term-Reason	v42StringToLong			30
VALUE	USR-Connect-Term-Reason	v42InvalidCommand		31
VALUE	USR-Connect-Term-Reason	none				32	
VALUE	USR-Connect-Term-Reason	v32Cleardown			33
VALUE	USR-Connect-Term-Reason	dialSecurity			34
VALUE	USR-Connect-Term-Reason	remoteAccessDenied		35
VALUE	USR-Connect-Term-Reason	loopLoss			36
VALUE	USR-Connect-Term-Reason	ds0Teardown			37
VALUE	USR-Connect-Term-Reason	promptNotEnabled		38
VALUE	USR-Connect-Term-Reason	noPromptingInSync		39
VALUE	USR-Connect-Term-Reason	nonArqMode			40
VALUE	USR-Connect-Term-Reason	modeIncompatible		41
VALUE	USR-Connect-Term-Reason	noPromptInNonARQ		42
VALUE	USR-Connect-Term-Reason	dialBackLink			43
VALUE	USR-Connect-Term-Reason	linkAbort			44
VALUE	USR-Connect-Term-Reason	autopassFailed			45
VALUE	USR-Connect-Term-Reason	pbGenericError			46
VALUE	USR-Connect-Term-Reason	pbLinkErrTxPreAck		47
VALUE	USR-Connect-Term-Reason	pbLinkErrTxTardyACK		48

share/contrib/raddb/dictionary.usr  view on Meta::CPAN

VALUE	USR-Failure-to-Connect-Reason	v42BadSetup		28
VALUE	USR-Failure-to-Connect-Reason	v42InvalidCodeWord	29
VALUE	USR-Failure-to-Connect-Reason	v42StringToLong		30
VALUE	USR-Failure-to-Connect-Reason	v42InvalidCommand	31
VALUE	USR-Failure-to-Connect-Reason	none			32	
VALUE	USR-Failure-to-Connect-Reason	v32Cleardown		33
VALUE	USR-Failure-to-Connect-Reason	dialSecurity		34
VALUE	USR-Failure-to-Connect-Reason	remoteAccessDenied	35
VALUE	USR-Failure-to-Connect-Reason	loopLoss		36
VALUE	USR-Failure-to-Connect-Reason	ds0Teardown		37
VALUE	USR-Failure-to-Connect-Reason	promptNotEnabled	38
VALUE	USR-Failure-to-Connect-Reason	noPromptingInSync	39
VALUE	USR-Failure-to-Connect-Reason	nonArqMode		40
VALUE	USR-Failure-to-Connect-Reason	modeIncompatible	41
VALUE	USR-Failure-to-Connect-Reason	noPromptInNonARQ	42
VALUE	USR-Failure-to-Connect-Reason	dialBackLink		43
VALUE	USR-Failure-to-Connect-Reason	linkAbort		44
VALUE	USR-Failure-to-Connect-Reason	autopassFailed		45
VALUE	USR-Failure-to-Connect-Reason	pbGenericError		46
VALUE	USR-Failure-to-Connect-Reason	pbLinkErrTxPreAck	47
VALUE	USR-Failure-to-Connect-Reason	pbLinkErrTxTardyACK	48



( run in 1.865 second using v1.01-cache-2.11-cpan-6aa56a78535 )