From ebdff809d43b8ef0be4fdeb8a5e923b967343ff9 Mon Sep 17 00:00:00 2001 From: Christian Ramseyer Date: Fri, 30 Sep 2022 15:00:02 +0200 Subject: [PATCH] add FTD.pm contributed by Sebastian Roesch --- Changes | 7 + lib/App/Netdisco.pm | 3 +- lib/App/Netdisco/SSHCollector/Platform/FTD.pm | 141 ++++++++++++++++++ 3 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 lib/App/Netdisco/SSHCollector/Platform/FTD.pm diff --git a/Changes b/Changes index c866a998..aac0c78e 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,10 @@ +2.057006 - tbd + + [ENHANCEMENTS] + + * added Firepower SSH collector (FTD.pm) contributed by Sebastian Roesch (roesch[at]alcera.de) on the mailing list + + 2.057005 - 2022-09-28 [BUG FIXES] diff --git a/lib/App/Netdisco.pm b/lib/App/Netdisco.pm index 184f0eb4..3cc616ee 100644 --- a/lib/App/Netdisco.pm +++ b/lib/App/Netdisco.pm @@ -341,7 +341,8 @@ of Waikato, Hamilton NZ), Dusty Hall (Auburn U), Jon Monroe (center pointe), Alexander Barthel, Bill Anderson, Alexander Hartmaier (t-systems.at), Justin Hunter (Arizona State U), Jethro Binks (U of Strathclyde, Glasgow), Jordi Guijarro (UAB.es), Sam Stickland (spacething.org), Stefan Radman (CTBTO.org), -Clint Wise, Max Kosmach, Bernhard Augenstein and Nick Nauwelaerts (aquafin.be). +Clint Wise, Max Kosmach, Bernhard Augenstein, Sebastian Roesch and Nick +Nauwelaerts (aquafin.be). We probably forgot some names - sorry about that :-(. diff --git a/lib/App/Netdisco/SSHCollector/Platform/FTD.pm b/lib/App/Netdisco/SSHCollector/Platform/FTD.pm new file mode 100644 index 00000000..4c594ac5 --- /dev/null +++ b/lib/App/Netdisco/SSHCollector/Platform/FTD.pm @@ -0,0 +1,141 @@ +package App::Netdisco::SSHCollector::Platform::FTD; + +=head1 NAME + +App::Netdisco::SSHCollector::Platform::FTD + +=head1 DESCRIPTION + +Collect IPv4 ARP and IPv6 neighbor entries from Cisco Firepower devices. + +You will need the following configuration for the user to automatically enter +C status after login: + + aaa authorization exec LOCAL auto-enable + +To use an C password separate from the login password, add an +C under C tag in your configuration file: + + device_auth: + - tag: sshftd + driver: cli + platform: FTD + only: '192.0.2.1' + username: oliver + password: letmein + enable_password: myenablepass + +=cut + +use strict; +use warnings; + +use Dancer ':script'; +use Expect; +use Moo; + +=head1 PUBLIC METHODS + +=over 4 + +=item B + +Retrieve ARP and neighbor entries from device. C<$host> is the hostname or IP +address of the device. C<$ssh> is a Net::OpenSSH connection to the device. + +Returns a list of hashrefs in the format C<{ mac =E MACADDR, ip =E IPADDR }>. + +=back + +=cut + +sub arpnip { + my ($self, $hostlabel, $ssh, $args) = @_; + + 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) { + my ($ip, $mac) = ($1, $2); + if ($ip !~ m/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/) { +# foreach my $name (@names) { +# if ($name =~ qr/name\s([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})\s([\w-]*)/x) { +# if ($ip eq $2) { +# $ip = $1; +# } +# } +# } + } + 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); + push @arpentries, { mac => $mac, ip => $ip }; + } + } + # end ipv6 + + $expect->send("exit\n"); + $expect->soft_close(); + + return @arpentries; +} + +1;