1package App::Netdisco::SSHCollector::Platform::ASA; 2 3=head1 NAME 4 5App::Netdisco::SSHCollector::Platform::ASA 6 7=head1 DESCRIPTION 8 9Collect IPv4 ARP and IPv6 neighbor entries from Cisco ASA devices. 10 11You will need the following configuration for the user to automatically enter 12C<enable> status after login: 13 14 aaa authorization exec LOCAL auto-enable 15 16To use an C<enable> password separate from the login password, add an 17C<enable_password> under C<device_auth> tag in your configuration file: 18 19 device_auth: 20 - tag: sshasa 21 driver: cli 22 platform: ASA 23 only: '192.0.2.1' 24 username: oliver 25 password: letmein 26 enable_password: myenablepass 27 28=cut 29 30use strict; 31use warnings; 32 33use Dancer ':script'; 34use Expect; 35use Moo; 36 37=head1 PUBLIC METHODS 38 39=over 4 40 41=item B<arpnip($host, $ssh)> 42 43Retrieve ARP and neighbor entries from device. C<$host> is the hostname or IP 44address of the device. C<$ssh> is a Net::OpenSSH connection to the device. 45 46Returns a list of hashrefs in the format C<{ mac =E<gt> MACADDR, ip =E<gt> IPADDR }>. 47 48=back 49 50=cut 51 52sub arpnip { 53 my ($self, $hostlabel, $ssh, $args) = @_; 54 55 debug "$hostlabel $$ arpnip()"; 56 57 my ($pty, $pid) = $ssh->open2pty; 58 unless ($pty) { 59 debug "unable to run remote command [$hostlabel] " . $ssh->error; 60 return (); 61 } 62 my $expect = Expect->init($pty); 63 64 my ($pos, $error, $match, $before, $after); 65 my $prompt; 66 67 if ($args->{enable_password}) { 68 $prompt = qr/>/; 69 ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt); 70 71 $expect->send("enable\n"); 72 73 $prompt = qr/Password:/; 74 ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt); 75 76 $expect->send( $args->{enable_password} ."\n" ); 77 } 78 79 $prompt = qr/#\s*$/; 80 ($pos, $error, $match, $before, $after) = $expect->expect(10, -re, $prompt); 81 82 $expect->send("terminal pager 2147483647\n"); 83 ($pos, $error, $match, $before, $after) = $expect->expect(5, -re, $prompt); 84 85 $expect->send("show names\n"); 86 ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt); 87 my @names = split(m/\n/, $before); 88 89 $expect->send("show arp\n"); 90 ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt); 91 my @lines = split(m/\n/, $before); 92 93 my @arpentries = (); 94 95 # ifname 192.0.2.1 0011.2233.4455 123 96 my $linereg = qr/[A-z0-9\-\.]+\s([A-z0-9\-\.]+)\s 97 ([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4})/x; 98 99 foreach my $line (@lines) { 100 if ($line =~ $linereg) { 101 my ($ip, $mac) = ($1, $2); 102 if ($ip !~ m/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) { 103 foreach my $name (@names) { 104 if ($name =~ qr/name\s([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\s([\w-]*)/x) { 105 if ($ip eq $2) { 106 $ip = $1; 107 } 108 } 109 } 110 } 111 if ($ip =~ m/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) { 112 push @arpentries, { mac => $mac, ip => $ip }; 113 } 114 } 115 } 116 117 # start ipv6 118 $expect->send("show ipv6 neighbor\n"); 119 ($pos, $error, $match, $before, $after) = $expect->expect(60, -re, $prompt); 120 121 @lines = split(m/\n/, $before); 122 123 # IPv6 age MAC state ifname 124 $linereg = qr/([0-9a-fA-F\:]+)\s+[0-9]+\s 125 ([0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4})/x; 126 127 foreach my $line (@lines) { 128 if ($line =~ $linereg) { 129 my ($ip, $mac) = ($1, $2); 130 push @arpentries, { mac => $mac, ip => $ip }; 131 } 132 } 133 # end ipv6 134 135 $expect->send("exit\n"); 136 $expect->soft_close(); 137 138 return @arpentries; 139} 140 1411; 142