From 1abc3043a2ded4596554fdd61cb33ba2f54308f2 Mon Sep 17 00:00:00 2001 From: veorlo Date: Thu, 13 Feb 2025 21:58:38 +0000 Subject: [PATCH] Debugging and cleanup before modern OS releases --- Dockerfile | 2 +- README.md | 1 - conf/logging.conf | 14 +- grnoc-routerproxy.spec | 12 +- lib/GRNOC/RouterProxy.pm | 1938 ++++++++++++++----------------- lib/GRNOC/RouterProxy/Config.pm | 9 +- lib/GRNOC/RouterProxy/Logger.pm | 71 +- webroot/index.cgi | 1099 ++++++++---------- 8 files changed, 1378 insertions(+), 1768 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2d07e7c..560cb59 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,7 +7,7 @@ COPY conf/globalnoc-public-el7.repo /etc/yum.repos.d/globalnoc-public-el7.repo RUN yum makecache RUN yum -y install epel-release -RUN yum -y install perl-Template-Toolkit perl-XML-Parser perl-XML-Simple perl-CGI-Ajax perl-Time-ParseDate perl-Net-Telnet perl-Expect perl-GRNOC-TL1 perl-GRNOC-Config perl-Class-Accessor perl-YAML perl-JSON perl-Log-Log4perl +RUN yum -y install perl-Template-Toolkit perl-XML-Parser perl-XML-Simple perl-CGI perl-Time-ParseDate perl-Net-Telnet perl-Expect perl-GRNOC-TL1 perl-GRNOC-Config perl-Class-Accessor perl-YAML perl-JSON perl-Log-Log4perl RUN yum -y install perl-GRNOC-WebService perl-GRNOC-WebService-Client perl-Test-Deep perl-Test-Exception perl-Test-Pod perl-Test-Pod-Coverage perl-Devel-Cover perl-Data-Dumper perl-Test-Harness perl-Test-Simple openssh-clients COPY conf/routerproxy.conf /etc/httpd/conf.d/routerproxy.conf diff --git a/README.md b/README.md index bde08ed..b1bf161 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,6 @@ Perl modules need to be installed as well (generally easily done with cpan). (NOTE: This is now only required for the menu based commands.. if you don't have it installed, RouterProxy will still work). * CGI -* CGI::Ajax * XML::Simple * Encode * Expect diff --git a/conf/logging.conf b/conf/logging.conf index 065be51..752a2aa 100644 --- a/conf/logging.conf +++ b/conf/logging.conf @@ -1,15 +1,11 @@ -log4perl.logger.GRNOC.RouterProxy = INFO, Screen -log4perl.logger.GRNOC.RouterProxy.Generator = INFO, Screen -log4perl.logger = DEBUG, Screen +log4perl.logger.GRNOC.RouterProxy = INFO, SYSLOG +log4perl.logger.GRNOC.RouterProxy.Generator = INFO, SYSLOG +log4perl.logger = DEBUG, SYSLOG -# Logs against only the most specific category +# Only log one line (prevents duplicate logging) log4perl.oneMessagePerAppender = 1 -log4perl.appender.Screen = Log::Log4perl::Appender::Screen -log4perl.appender.Screen.stderr = 0 -log4perl.appender.Screen.layout = Log::Log4perl::Layout::SimpleLayout - log4perl.appender.SYSLOG = Log::Dispatch::Syslog log4perl.appender.SYSLOG.facility = LOCAL0 log4perl.appender.SYSLOG.layout = PatternLayout -log4perl.appender.SYSLOG.layout.ConversionPattern=[%d] %p %F %L %c - %m%n +log4perl.appender.SYSLOG.layout.ConversionPattern=[%p] %l: %m%n diff --git a/grnoc-routerproxy.spec b/grnoc-routerproxy.spec index 4c23184..821f946 100644 --- a/grnoc-routerproxy.spec +++ b/grnoc-routerproxy.spec @@ -1,6 +1,6 @@ Summary: GRNOC Router Proxy Name: grnoc-routerproxy -Version: 2.3.2 +Version: 2.4.0 Release: %{_buildno}%{?dist} License: GRNOC Group: Auth @@ -14,7 +14,7 @@ Requires: perl >= 5.8.8 Requires: perl-Template-Toolkit Requires: perl(XML::Parser) Requires: perl(XML::Simple) -Requires: perl(CGI::Ajax) +Requires: perl(CGI) Requires: perl(Time::ParseDate) Requires: perl(Net::Telnet) Requires: perl(Expect) @@ -26,7 +26,9 @@ Requires: perl(JSON) Requires: perl(Log::Log4perl) Provides: perl(GRNOC::RouterProxy) -Provides: perl(GRNOC::RouterProxy::Commands), perl(GRNOC::RouterProxy::Config), perl(GRNOC::RouterProxy::Logger) +Provides: perl(GRNOC::RouterProxy::Commands) +Provides: perl(GRNOC::RouterProxy::Config) +Provides: perl(GRNOC::RouterProxy::Logger) BuildRequires: tar AutoReqProv: no @@ -47,6 +49,8 @@ rm -rf $RPM_BUILD_ROOT %{__install} conf/routerproxy.yaml %{buildroot}%{_sysconfdir}/grnoc/routerproxy/ %{__install} conf/logging.conf %{buildroot}%{_sysconfdir}/grnoc/routerproxy/ +%{__install} -d -p %{buildroot}/var/log/grnoc/routerproxy/ + %{__install} -d -p %{buildroot}%{_sysconfdir}/httpd/conf.d/grnoc/ %{__install} conf/routerproxy.conf %{buildroot}%{_sysconfdir}/httpd/conf.d/grnoc/ @@ -90,9 +94,11 @@ rm -rf $RPM_BUILD_ROOT %defattr(754,apache,apache,-) %{_datadir}/grnoc/routerproxy/www/index.cgi %{_datadir}/grnoc/routerproxy/www/routerproxy.js + %defattr(644,root,apache,-) %config(noreplace) %{_datadir}/grnoc/routerproxy/www/style.css %{_datadir}/grnoc/routerproxy/templates/index.tt %attr(755,apache,apache) %dir %{_datadir}/grnoc/routerproxy/.ssh/ +%attr(755,apache,apache) %dir /var/log/grnoc/routerproxy/ diff --git a/lib/GRNOC/RouterProxy.pm b/lib/GRNOC/RouterProxy.pm index e9b6a8a..4e50951 100644 --- a/lib/GRNOC/RouterProxy.pm +++ b/lib/GRNOC/RouterProxy.pm @@ -1,26 +1,12 @@ package GRNOC::RouterProxy; +our $VERSION = '2.4.0'; use strict; +use warnings; -use Net::Telnet; use Expect; - -# gots junoscript? -my $hasJunoscript; -BEGIN { - - eval { - require JUNOS::Device; - }; - if ($@) { - $hasJunoscript = 0; - } - else { - $hasJunoscript = 1; - JUNOS::Device->import; - } -} - +use Net::Telnet; +use Log::Log4perl; use Data::Dumper; use GRNOC::Config; @@ -33,425 +19,381 @@ use GRNOC::TL1::Device::Ciena::CoreDirector; use GRNOC::RouterProxy::Config; my $timeout = 0; +my $hasJunoscript; -our $VERSION = '2.3.2'; -sub new { - - my $caller = shift; - my $class = ref($caller) || $caller; - - my $self = { - username => 'username', - password => 'password', - type => 'junos', - method => 'ssh', - junoscript => '0', - iosxml => '0', - hostname => 'hostname', - port => '23', - maxlines => '5000', - timeout => '60', - debug => '0', - @_ - }; - - bless($self, $class); +Log::Log4perl::init('/etc/grnoc/routerproxy/logging.conf'); +my $logger = Log::Log4perl->get_logger('GRNOC.RouterProxy'); - return $self; +BEGIN { + eval { + require JUNOS::Device; + }; + if ($@) { + $hasJunoscript = 0; + } + else { + $hasJunoscript = 1; + JUNOS::Device->import; + } } -sub command { - - my ($self) = @_; - shift; - my $command = shift; - - if ($self->{type} eq "ome" || $self->{type} eq "hdxc" || $self->{type} eq "ons15454" || $self->{type} eq "ciena") { - - my $tl1 = GRNOC::TL1->new( - username => $self->{username}, - password => $self->{password}, - type => $self->{type}, - host => $self->{hostname}, - port => $self->{port}, - ctag => 1337); - $tl1->connect(); - $tl1->login(); - - my $result = $tl1->cmd($command); - $result =~ s/ / /g; - $result =~ s//>/g; - #$result =~ s/\n/
/g; - - $result = $self->sanitize_text($result); - return $result; - } - - elsif ($self->{type} eq "iosxr" && $self->{method} eq "ssh") { - - my $result = &iosxrSSH($self, $command); - - $result =~ s/ / /g; - $result =~ s//>/g; - #$result =~ s/\n/
/g; - - return $result; - } - - elsif ($self->{type} eq "hp" && $self->{method} eq "ssh") { - - my $result = &hpSSH($self, $command); - - $result =~ s/ / /g; - $result =~ s//>/g; - #$result =~ s/\n/
/g; - - $result = $self->sanitize_text($result); - return $result; - } - elsif (($self->{type} eq "ios2" || $self->{type} eq "ios" || $self->{type} eq "ios6509" || $self->{type} eq "nx-os" || $self->{type} eq 'brocade') && $self->{method} eq "ssh") { - - my $result = &ios2SSH($self, $command); - - $result =~ s/ / /g; - $result =~ s//>/g; - #$result =~ s/\n/
/g; - - $result = $self->sanitize_text($result); - return $result; - } - - elsif ($self->{type} eq "ios2" && $self->{method} eq "telnet") { - - my $result = &ios2Telnet($self, $command); +sub new { + my $caller = shift; + my $class = ref($caller) || $caller; + + my $self = { + username => 'username', + password => 'password', + type => 'junos', + method => 'ssh', + junoscript => '0', + iosxml => '0', + hostname => 'hostname', + port => '23', + maxlines => '5000', + timeout => '60', + debug => '0', + @_ + }; - $result =~ s/ / /g; - $result =~ s//>/g; - #$result =~ s/\n/
/g; + bless($self, $class); + return $self; +} - $result = $self->sanitize_text($result); - return $result; - } - elsif ($self->{type} eq "force10" && $self->{method} eq "ssh") { +#ISSUE=12307 Remove sensitive information, as specified in the config file, from any output +sub sanitize_text { + my $self = shift; + my $text = shift; - my $result = &force10SSH($self, $command); + my $conf = GRNOC::RouterProxy::Config->new($self->{'config_path'}); + my $stanzas = $conf->Redacts(); - #$result =~ s/\t/     /g; - $result =~ s/ / /g; - $result =~ s//>/g; - #$result =~ s/\n/
/g; - - $result = $self->sanitize_text($result); - return $result; - } - - elsif ($self->{type} eq "bladeOS" && $self->{method} eq "ssh") { - - my $result = &bladeOS($self, $command); - - #$result =~ s/\t/     /g; - $result =~ s/ / /g; - $result =~ s//>/g; - #$result =~ s/\n/
/g; - - $result = $self->sanitize_text($result); - return $result; - } - - elsif ($self->{type} eq "junos" && $self->{method} eq "ssh") { + foreach my $stanza ( @$stanzas ) { + $stanza =~ s/ / \;/g; + $stanza =~ s/(?/>\;/g; + $text =~ s/$stanza/\[REDACTED\]/g; + } + return $text; +} - my $result = &junosSSH($self, $command); +# Helper to swap chars for HTML codes and sanitize result strings +sub clean_result { + my $self = shift; + my $result = shift; + my $sanitize = shift || 1; $result =~ s/ / /g; $result =~ s//>/g; - #$result =~ s/\n/
/g; + $result = $self->sanitize_text($result) if $sanitize; + return $result +} - $result = $self->sanitize_text($result); - return $result; - } +sub blankPrompt { + my $string = shift; - elsif ($self->{type} eq "arista" && $self->{method} eq "ssh") { + # pull out the first line + my $line = substr($string, 0, index($string, "\n")); - my $result = &aristaSSH($self, $command); + # find the first > + my $index = index($line, '>'); - $result =~ s/ / /g; - $result =~ s//>/g; - #$result =~ s/\n/
/g; + # otherwise find the first # + $index = index($line, '#') if ($index < 0); - return $result; - } + # get the prompt (user at host) + my $prompt = substr($string, 0, $index + 1); - elsif ($self->{method} eq "ssh") { + # replace each char with a space + $prompt =~ s/#/>/; + $prompt =~ s/[^>]/\./g; - my $result; - # using junoscript? - if ($self->{junoscript} eq "1") { + # get everything after the prompt + $string = substr($string, $index + 1); - if (!$hasJunoscript) { + # reattach our blanked out prompt to the rest of the string + $string = $prompt . $string; - $result = "Junoscript must be installed."; - } - - else { - - my %info = ( - access => "ssh", - login => $self->{username}, - password => $self->{password}, - hostname => $self->{hostname}); + return $string; +} - my $junos = new JUNOS::Device(%info); - $result = $junos->command($command)->toString; - $result =~ s/junos://g; - } - $result = $self->sanitize_text($result); - return $result; +sub command { + my ($self) = @_; + shift; + my $command = shift; + + $logger->info("Issuing command '$command' on $self->{'hostname'}"); + + if ($self->{'type'} eq "ome" || $self->{'type'} eq "hdxc" || $self->{'type'} eq "ons15454" || $self->{'type'} eq "ciena") { + my $tl1 = GRNOC::TL1->new( + username => $self->{'username'}, + password => $self->{'password'}, + type => $self->{'type'}, + host => $self->{'hostname'}, + port => $self->{'port'}, + ctag => 1337 + ); + $tl1->connect(); + $tl1->login(); + + my $result = $tl1->cmd($command); + return $self->clean_result($result); } - else { - - return "Unsupported connection type"; + elsif ($self->{'type'} eq "iosxr" && $self->{'method'} eq "ssh") { + my $result = &iosxrSSH($self, $command); + return $self->clean_result($result, 0); } - } - elsif ($self->{method} eq "telnet") { + elsif ($self->{'type'} eq "hp" && $self->{'method'} eq "ssh") { + my $result = &hpSSH($self, $command); + return $self->clean_result($result); + } - my $buf; - my $prompt; + elsif (($self->{'type'} eq "ios2" || $self->{'type'} eq "ios" || $self->{'type'} eq "ios6509" || $self->{'type'} eq "nx-os" || $self->{'type'} eq 'brocade') && $self->{'method'} eq "ssh") { + my $result = &ios2SSH($self, $command); + return $self->clean_result($result); + } - # default port 23 - my $port = $self->{port}; + elsif ($self->{'type'} eq "ios2" && $self->{'method'} eq "telnet") { + my $result = &ios2Telnet($self, $command); + return $self->clean_result($result); + } - if ($port eq "") { - $port = "23"; + elsif ($self->{'type'} eq "force10" && $self->{'method'} eq "ssh") { + my $result = &force10SSH($self, $command); + return $self->clean_result($result); } - my $telnet = Net::Telnet->new(Timeout => 1, Errmode => 'return', Port => $port); - my $result = $telnet->open($self->{hostname}); - if (!$result) { - die($telnet->errmsg()); + elsif ($self->{'type'} eq "bladeOS" && $self->{'method'} eq "ssh") { + my $result = &bladeOS($self, $command); + return $self->clean_result($result); + } + + elsif ($self->{'type'} eq "junos" && $self->{'method'} eq "ssh") { + my $result = &junosSSH($self, $command); + return $self->clean_result($result); } - # JunOS login - if ($self->{type} eq "junos") { + elsif ($self->{'type'} eq "arista" && $self->{'method'} eq "ssh") { + my $result = &aristaSSH($self, $command); + return $self->clean_result($result, 0); + } - # junoscript? - if ($self->{junoscript} eq "1") { + elsif ($self->{'method'} eq "ssh") { + return "Unsupported connection type" if ($self->{'junoscript'} ne "1"); + my $result; if (!$hasJunoscript) { - - $result = "Junoscript must be installed."; + $result = "Junoscript must be installed"; } else { - my %info = ( - access => "telnet", - login => $self->{username}, - password => $self->{password}, - hostname => $self->{hostname}); - - my $junos = new JUNOS::Device(%info); - my $result = $junos->command($command)->toString; - $result =~ s/junos://g; + my %info = ( + access => "ssh", + login => $self->{'username'}, + password => $self->{'password'}, + hostname => $self->{'hostname'} + ); + my $junos = new JUNOS::Device(%info); + $result = $junos->command($command)->toString; + $result =~ s/junos://g; } - $result = $self->sanitize_text($result); return $result; - } - else { + } - my $result = $telnet->login($self->{username}, $self->{password}); - if (!$result) { - die($telnet->errmsg()); + elsif ($self->{'method'} eq "telnet") { + my $buf; + my $prompt; + + my $port = $self->{'port'} || "23"; # Default port 23 + my $telnet = Net::Telnet->new( + Timeout => 1, + Errmode => 'return', + Port => $port + ); + my $result = $telnet->open($self->{'hostname'}); + die($telnet->errmsg()) unless $result; + + # JunOS login + if ($self->{'type'} eq "junos") { + if ($self->{'junoscript'} eq "1") { + if (!$hasJunoscript) { + $result = "Junoscript must be installed"; + } + else { + my %info = ( + access => "telnet", + login => $self->{'username'}, + password => $self->{'password'}, + hostname => $self->{'hostname'} + ); + my $junos = new JUNOS::Device(%info); + my $result = $junos->command($command)->toString; + $result =~ s/junos://g; + } + $result = $self->sanitize_text($result); + return $result; + } + else { + my $result = $telnet->login($self->{'username'}, $self->{'password'}); + die($telnet->errmsg()) unless ($result); + $telnet->cmd("set cli screen-length 0"); + } } - $telnet->cmd("set cli screen-length 0"); - } - } - # IOS login - elsif ($self->{type} eq "ios" || $self->{type} eq "ios6509") { + # IOS login + elsif ($self->{'type'} eq "ios" || $self->{'type'} eq "ios6509") { + $telnet->login($self->{'username'}, $self->{'password'}); + die($telnet->errmsg()) unless ($result); + $telnet->cmd("terminal length 0"); + } - $telnet->login($self->{username}, $self->{password}); - if (!$result) { - die($telnet->errmsg()); - } - $telnet->cmd("terminal length 0"); + eval { + # setup the timeout handler + local $SIG{'ALRM'} = sub { + $buf .= "\n--- Maximum Timeout Exceeded ---\n"; + die; + }; + + # start the timeout timer + alarm($self->{'timeout'}); + + # issue command and eat up echo + $telnet->print($command); + $telnet->getline(); + + # eat up extra lines for IOS + if ($self->{'type'} eq "ios") { + $telnet->getline(); + $telnet->getline(); + $telnet->getline(); + } + + my $i = 0; + my $msg; + while (1) { + $msg = $telnet->getline(); + last if ($msg eq ""); + # $msg =~ s/ / /g; + # $msg =~ s//>/g; + $msg = $self->clean_result($msg, 0); + $buf .= $msg; + $i++; + if ($i == $self->{'maxlines'}) { + $buf .= "\n--- Maximum Output Exceeded ---\n"; + last; + } + } + alarm(0); + }; + + $buf = $self->sanitize_text($buf); + return $buf; } +} - eval { - - # setup the timeout handler - local $SIG{ALRM} = sub { - $buf .= "\n--- Maximum Timeout Exceeded ---\n"; - die; - }; +sub force10SSH { + my $self = shift; + my $cmd = shift; - # start the timeout timer - alarm($self->{'timeout'}); + my $username = $self->{'username'}; + my $password = $self->{'password'}; + my $hostname = $self->{'hostname'}; - my $i = 0; - my $msg; + my $prompt; + my $buf; + my $count = 0; + my $ssh; - # issue command and eat up echo - $telnet->print($command); - $telnet->getline(); + $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); + $ssh->log_stdout(0); + $ssh->log_file(sub {$prompt .= shift }); + $ssh->expect( + $self->{'timeout'}, + [ + 'assword:', + sub { + my $out = shift; + print $out "$password\n"; + exp_continue; + } + ], + [ + 'yes/no', + sub { + my $out = shift; + print $out "yes\n"; + exp_continue; + } + ], + ['#', sub {}], + ['>', sub {}] + ); - # eat up extra lines for IOS - if ($self->{type} eq "ios") { - $telnet->getline(); - $telnet->getline(); - $telnet->getline(); - } + $prompt = reverse($prompt); + my $index = index($prompt, "\n"); + $prompt = reverse(substr($prompt, 0, $index)); - while (1) { + $ssh->log_file(sub { $buf .= shift }); + $ssh->send("terminal length 0\r\n"); + $ssh->expect($self->{'timeout'}, ["^$prompt", sub {}]); - $msg = $telnet->getline(); - if ($msg eq "") { - last; + eval { + local $SIG{'ALRM'} = sub { + $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; + die; + }; + + $ssh->log_file(sub { + if ($count >= $self->{'maxlines'}) { + $buf .= "\n--- Maximum Output Exceeded ---\n\n"; + $ssh->log_file(undef); + die; + } + my $data = shift; + $buf .= $data; + my $newlines = ($data =~ tr/\n//); + $count += $newlines; + }); + alarm($self->{'timeout'}); + + # dont give a newline if the command contains ? + my $matchCmd = $cmd; + if ($cmd =~ /\?/) { + chop($matchCmd); + $ssh->send("$cmd"); } - $msg =~ s/ / /g; - $msg =~ s//>/g; - #$msg =~ s/\n/
/g; - $buf .= $msg; - $i++; - if ($i == $self->{maxlines}) { - $buf .= "\n--- Maximum Output Exceeded ---\n"; - last; + else { + $ssh->send("$cmd\r\n"); } - } - alarm(0); + $ssh->expect($self->{'timeout'}, ["^$prompt", sub {}]); + alarm(0); }; - $buf = $self->sanitize_text($buf); + $buf =~ s/.*\n//; + $buf = blankPrompt($buf); + $buf = reverse($buf); + $buf =~ s/.*\n//; + $buf = reverse($buf); return $buf; - } } -sub force10SSH { - - my $self = shift; - my $cmd = shift; - - my $username = $self->{username}; - my $password = $self->{password}; - my $hostname = $self->{hostname}; - - my $prompt; - my $buf; - my $count = 0; - my $ssh; - - $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); - $ssh->log_stdout(0); - $ssh->log_file(sub {$prompt .= shift }); - $ssh->expect($self->{'timeout'}, - ['assword:', - sub { - my $out = shift; - print $out "$password\n"; - exp_continue; - }], - ['yes/no', - sub { - my $out = shift; - print $out "yes\n"; - exp_continue; - }], - ['#', - sub { - }], - ['>', - sub { - }] - ); - - $prompt = reverse($prompt); - my $index = index($prompt, "\n"); - $prompt = substr($prompt, 0, $index); - $prompt = reverse($prompt); - - $ssh->log_file(sub { $buf .= shift }); - $ssh->send("terminal length 0\r\n"); - $ssh->expect($self->{'timeout'}, - ["^$prompt", sub {}]); - - eval { - - local $SIG{ALRM} = sub { - - $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; - die; - }; - - $ssh->log_file(sub { - - if ($count >= $self->{maxlines}) { - - $buf .= "\n--- Maximum Output Exceeded ---\n\n"; - $ssh->log_file(undef); - die; - } - my $data = shift; - $buf .= $data; - - my $newlines = ($data =~ tr/\n//); - $count += $newlines; - }); - alarm($self->{'timeout'}); - - # dont give a newline if the command contains ? - my $matchCmd = $cmd; - if ($cmd =~ /\?/) { - chop($matchCmd); - $ssh->send("$cmd"); - } - else { - $ssh->send("$cmd\r\n"); - } - $ssh->expect($self->{'timeout'}, - ["^$prompt", - sub {}]); - alarm(0); - }; - - $buf =~ s/.*\n//; - $buf = blankPrompt($buf); - - $buf = reverse($buf); - $buf =~ s/.*\n//; - - # if they got a command list, remove another line at the end - #if ($cmd =~ /\?/) { - - # $buf =~ s/.*\n//; - #} - $buf = reverse($buf); - - return $buf; -} sub bladeOS { - my $self = shift; my $cmd = shift; - my $username = $self->{username}; - my $password = $self->{password}; - my $hostname = $self->{hostname}; + my $username = $self->{'username'}; + my $password = $self->{'password'}; + my $hostname = $self->{'hostname'}; my $prompt; my $buf; @@ -461,803 +403,671 @@ sub bladeOS { $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); $ssh->log_stdout(0); $ssh->log_file(sub {$prompt .= shift }); - $ssh->expect($self->{'timeout'}, - ['assword:', - sub { - my $out = shift; - print $out "$password\n"; - exp_continue; - }], - ['yes/no', - sub { - my $out = shift; - print $out "yes\n"; - exp_continue; - }], - ['#', - sub { - }], - ['>', - sub { - }] - ); + $ssh->expect( + $self->{'timeout'}, + [ + 'assword:', + sub { + my $out = shift; + print $out "$password\n"; + exp_continue; + } + ], + [ + 'yes/no', + sub { + my $out = shift; + print $out "yes\n"; + exp_continue; + } + ], + ['#', sub {}], + ['>', sub {}] + ); $prompt = reverse($prompt); my $index = index($prompt, "\n"); - $prompt = substr($prompt, 0, $index); - $prompt = reverse($prompt); + $prompt = reverse(substr($prompt, 0, $index)); $ssh->log_file(sub { $buf .= shift }); $ssh->send("terminal length 0\r\n"); - $ssh->expect($self->{'timeout'}, - ["^$prompt", sub {}]); + $ssh->expect($self->{'timeout'}, ["^$prompt", sub {}]); eval { - - local $SIG{ALRM} = sub { - - $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; - die; - }; - - $ssh->log_file(sub { - - if ($count >= $self->{maxlines}) { - - $buf .= "\n--- Maximum Output Exceeded ---\n\n"; - $ssh->log_file(undef); - die; - } - my $data = shift; - $buf .= $data; - - my $newlines = ($data =~ tr/\n//); - $count += $newlines; - }); - alarm($self->{'timeout'}); - - # dont give a newline if the command contains ? - my $matchCmd = $cmd; - if ($cmd =~ /\?/) { - chop($matchCmd); - $ssh->send("$cmd"); - } - else { - $ssh->send("$cmd\r\n"); - } - $ssh->expect($self->{'timeout'}, - ["^$prompt", - sub {}]); - alarm(0); + local $SIG{'ALRM'} = sub { + $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; + die; + }; + + $ssh->log_file(sub { + if ($count >= $self->{'maxlines'}) { + $buf .= "\n--- Maximum Output Exceeded ---\n\n"; + $ssh->log_file(undef); + die; + } + my $data = shift; + $buf .= $data; + my $newlines = ($data =~ tr/\n//); + $count += $newlines; + }); + alarm($self->{'timeout'}); + + # dont give a newline if the command contains ? + my $matchCmd = $cmd; + if ($cmd =~ /\?/) { + chop($matchCmd); + $ssh->send("$cmd"); + } + else { + $ssh->send("$cmd\r\n"); + } + $ssh->expect($self->{'timeout'},["^$prompt",sub {}]); + alarm(0); }; # remove 4 blank lines $buf =~ s/.*\n//; $buf =~ s/.*\n//; $buf =~ s/.*\n//; - $buf =~ s/.*\n//; - #$buf = blankPrompt($buf); - + $buf =~ s/.*\n//; $buf = reverse($buf); #remove last line (prompt) $buf =~ s/.*\n//; $buf = reverse($buf); - return $buf; } -sub hpSSH { - my $self = shift; - my $cmd = shift; +sub hpSSH { + my $self = shift; + my $cmd = shift; - my $username = $self->{username}; - my $password = $self->{password}; - my $hostname = $self->{hostname}; + my $username = $self->{'username'}; + my $password = $self->{'password'}; + my $hostname = $self->{'hostname'}; - my $buf; - my $count = 0; - my $ssh; + my $buf; + my $count = 0; + my $ssh; - $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); - $ssh->log_stdout(0); - $ssh->expect($self->{'timeout'}, - ['assword:', - sub { - my $out = shift; - print $out "$password\n"; - exp_continue; - }], - ['Press any key to continue', - sub { - my $out = shift; - print $out "\n"; - exp_continue; - }], - ['yes/no', - sub { - my $out = shift; - print $out "yes\n"; - exp_continue; - }], - ['#', - sub { - }], - ['>', + $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); + $ssh->log_stdout(0); + $ssh->expect( + $self->{'timeout'}, + [ + 'assword:', + sub { + my $out = shift; + print $out "$password\n"; + exp_continue; + } + ], + [ 'Press any key to continue', + sub { + my $out = shift; + print $out "\n"; + exp_continue; + } + ], + [ 'yes/no', + sub { + my $out = shift; + print $out "yes\n"; + exp_continue; + } + ], + ['#', sub {}], + ['>', sub {}] + ); + + my $questionMark = 0; + eval { + local $SIG{'ALRM'} = sub { + $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; + die; + }; + + $ssh->log_file(sub { + if ($count >= $self->{'maxlines'}) { + $ssh->log_file(undef); + $buf .= "\n--- Maximum Output Exceeded ---\n\n"; + die; + } + my $data = shift; + $data =~ s/-- MORE --.*Control-C.*$//; + $data =~ s/\e[[\w;]*//g; + $buf .= $data; + + my $newlines = ($data =~ tr/\n//); + $count += $newlines; + }); + alarm($self->{'timeout'}); + + if ($cmd =~ /\?/) { + $questionMark = 1; + $cmd =~ s/(.*)\?/$1/; + $ssh->send("$cmd"); + sleep(1); + $ssh->send("?"); + } + else { + $ssh->send("$cmd\n"); + } + $ssh->expect( + $self->{'timeout'}, + ['[>]', sub {}], + [ + 'Control-C', sub { - }] - ); - - my $questionMark = 0; - - eval { - - local $SIG{ALRM} = sub { - - $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; - die; + my $out = shift; + print $out " "; + exp_continue; + } + ] + ); + alarm(0); }; - $ssh->log_file(sub { - - if ($count >= $self->{maxlines}) { - $ssh->log_file(undef); - $buf .= "\n--- Maximum Output Exceeded ---\n\n"; - die; - } - my $data = shift; - $data =~ s/-- MORE --.*Control-C.*$//; - $data =~ s/\e[[\w;]*//g; - - $buf .= $data; - - my $newlines = ($data =~ tr/\n//); - $count += $newlines; - }); - alarm($self->{'timeout'}); - - if ($cmd =~ /\?/) { + # detect invalid input and fix it + if ($buf =~ /input: (.*)/) { + $buf = "Invalid input: $1"; + return $buf; + } + $buf =~ s/.*\n//; - $questionMark = 1; - $cmd =~ s/(.*)\?/$1/; - $ssh->send("$cmd"); - sleep(1); - $ssh->send("?"); + # create dummy prompt + if ($questionMark) { + $buf = "> $cmd?\n" . $buf; } else { - $ssh->send("$cmd\n"); + $buf = "> $cmd\n" . $buf; } - $ssh->expect($self->{'timeout'}, - ['[>]', - sub { - }], - ['Control-C', - sub { - my $out = shift; - print $out " "; - exp_continue; - }]); - alarm(0); - }; - # detect invalid input and fix it - if ($buf =~ /input: (.*)/) { - $buf = "Invalid input: $1"; + $buf = reverse($buf); + # remove last line (prompt) + $buf =~ s/.*\n//; + $buf = reverse($buf); return $buf; - } - $buf =~ s/.*\n//; - #$buf = blankPrompt($buf); - - # create dummy prompt - if ($questionMark) { - $buf = "> $cmd?\n" . $buf; - } - else { - $buf = "> $cmd\n" . $buf; - } - - $buf = reverse($buf); - # remove last line (prompt) - $buf =~ s/.*\n//; - $buf = reverse($buf); - - return $buf; } -sub ios2Telnet { - - my $self = shift; - my $cmd = shift; - - my $username = $self->{username}; - my $password = $self->{password}; - my $hostname = $self->{hostname}; - - my $buf; - my $count = 0; - my $telnet; - - $telnet = Net::Telnet->new(Timeout => 1, Errmode => 'return', Port => $self->{port}); - my $result = $telnet->open($self->{hostname}); - if (!$result) { - die($telnet->errmsg()); - } - $telnet->login($username, $password); - $telnet->cmd("terminal length 0"); - $telnet->buffer_empty(); +sub ios2Telnet { + my $self = shift; + my $cmd = shift; - eval { + my $username = $self->{'username'}; + my $password = $self->{'password'}; + my $hostname = $self->{'hostname'}; - # setup the timeout handler - local $SIG{ALRM} = sub { + my $buf; + my $count = 0; + my $telnet; - $buf .= "\n--- Maximum Timeout Exceeded ---\n"; - die; - }; + $telnet = Net::Telnet->new(Timeout => 1, Errmode => 'return', Port => $self->{'port'}); + my $result = $telnet->open($self->{'hostname'}); + die($telnet->errmsg()) unless ($result); - # start the timeout timer - alarm($self->{'timeout'}); + $telnet->login($username, $password); + $telnet->cmd("terminal length 0"); + $telnet->buffer_empty(); - my $i = 0; - my $msg; + eval { + # setup the timeout handler + local $SIG{'ALRM'} = sub { + $buf .= "\n--- Maximum Timeout Exceeded ---\n"; + die; + }; - # issue command and eat up echo - $telnet->print($cmd); - $telnet->getline(); + # start the timeout timer + alarm($self->{'timeout'}); - # eat up extra lines for IOS - if ($self->{type} eq "ios") { - $telnet->getline(); - $telnet->getline(); - $telnet->getline(); - } + # issue command and eat up echo + $telnet->print($cmd); + $telnet->getline(); - while (1) { - - $msg = $telnet->getline(); - if ($msg eq "") { - last; - } - $buf .= $msg; - $i++; - if ($i == $self->{maxlines}) { - $buf .= "\n--- Maximum Output Exceeded ---\n"; - last; - } - } - alarm(0); - }; + # eat up extra lines for IOS + if ($self->{'type'} eq "ios") { + $telnet->getline(); + $telnet->getline(); + $telnet->getline(); + } - return $buf; + my $i = 0; + my $msg; + while (1) { + $msg = $telnet->getline(); + last if ($msg eq ""); + $buf .= $msg; + $i++; + if ($i == $self->{'maxlines'}) { + $buf .= "\n--- Maximum Output Exceeded ---\n"; + last; + } + } + alarm(0); + }; + return $buf; } -sub ios2SSH { - - my $self = shift; - my $cmd = shift; - - my $username = $self->{username}; - my $password = $self->{password}; - my $hostname = $self->{hostname}; - my $buf; - my $count = 0; - my $ssh; +sub ios2SSH { + my $self = shift; + my $cmd = shift; - $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); - $ssh->log_stdout(0); - $ssh->expect(5, - ['assword:', - sub { - my $out = shift; - print $out "$password\n"; - exp_continue; - }], - ['yes/no', - sub { - my $out = shift; - print $out "yes\n"; - exp_continue; - }], - ['#', - sub { - }], - ['>', - sub { - }] - ); + my $username = $self->{'username'}; + my $password = $self->{'password'}; + my $hostname = $self->{'hostname'}; - $ssh->log_file(sub { $buf .= shift }); - $ssh->send("terminal length 0\n"); - $ssh->expect(5, - ['#', - sub { - }], - ['>', - sub { - }] - ); + my $buf; + my $count = 0; + my $ssh; - eval { + $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); + $ssh->log_stdout(0); + $ssh->expect( + 5, + [ + 'assword:', + sub { + my $out = shift; + print $out "$password\n"; + exp_continue; + } + ], + [ + 'yes/no', + sub { + my $out = shift; + print $out "yes\n"; + exp_continue; + } + ], + ['#', sub {}], + ['>', sub {}] + ); - local $SIG{ALRM} = sub { + $ssh->log_file(sub { $buf .= shift }); + $ssh->send("terminal length 0\n"); + $ssh->expect( + 5, + ['#', sub {}], + ['>', sub {}] + ); - $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; - die; + eval { + local $SIG{'ALRM'} = sub { + $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; + die; + }; + + $ssh->log_file(sub { + if ($count >= $self->{'maxlines'}) { + $ssh->log_file(undef); + $buf .= "\n--- Maximum Output Exceeded ---\n\n"; + die; + } + my $data = shift; + $buf .= $data; + + my $newlines = ($data =~ tr/\n//); + $count += $newlines; + }); + alarm($self->{'timeout'}); + + if ($cmd =~ /\?/) { + $ssh->send("$cmd"); + } + else { + $ssh->send("$cmd\n"); + } + $ssh->expect( + $self->{'timeout'}, + ['^\S*#', sub {}], + ['^\S*>', sub {}] + ); + alarm(0); }; - $ssh->log_file(sub { - - if ($count >= $self->{maxlines}) { - $ssh->log_file(undef); - $buf .= "\n--- Maximum Output Exceeded ---\n\n"; - die; - } - - my $data = shift; - $buf .= $data; - - my $newlines = ($data =~ tr/\n//); - $count += $newlines; - }); - alarm($self->{'timeout'}); - if ($cmd =~ /\?/) { - $ssh->send("$cmd"); - } - else { - $ssh->send("$cmd\n"); - } - - $ssh->expect($self->{'timeout'}, - ['^\S*#', - sub { - }], - ['^\S*>', - sub { - }]); - alarm(0); - }; - - $buf =~ s/.*\n//; - $buf =~ s/.*\n//; - $buf = blankPrompt($buf); - $buf = reverse($buf); - # remove last line (prompt) - $buf =~ s/.*\n//; - $buf = reverse($buf); - - return $buf; + $buf =~ s/.*\n//; + $buf =~ s/.*\n//; + $buf = blankPrompt($buf); + $buf = reverse($buf); + # remove last line (prompt) + $buf =~ s/.*\n//; + $buf = reverse($buf); + return $buf; } -sub iosxrSSH { - my $self = shift; - my $cmd = shift; - - my $username = $self->{username}; - my $password = $self->{password}; - my $hostname = $self->{hostname}; - - my $buf; - my $count = 0; - my $questionMark = 0; - my $ssh; +sub iosxrSSH { + my $self = shift; + my $cmd = shift; - $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); - $ssh->log_stdout(0); - $ssh->expect($self->{'timeout'}, - ['assword:', - sub { - my $out = shift; - print $out "$password\n"; - exp_continue; - }], - ['yes/no', - sub { - my $out = shift; - print $out "yes\n"; - exp_continue; - }], - ['#', - sub { - }], - ['>', - sub { - }] - ); + my $username = $self->{'username'}; + my $password = $self->{'password'}; + my $hostname = $self->{'hostname'}; - $ssh->log_file(sub { $buf .= shift }); - $ssh->send("terminal length 0\n"); - $ssh->expect($self->{'timeout'}, - ['#', - sub { - }], - ['>', - sub { - }]); + my $buf; + my $count = 0; + my $questionMark = 0; + my $ssh; + $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); + $ssh->log_stdout(0); + $ssh->expect( + $self->{'timeout'}, + [ + 'assword:', + sub { + my $out = shift; + print $out "$password\n"; + exp_continue; + } + ], + [ + 'yes/no', + sub { + my $out = shift; + print $out "yes\n"; + exp_continue; + } + ], + ['#', sub {}], + ['>', sub {}] + ); - eval { + $ssh->log_file(sub { $buf .= shift }); + $ssh->send("terminal length 0\n"); + $ssh->expect( + $self->{'timeout'}, + ['#', sub {}], + ['>', sub {}] + ); - local $SIG{ALRM} = sub { + eval { + local $SIG{'ALRM'} = sub { + $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; + die; + }; + alarm($self->{'timeout'}); + + if ($cmd =~ /\?/) { + $questionMark = 1; + $ssh->send("$cmd"); + } + else { + $ssh->send("$cmd\n"); + } - $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; - die; + $ssh->log_file(sub { + if ($count >= $self->{'maxlines'}) { + $ssh->log_file(undef); + $buf .= "\n--- Maximum Output Exceeded ---\n\n"; + die; + } + my $data = shift; + $buf .= $data; + my $newlines = ($data =~ tr/\n//); + $count += $newlines; + }); + + if ($questionMark) { + $cmd =~ s/(.*)\?/$1/; + $ssh->expect( + $self->{'timeout'}, + ["^.*[#>]($cmd)", sub {}] + ); + } + else { + $ssh->expect( + $self->{'timeout'}, + ['^.*#$', sub {}], + ['^.*>$', sub {}] + ); + } + alarm(0); }; - alarm($self->{'timeout'}); - - if ($cmd =~ /\?/) { - $questionMark = 1; - $ssh->send("$cmd"); - } - else { - $ssh->send("$cmd\n"); - } - - $ssh->log_file(sub { - - if ($count >= $self->{maxlines}) { - $ssh->log_file(undef); - $buf .= "\n--- Maximum Output Exceeded ---\n\n"; - die; - } - - my $data = shift; - $buf .= $data; - - my $newlines = ($data =~ tr/\n//); - $count += $newlines; - }); - - if ($questionMark) { - - $cmd =~ s/(.*)\?/$1/; - $ssh->expect($self->{'timeout'}, - ["^.*[#>]($cmd)", - sub {}]); - } - else { - $ssh->expect($self->{'timeout'}, - ['^.*#$', - sub { - }], - ['^.*>$', - sub { - }]); - } - - alarm(0); - }; - - # remove first blank line - $buf =~ s/.*\n//; - $buf = blankPrompt($buf); - - # add an extra space to line up the ^ if needed - if ($buf =~ /% Invalid input detected at/) { - - $buf =~ s/\^/ ^/; - } + # remove first blank line + $buf =~ s/.*\n//; + $buf = blankPrompt($buf); - $buf = reverse($buf); - #remove last line (prompt) - $buf =~ s/.*\n//; - $buf = reverse($buf); + # add an extra space to line up the ^ if needed + $buf =~ s/\^/ ^/ if ($buf =~ /% Invalid input detected at/); - return $buf; + $buf = reverse($buf); + #remove last line (prompt) + $buf =~ s/.*\n//; + $buf = reverse($buf); + return $buf; } + sub junosSSH { + my $self = shift; + my $cmd = shift; - my $self = shift; - my $cmd = shift; + my $username = $self->{'username'}; + my $password = $self->{'password'}; + my $hostname = $self->{'hostname'}; - my $username = $self->{username}; - my $password = $self->{password}; - my $hostname = $self->{hostname}; + my $buf; + my $count = 0; + my $ssh; + my $questionMark = 0; - my $buf; - my $count = 0; - my $ssh; - my $questionMark = 0; + $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); + $ssh->log_stdout(0); + $ssh->expect( + $self->{'timeout'}, + [ + 'assword:', + sub { + my $out = shift; + print $out "$password\n"; + } + ], + [ + 'yes/no', + sub { + my $out = shift; + print $out "yes\n"; + exp_continue; + } + ] + ); + + $ssh->expect( + $self->{'timeout'}, + ['^([^\\s])*#\\\s\$', sub {}], + ['^([^\\s])*>\\\s\$', sub {}] + ); - $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); - $ssh->log_stdout(0); - $ssh->expect($self->{'timeout'}, - ['assword:', - sub { - my $out = shift; - print $out "$password\n"; - }], - ['yes/no', - sub { - my $out = shift; - print $out "yes\n"; - exp_continue; - }]); - - $ssh->expect($self->{'timeout'}, - ["^([^\\s])*#\\\s\$", - sub { - }], - ["^([^\\s])*>\\\s\$", - sub { - }]); - - $ssh->log_file(sub { $buf .= shift }); - $ssh->send("set cli screen-length 0\n"); - - $ssh->expect($self->{'timeout'}, - ["^([^\\s])*#\\\s\$", - sub { - }], - ["^([^\\s])*>\\\s\$", - sub { - }]); + $ssh->log_file(sub { $buf .= shift }); + $ssh->send("set cli screen-length 0\n"); + + $ssh->expect( + $self->{'timeout'}, + ['^([^\\s])*#\\\s\$', sub {}], + ['^([^\\s])*>\\\s\$', sub {}] + ); - eval { - - local $SIG{ALRM} = sub { + eval { + local $SIG{'ALRM'} = sub { + $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; + die; + }; + $ssh->log_file(sub { + if ($count >= $self->{'maxlines'}) { + $ssh->log_file(undef); + $buf .= "\n--- Maximum Output Exceeded ---\n\n"; + die; + } + my $data = shift; + $buf .= $data; + my $newlines = ($data =~ tr/\n//); + $count += $newlines; + }); + alarm($self->{'timeout'}); + + if ($cmd =~ /\?/) { + $questionMark = 1; + $ssh->send("$cmd"); + } + else { + $ssh->send("$cmd\n"); + } - $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; - die; + if ($questionMark) { + $cmd =~ s/(.*)\?/$1/; + $ssh->expect( + $self->{'timeout'}, + ["^.*# $cmd", sub {}], + ["^.*> $cmd", sub {}] + ); + } + else { + $ssh->expect( + $self->{'timeout'}, + ['^([^\\s])*#\\\s\$', sub {}], + ['^([^\\s])*>\\\s\$', sub {}] + ); + } + alarm(0); }; - $ssh->log_file(sub { - - if ($count >= $self->{maxlines}) { - $ssh->log_file(undef); - $buf .= "\n--- Maximum Output Exceeded ---\n\n"; - die; - } - my $data = shift; - $buf .= $data; - - my $newlines = ($data =~ tr/\n//); - $count += $newlines; - }); - alarm($self->{'timeout'}); - - if ($cmd =~ /\?/) { - - $questionMark = 1; - $ssh->send("$cmd"); - } - else { - $ssh->send("$cmd\n"); - } - - if ($questionMark) { - - $cmd =~ s/(.*)\?/$1/; - $ssh->expect($self->{'timeout'}, - ["^.*# $cmd", - sub { - }], - ["^.*> $cmd", - sub { - }]); - } - else { - $ssh->expect($self->{'timeout'}, - ["^([^\\s])*#\\\s\$", - sub { - }], - ["^([^\\s])*>\\\s\$", - sub { - }]); - } - - alarm(0); - }; - - # remove first 3 lines - $buf =~ s/.*\n//; - $buf =~ s/.*\n//; - $buf =~ s/.*\n//; - - if ($buf =~ /{.*}.*\n/) { + # remove first 3 lines + $buf =~ s/.*\n//; $buf =~ s/.*\n//; - } - - # blank out the prompt on the first line - $buf = blankPrompt($buf); - $buf = reverse($buf); - # remove last line (prompt) - $buf =~ s/.*\n//; - - if ($buf =~ /}.*{.*\n/) { $buf =~ s/.*\n//; - } - - if ($questionMark) { - my $check = reverse("syntax error, expecting"); - if ($buf =~ /$check/) { - $buf =~ s/.*\n//; - $buf =~ s/.*\n//; - $buf =~ s/.*\n//; - $buf =~ s/.*\n//; - if ($buf =~ /}.*{.*\n/) { + if ($buf =~ /{.*}.*\n/) { $buf =~ s/.*\n//; - } } - } - - $buf = reverse($buf); - - return $buf; -} - -sub aristaSSH { - - my $self = shift; - my $cmd = shift; - - my $username = $self->{username}; - my $password = $self->{password}; - my $hostname = $self->{hostname}; - - my $buf; - my $count = 0; - my $questionMark = 0; - my $ssh; - - $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); - $ssh->log_stdout(0); - $ssh->expect($self->{'timeout'}, - ['assword:', - sub { - my $out = shift; - print $out "$password\n"; - exp_continue; - }], - ['yes/no', - sub { - my $out = shift; - print $out "yes\n"; - exp_continue; - }], - ['#', - sub { - }], - ['>', - sub { - }] - ); - - $ssh->log_file(sub { $buf .= shift }); - $ssh->send("terminal length 0\n"); - $ssh->expect($self->{'timeout'}, - ['#', - sub { - }], - ['>', - sub { - }]); - eval { - - local $SIG{ALRM} = sub { - - $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; - die; - }; - - alarm($self->{'timeout'}); - - if ($cmd =~ /\?/) { - $questionMark = 1; - $ssh->send("$cmd"); - } - else { - $ssh->send("$cmd\n"); - } - - $ssh->log_file(sub { - - if ($count >= $self->{maxlines}) { - $ssh->log_file(undef); - $buf .= "\n--- Maximum Output Exceeded ---\n\n"; - die; - } - - my $data = shift; - $buf .= $data; - - my $newlines = ($data =~ tr/\n//); - $count += $newlines; - }); + # blank out the prompt on the first line + $buf = blankPrompt($buf); + $buf = reverse($buf); + # remove last line (prompt) + $buf =~ s/.*\n//; + $buf =~ s/.*\n// if ($buf =~ /}.*{.*\n/); if ($questionMark) { - - $cmd =~ s/(.*)\?/$1/; - $ssh->expect($self->{'timeout'}, - ["^.*[#>]($cmd)", - sub {}]); - } - else { - $ssh->expect($self->{'timeout'}, - ['^.*#$', - sub { - }], - ['^.*>$', - sub { - }]); + my $check = reverse("syntax error, expecting"); + if ($buf =~ /$check/) { + $buf =~ s/.*\n//; + $buf =~ s/.*\n//; + $buf =~ s/.*\n//; + $buf =~ s/.*\n//; + if ($buf =~ /}.*{.*\n/) { + $buf =~ s/.*\n//; + } + } } - - alarm(0); - }; - - # remove first blank line - $buf =~ s/.*\n//; - $buf = blankPrompt($buf); - - # add an extra space to line up the ^ if needed - if ($buf =~ /% Invalid input detected at/) { - - $buf =~ s/\^/ ^/; - } - - $buf = reverse($buf); - #remove last line (prompt) - $buf =~ s/.*\n//; - $buf = reverse($buf); - - return $buf; + $buf = reverse($buf); + return $buf; } -sub blankPrompt { - - my $string = shift; - - # pull out the first line - my $line = substr($string, 0, index($string, "\n")); - - # find the first > - my $index = index($line, '>'); - - # otherwise find the first # - if ($index < 0) { - $index = index($line, '#'); - } - - # get the prompt (user at host) - my $prompt = substr($string, 0, $index + 1); - # print STDERR "index is $index, prompt is $prompt, "; +sub aristaSSH { + my $self = shift; + my $cmd = shift; - # replace each char with a space - $prompt =~ s/#/>/; - $prompt =~ s/[^>]/\./g; + my $username = $self->{'username'}; + my $password = $self->{'password'}; + my $hostname = $self->{'hostname'}; - #print STDERR "now its $prompt\n"; + my $buf; + my $count = 0; + my $questionMark = 0; + my $ssh; - # get everything after the prompt - $string = substr($string, $index + 1); + $ssh = Expect->spawn("ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -l $username $hostname"); + $ssh->log_stdout(0); + $ssh->expect( + $self->{'timeout'}, + [ + 'assword:', + sub { + my $out = shift; + print $out "$password\n"; + exp_continue; + } + ], + [ + 'yes/no', + sub { + my $out = shift; + print $out "yes\n"; + exp_continue; + } + ], + ['#', sub {}], + ['>', sub {}] + ); - # reattach our blanked out prompt to the rest of the string - $string = $prompt . $string; + $ssh->log_file(sub { $buf .= shift }); + $ssh->send("terminal length 0\n"); + $ssh->expect( + $self->{'timeout'}, + ['#', sub {}], + ['>', sub {}] + ); - return $string; -} + eval { + local $SIG{'ALRM'} = sub { + $buf .= "\n--- Maximum Timeout Exceeded ---\n\n"; + die; + }; + alarm($self->{'timeout'}); + + if ($cmd =~ /\?/) { + $questionMark = 1; + $ssh->send("$cmd"); + } + else { + $ssh->send("$cmd\n"); + } -#ISSUE=12307 Remove sensitive information, as specified in the config file, from any output -sub sanitize_text{ - my $self = shift; - my $text = shift; + $ssh->log_file(sub { + if ($count >= $self->{'maxlines'}) { + $ssh->log_file(undef); + $buf .= "\n--- Maximum Output Exceeded ---\n\n"; + die; + } + my $data = shift; + $buf .= $data; + my $newlines = ($data =~ tr/\n//); + $count += $newlines; + }); + + if ($questionMark) { + $cmd =~ s/(.*)\?/$1/; + $ssh->expect( + $self->{'timeout'}, + ["^.*[#>]($cmd)", sub {}] + ); + } + else { + $ssh->expect( + $self->{'timeout'}, + ['^.*#$', sub {}], + ['^.*>$', sub {}] + ); + } + alarm(0); + }; - my $conf = GRNOC::RouterProxy::Config->New($self->{'config_path'}); - my $stanzas = $conf->Redacts(); + # remove first blank line + $buf =~ s/.*\n//; + $buf = blankPrompt($buf); - foreach my $stanza ( @$stanzas ) { - $stanza =~ s/ / \;/g; - $stanza =~ s/(?/>\;/g; - $text =~ s/$stanza/\[REDACTED\]/g; - } + # add an extra space to line up the ^ if needed + $buf =~ s/\^/ ^/ if ($buf =~ /% Invalid input detected at/); - return $text; + $buf = reverse($buf); + #remove last line (prompt) + $buf =~ s/.*\n//; + $buf = reverse($buf); + return $buf; } 1; diff --git a/lib/GRNOC/RouterProxy/Config.pm b/lib/GRNOC/RouterProxy/Config.pm index a07b8c9..1208a3c 100644 --- a/lib/GRNOC/RouterProxy/Config.pm +++ b/lib/GRNOC/RouterProxy/Config.pm @@ -7,10 +7,13 @@ use Log::Log4perl; use XML::Simple; use YAML; +Log::Log4perl::init('/etc/grnoc/routerproxy/logging.conf'); + sub New { my $class = shift; + my $self = { - log => Log::Log4perl->get_logger('GRNOC.RouterProxy.Config'), + log => Log::Log4perl->get_logger('GRNOC.RouterProxy'), path => shift }; @@ -41,7 +44,7 @@ sub loadXML { my $self = shift; my $path = shift; - $self->{'log'}->info("Loading xml configuration from $self->{'path'}."); + $self->{'log'}->debug("Loading XML config $self->{'path'}"); my $xml = XMLin($path, forcearray => 1); @@ -174,7 +177,7 @@ Loads configuration from a JSON file. sub loadYAML { my $self = shift; - $self->{'log'}->info("Loading yaml configuration from $self->{'path'}."); + $self->{'log'}->debug("Loading YAML config $self->{'path'}."); my $yaml = YAML::LoadFile($self->{'path'}); diff --git a/lib/GRNOC/RouterProxy/Logger.pm b/lib/GRNOC/RouterProxy/Logger.pm index 038a3c5..14b0787 100644 --- a/lib/GRNOC/RouterProxy/Logger.pm +++ b/lib/GRNOC/RouterProxy/Logger.pm @@ -3,55 +3,38 @@ package GRNOC::RouterProxy::Logger; use Time::ParseDate; sub addEntry { + my ($logfile, $ip, $router, $cmd) = @_; - my $logfile = shift; - my $ip = shift; - my $router = shift; - my $cmd = shift; - - my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(); - $year += 1900; - $mon++; - - if ($hour < 10) { - $hour = "0$hour"; - } - if ($min < 10) { - $min = "0$min"; - } - if ($sec < 10) { - $sec = "0$sec"; - } - - my $time = "[$year/$mon/$mday $hour:$min:$sec]"; - - open(FILE, ">>$logfile") || die ("Error opening log file"); - print FILE "$time $ip $router: $cmd\n"; - close(FILE); + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(); + $year += 1900; + $mon++; + $hour = "0$hour" if ($hour < 10); + $min = "0$min" if ($min < 10); + $sec = "0$sec" if ($sec < 10); + + my $time = "[$year/$mon/$mday $hour:$min:$sec]"; + + open(FILE, ">>$logfile") || die ("ERROR: Could not open logfile '$logfile'"); + print FILE "$time $ip $router: $cmd\n"; + close(FILE); } sub getLastTime { + my $logfile = shift; + + open(FILE, $logfile); + my @lines = ; + close(FILE); + + my $lastLine = $lines[@lines - 1]; + return undef unless $lastLine; + + my ($year, $month, $day, $hour, $min, $sec) = $lastLine =~ /\[([^\/]*)\/([^\/]*)\/([^ ]*) ([^:]*):([^:]*):([^\]]*).*/; + $hour = "0$hour" if ($hour < 10); + $min = "0$min" if ($min < 10); + $sec = "0$sec" if ($sec < 10); - my $logfile = shift; - open(FILE, $logfile); - my @lines = ; - close(FILE); - - my $lastLine = $lines[@lines - 1]; - my ($year, $month, $day, $hour, $min, $sec) = $lastLine =~ /\[([^\/]*)\/([^\/]*)\/([^ ]*) ([^:]*):([^:]*):([^\]]*).*/; - #$month++; - - if ($hour < 10) { - $hour = "0" . $hour; - } - if ($min < 10) { - $min = "0" . $min; - } - if ($sec < 10) { - $sec = "0" . $sec; - } - - return parsedate("$month-$day-$year $hour:$min:$sec"); + return parsedate("$month-$day-$year $hour:$min:$sec"); } 1; diff --git a/webroot/index.cgi b/webroot/index.cgi index 6aa1e17..90ecb8a 100755 --- a/webroot/index.cgi +++ b/webroot/index.cgi @@ -1,26 +1,38 @@ #!/usr/bin/perl +use strict; use warnings; -use FindBin; - use CGI; +use JSON; +use FindBin; use FileHandle; +use Encode; +use Template; use XML::Simple; +use Data::Dumper; +use Time::ParseDate; + use GRNOC::RouterProxy; +use GRNOC::RouterProxy::Logger; use GRNOC::RouterProxy::Config; use GRNOC::RouterProxy::Commands; -use Encode; -use Data::Dumper; use GRNOC::Config; -use Template; -use JSON; +use GRNOC::TL1; +use GRNOC::TL1::Device::Nortel::OME6500; +use GRNOC::TL1::Device::Nortel::HDXc; +use GRNOC::TL1::Device::Cisco::ONS15454; +use GRNOC::TL1::Device::Ciena::CoreDirector; -# set our home directory relative to our script +# Set the home directory relative to this script my $home_dir = "$FindBin::Bin/../"; $ENV{'HOME'} = $home_dir; -# do they have Junoscript installed? +# Initialize the logger +Log::Log4perl::init('/etc/grnoc/routerproxy/logging.conf'); +my $logger = Log::Log4perl->get_logger('GRNOC.RouterProxy'); + +# Check for and import JUNOS Script support my $hasJunoscript; BEGIN { eval { @@ -34,7 +46,7 @@ BEGIN { } } -# do they have IOS XR XML installed? +# Check for and import IOS XR XML support my $hasIosXML; BEGIN { eval { @@ -48,66 +60,100 @@ BEGIN { } } -use GRNOC::TL1; -use GRNOC::TL1::Device::Nortel::OME6500; -use GRNOC::TL1::Device::Nortel::HDXc; -use GRNOC::TL1::Device::Cisco::ONS15454; -use GRNOC::TL1::Device::Ciena::CoreDirector; - -use GRNOC::RouterProxy::Logger; -use Time::ParseDate; - -use strict; - -# use fast XML parser +# Use the fast XML parser local $ENV{'XML_SIMPLE_PREFERRED_PARSER'} = 'XML::Parser'; +# Init CGI my $cgi = CGI->new(); -my $config_path = ConfigChooser( $ENV{'REQUEST_URI'}, - "/etc/grnoc/routerproxy/mappings.xml"); +# Confirm the mappings config path or error out +my $config_path = getMappedConfig($ENV{'REQUEST_URI'}, "/etc/grnoc/routerproxy/mappings.xml"); unless (defined($config_path) && -e $config_path) { - warn ("Please check mapping file. The config file for this url cannot be located\n"); + my $msg = "Configuration for $ENV{'REQUEST_URI'} not found. Check mapping file '$config_path'"; + $logger->error($msg); print $cgi->header(); print $cgi->start_html(); - print "

Please check mapping file. The config file for this url cannot be located

"; + print "

$msg

"; print $cgi->end_html(); - exit 1; } +# Read the config and store devices by address my $conf = GRNOC::RouterProxy::Config->New($config_path); +my $devices = $conf->Devices(); +my $logfile = $conf->LogFile(); +my $maxlines = $conf->MaxLines(); +my $timeout = $conf->MaxTimeout(); +my $spamSeconds = $conf->MaxRate(); +my $enable_menu = $conf->ShowDropdown(); +my $remoteIP = $ENV{'REMOTE_ADDR'}; -# A little hack to store devices by address. Should be changed to use -# device name in the future. -my $devices = $conf->Devices(); -my $logfile = $conf->LogFile(); -my $maxlines = $conf->MaxLines(); -my $timeout = $conf->MaxTimeout(); -my $spamSeconds = $conf->MaxRate(); -my $global_enable_menu_commands = $conf->ShowDropdown(); +# Handles errors for undefined methods +sub getError { + my $msg = "The requested method does not exist"; + $logger->error($msg); + print $cgi->header(-type => "text/html", -status => "501"); + print $msg; +} + -my $remoteIP = $ENV{'REMOTE_ADDR'}; +# Prints HTML to STDOUT, called immediately after definition +sub makeHTML2 { + my $template = Template->new({ABSOLUTE => 1}); + my $input = "/usr/share/grnoc/routerproxy/templates/index.tt"; + + # If $handler is defined outside the makeHTML2 subroutine this error is returned: + # Can't use string ("") as a subroutine ref while "strict refs" in use at /gnoc/routerproxy/webroot/index.cgi line 302. + my $handler = { + device => \&getDevice, + devices => \&getDevices, + error => \&getError, + submit => \&getResponses + }; + # Check if a method has been called on this CGI. + my $method = $cgi->param('method'); + if (defined $method) { + if (!defined $handler->{$method}) { + $handler->{"error"}->(); + } else { + $handler->{$method}->(); + } + # HTML has been printed; Return. + return; + } -# Prints HTML to STDOUT + my $html = ""; + my $vars = { + network_name => $conf->NetworkName(), + primary_color => $conf->PrimaryColor(), + secondary_color => $conf->SecondaryColor(), + noc_mail => $conf->NOCMail(), + noc_name => $conf->NOCName(), + noc_site => $conf->NOCSite(), + groups => $conf->DeviceGroups(sort_devices => 1) + }; + $template->process($input, $vars, \$html); + print $cgi->header(-type => "text/html", -status => "200"); + print $html; + return; +} makeHTML2(); -sub ConfigChooser { - my $url = shift; - my $map_file = shift; - - # If mapping file is not found +# Gets a YAML config using the mappings config +sub getMappedConfig { + my ($url, $map_file) = @_; + + # Confirm the mapping config exists unless (-e $map_file) { - warn ("Mapping file is not found.\n"); + $logger->error("Mapping file '$map_file' not found.\n"); return undef; } my $config = GRNOC::Config->new( config_file => $map_file, force_array => 1 ); my $entries = $config->get( '/mappings/map' ); - foreach my $entry ( @$entries ) { my $regexp = $entry->{'regexp'}; if ( $url =~ /$regexp/ ) { @@ -117,45 +163,55 @@ sub ConfigChooser { return undef; } + +# Gets device metadata and prints it on the page sub getDevice { my $device = $cgi->param("device"); + if (!defined $device) { - print $cgi->header(-type => "text/html", - -status => "400" ); - print "Request requires parameters: device"; + my $msg = "Request is missing the 'device' parameter"; + $logger->error($msg); + print $cgi->header(-type => "text/html", -status => "400"); + print $msg; return; } # Create a copy of the device data and remove all secrets. my $data = $devices->{$device}; + if (!defined $data) { - print $cgi->header(-type => "text/html", - -status => "200" ); - print "The specified device does not exist."; + my $msg = "The specified device '$device' does not exist"; + $logger->error($msg); + print $cgi->header(-type => "text/html", -status => "200"); + print $msg; return; } + # Set commands and menu flag $data->{"commands"} = $conf->DeviceCommands($data->{"address"}); - $data->{"enable_menu"} = $global_enable_menu_commands; + $data->{"enable_menu"} = $enable_menu; + # Remove sensitive data fields delete $data->{"username"}; delete $data->{"password"}; delete $data->{"method"}; delete $data->{"command_group"}; delete $data->{"exclude_group"}; - print $cgi->header(-type => "text/html", - -status => "200" ); + # Print the data as encoded JSON + print $cgi->header(-type => "text/html", -status => "200"); print encode_json($data); } + +# getDevice for many devices sub getDevices { my @device_keys = keys %$devices; my @result = (); foreach my $key (keys %$devices) { my $data = $devices->{$key}; $data->{"commands"} = $conf->DeviceCommands($data->{"address"}); - $data->{"enable_menu"} = $global_enable_menu_commands; + $data->{"enable_menu"} = $enable_menu; delete $data->{"username"}; delete $data->{"password"}; @@ -164,56 +220,76 @@ sub getDevices { delete $data->{"exclude_group"}; push @result, $data; } - print $cgi->header(-type => "text/html", - -status => "200" ); + print $cgi->header(-type => "text/html", -status => "200"); print encode_json(\@result); } + +# Filters out spam requests by comparing last op time and $now using logs +sub filterSpam { + # Get the last log time from the logfile + my $last = GRNOC::RouterProxy::Logger::getLastTime($logfile); + + # Don't try to enforce spam limits for new logfiles + return unless $last; + + # Return a warning of how log to wait if the last command was less than spamSeconds before + my $diff = time() - $last; + if ($diff < $spamSeconds) { + my $wait = $spamSeconds - $diff; + return "Please wait $wait seconds before sending another command."; + } + return; +} + + +# Handle the request for data from a device for a command and return the response to the page sub getResponses { my $address = $cgi->param("device"); my $command = $cgi->param("command"); my $arguments = $cgi->param("arguments") || ""; my $menu_req = $cgi->param("menu") || 0; + # Confirm that the request has an address and command if (!defined $address || !defined $command) { - print $cgi->header(-type => "text/html", - -status => "400" ); - print "Request requires parameters: device, command"; + my $msg = "Request is missing either the 'device' or 'command' parameters"; + $logger->error($msg); + print $cgi->header(-type => "text/html", -status => "400" ); + print $msg; return; } + # Get the device data from the hash and confirm it is not empty my $device = $devices->{$address}; if (!defined $device) { - print $cgi->header(-type => "text/html", - -status => "200" ); - print "The specified device does not exist."; + my $msg = "The specified device '$device' does not exist"; + $logger->error($msg); + print $cgi->header(-type => "text/html", -status => "200" ); + print $msg; return; } - my $menu_enabled = $global_enable_menu_commands; - my $data = ""; - - if ($menu_req && $menu_enabled && $device->{"type"} eq "junos") { - $data = getMenuResponse($command, $device); - } elsif ($menu_req && $menu_enabled && $device->{"type"} eq "iosxr") { - $data = getIosMenuResponse($command, $device); - } elsif ($menu_req && $menu_enabled && $device->{"type"} eq "hdxc") { - $data = getHdxcMenuResponse($command, $device); - } elsif ($menu_req && $menu_enabled && $device->{"type"} eq "ons15454") { - $data = getOnsMenuResponse($command, $device); - } elsif ($menu_req && $menu_enabled && $device->{"type"} eq "ome") { - $data = getOmeMenuResponse($command, $device); - } elsif ($menu_req && $menu_enabled && $device->{"type"} eq "ciena") { - $data = getCienaMenuResponse($command, $device); + # Route the request and return the response to the page + my $response = ""; + if ($menu_req && $enable_menu && $device->{"type"} eq "junos") { + $response = getMenuResponse($command, $device); + } elsif ($menu_req && $enable_menu && $device->{"type"} eq "iosxr") { + $response = getIosMenuResponse($command, $device); + } elsif ($menu_req && $enable_menu && $device->{"type"} eq "hdxc") { + $response = getHdxcMenuResponse($command, $device); + } elsif ($menu_req && $enable_menu && $device->{"type"} eq "ons15454") { + $response = getOnsMenuResponse($command, $device); + } elsif ($menu_req && $enable_menu && $device->{"type"} eq "ome") { + $response = getOmeMenuResponse($command, $device); + } elsif ($menu_req && $enable_menu && $device->{"type"} eq "ciena") { + $response = getCienaMenuResponse($command, $device); } elsif ($menu_req) { - $data = "Menu enabled requests are not configured for this device. Please reload the page."; + $response = "Menu-enabled requests are not configured for this device. Please reload the page."; } else { - $data = getResponse($command, $arguments, $device); + $response = getResponse($command, $arguments, $device); } - - print $cgi->header(-type => "text/html", - -status => "200" ); - print "$data"; + print $cgi->header(-type => "text/html", -status => "200"); + print "$response"; } @@ -222,427 +298,254 @@ sub getResponse { my $arguments = shift; my $device = shift; - my $last = GRNOC::RouterProxy::Logger::getLastTime($logfile); - my $now = time(); - my $diff = $now - $last; - if ($diff < $spamSeconds) { - my $wait = $spamSeconds - $diff; - return "Please wait $wait seconds before sending another command."; + my $spam_warning = filterSpam(); + return $spam_warning if ($spam_warning); + + if (!validCommand($command, $arguments, $device) && $device->{'type'} ne 'TEST') { + my $msg = "Attempt to issue disabled command '$command' for $device->{'name'}"; + $logger->info($msg); + return $msg; } - GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device->{'address'}, $command . " " . $arguments); - if (!validCommand($command, $arguments, $device)) { - return "Disabled Command."; - } + # Append arguments to the command if any + $command = $command . " " . $arguments if ($arguments ne ""); - if ($arguments ne "") { - $command = $command . " " . $arguments; - } + # Add the command to the history log + GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device->{'address'}, $command . " " . $arguments); - my $name = $device->{'name'}; - my $hostname = $device->{'address'}; - my $method = $device->{'method'}; + # Fix encoding (legacy) my $username = $device->{'username'}; my $password = $device->{'password'}; - my $type = $device->{'type'}; - my $port = $device->{'port'}; - - # Fix encoding. I don't know why. This is legecy. Encode::from_to($username, 'utf8', 'iso-8859-1'); Encode::from_to($password, 'utf8', 'iso-8859-1'); my $proxy = GRNOC::RouterProxy->new( - hostname => $hostname, - port => $port, + hostname => $device->{'address'}, + port => $device->{'port'}, + method => $device->{'method'}, + type => $device->{'type'}, username => $username, password => $password, - method => $method, - type => $type, maxlines => $maxlines, config_path => $config_path, timeout => $timeout ); my $result = $proxy->command($command); - # End the timer if the command was successful. + # End the timer if the command was successful and return the result alarm(0); return $result; } -sub getError { - print $cgi->header(-type => "text/html", - -status => "501" ); - print "The requested method does not exist."; -} - -sub makeHTML2 { - my $tt = Template->new({ ABSOLUTE => 1 }); - my $input = "/usr/share/grnoc/routerproxy/templates/index.tt"; - - # If $handler is defined outside the makeHTML2 subroutine an error - # is returned. - # - # Can't use string ("") as a subroutine ref while "strict refs" in - # use at /gnoc/routerproxy/webroot/index.cgi line 302. - my $handler = { device => \&getDevice, - devices => \&getDevices, - error => \&getError, - submit => \&getResponses - }; - # Check if a method has been called on this CGI. - my $method = $cgi->param('method'); - if (defined $method) { - if (!defined $handler->{$method}) { - $handler->{"error"}->(); - } else { - $handler->{$method}->(); - } - # HTML has been printed; Return. - return; - } +sub tl1Connect { + my ($cmd, $device) = @_; - my $html = ""; - my $vars = { network_name => $conf->NetworkName(), - primary_color => $conf->PrimaryColor(), - secondary_color => $conf->SecondaryColor(), - noc_mail => $conf->NOCMail(), - noc_name => $conf->NOCName(), - noc_site => $conf->NOCSite(), - groups => $conf->DeviceGroups(sort_devices => 1) - }; - $tt->process($input, $vars, \$html); - - print $cgi->header(-type => "text/html", - -status => "200" ); - print $html; - return; -} + # Add a history log entry for this command and device + GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device, $cmd); -sub getCienaMenuResponse { + # Create a TL1 connection for issuing commands + $logger->debug("Establishing TL1 connection to $device->{'name'}"); + my $tl1 = GRNOC::TL1->new( + username => $device->{'username'}, + password => $device->{'password'}, + type => $device->{'type'}, + host => $device->{'address'}, + port => $device->{'port'}, + ctag => 1337 + ); + $tl1->connect(); + $tl1->login(); - my $cmd = shift; - my $device = shift; - - my @rows; - my $result; - - my $last = GRNOC::RouterProxy::Logger::getLastTime($logfile); - my $now = time(); - my $diff = $now - $last; - if ($diff < $spamSeconds) { - my $wait = $spamSeconds - $diff; - return "Please wait $wait seconds before sending another command."; - } - GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device, $cmd); - - # make sure the device exists in the config - if ( !defined( $devices->{$device} ) ) { - - return "Requested device is not configured. Please reload the page."; - } - - # use my TL1 module to issue the command - my $name = $devices->{$device}->{'name'}; - my $hostname = $devices->{$device}->{'address'}; - my $method = $devices->{$device}->{'method'}; - my $username = $devices->{$device}->{'username'}; - my $password = $devices->{$device}->{'password'}; - my $type = $devices->{$device}->{'type'}; - my $port = $devices->{$device}->{'port'}; - - my $tl1 = GRNOC::TL1->new( - username => $username, - password => $password, - type => $type, - host => $hostname, - port => $port, - ctag => 1337); - - $tl1->connect(); - $tl1->login(); - - # alarms cmd - if ($cmd eq "alarms") { - - @rows = $tl1->get_alarms(); - $result = retrAlmAll3(@rows); - } - - # eqpt cmd - elsif ($cmd eq "inventory") { - - @rows = $tl1->get_inventory(); - $result = retrEqpt(@rows); - } - - # circuits cmd - elsif ($cmd eq "circuits") { - - @rows = $tl1->get_cross_connects(); - $result = retrCrs2(@rows); - } - - return $result; + # Return the TL1 connection + return $tl1; } -sub getOnsMenuResponse { - my $cmd = shift; - my $device = shift; - - my @rows; - my $result; - - my $last = GRNOC::RouterProxy::Logger::getLastTime($logfile); - my $now = time(); - my $diff = $now - $last; - if ($diff < $spamSeconds) { - my $wait = $spamSeconds - $diff; - return "Please wait $wait seconds before sending another command."; - } - GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device, $cmd); - - # make sure the device exists in the config - if ( !defined( $devices->{$device} ) ) { - - return "Requested device is not configured. Please reload the page."; - } - - # use my TL1 module to issue the command - my $name = $devices->{$device}->{'name'}; - my $hostname = $devices->{$device}->{'address'}; - my $method = $devices->{$device}->{'method'}; - my $username = $devices->{$device}->{'username'}; - my $password = $devices->{$device}->{'password'}; - my $type = $devices->{$device}->{'type'}; - my $port = $devices->{$device}->{'port'}; - - my $tl1 = GRNOC::TL1->new( - username => $username, - password => $password, - type => $type, - host => $hostname, - port => $port, - ctag => 1337); - - $tl1->connect(); - $tl1->login(); - - # alarms cmd - if ($cmd eq "alarms") { - - @rows = $tl1->get_alarms(); - $result = retrAlmAll(@rows); - } - - # circuits cmd - elsif ($cmd eq "circuits") { - - @rows = $tl1->get_cross_connects(); - $result = retrCrs(@rows); - } - - # inventory cmd - elsif ($cmd eq "inventory") { - - @rows = $tl1->get_inventory(); - $result = retrInv(@rows); - } - - return $result; -} +sub getCienaMenuResponse { + my ($cmd, $device) = @_; + my @rows; + my $result; + + my $spam_warning = filterSpam(); + return $spam_warning if ($spam_warning); + + # Get the device from the hash of devices if it exists or return a warning + $device = $devices->{$device} if (exists($devices->{$device}) && defined($devices->{$device})); + if (!defined($device)) { + my $msg = "The requested device \"$device->{'name'}\" does not exist. Please reload the page."; + $logger->warn($msg); + return $msg; + } -sub getOmeMenuResponse { + my $tl1 = tl1Connect($cmd, $device); - my $cmd = shift; - my $device = shift; - - my @rows; - my $result; - - my $last = GRNOC::RouterProxy::Logger::getLastTime($logfile); - my $now = time(); - my $diff = $now - $last; - if ($diff < $spamSeconds) { - my $wait = $spamSeconds - $diff; - return "Please wait $wait seconds before sending another command."; - } - GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device, $cmd); - - # make sure the device exists in the config - if ( !defined( $devices->{$device} ) ) { - - return "Requested device is not configured. Please reload the page."; - } - - # use my TL1 module to issue the command - my $name = $devices->{$device}->{'name'}; - my $hostname = $devices->{$device}->{'address'}; - my $method = $devices->{$device}->{'method'}; - my $username = $devices->{$device}->{'username'}; - my $password = $devices->{$device}->{'password'}; - my $type = $devices->{$device}->{'type'}; - my $port = $devices->{$device}->{'port'}; - - my $tl1 = GRNOC::TL1->new( - username => $username, - password => $password, - type => $type, - host => $hostname, - port => $port, - ctag => 1337); - - $tl1->connect(); - $tl1->login(); - - # alarms cmd - if ($cmd eq "alarms") { - - @rows = $tl1->get_alarms(); - $result = retrAlmAll2(@rows); - } - - # circuits cmd - elsif ($cmd eq "circuits") { - - @rows = $tl1->get_cross_connects(); - $result = retrCrsAll2(@rows); - } - - # inventory cmd - elsif ($cmd eq "inventory") { - - @rows = $tl1->get_inventory(); - $result = retrInventory2(@rows); - # ons15454$result = retrInv(@rows); - } - - return $result; + if ($cmd eq "alarms") { + @rows = $tl1->get_alarms(); + $result = retrAlmAll3(@rows); + } + elsif ($cmd eq "inventory") { + @rows = $tl1->get_inventory(); + $result = retrEqpt(@rows); + } + elsif ($cmd eq "circuits") { + @rows = $tl1->get_cross_connects(); + $result = retrCrs2(@rows); + } + return $result; } -sub getHdxcMenuResponse { - - my $cmd = shift; - my $device = shift; - my @rows; - my $result; - - my $last = GRNOC::RouterProxy::Logger::getLastTime($logfile); - my $now = time(); - my $diff = $now - $last; - if ($diff < $spamSeconds) { - my $wait = $spamSeconds - $diff; - return "Please wait $wait seconds before sending another command."; - } - GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device, $cmd); - - # make sure the device exists in the config - if ( !defined( $devices->{$device} ) ) { - return "Requested device is not configured. Please reload the page."; - } - - # use my TL1 module to issue the command - my $name = $devices->{$device}->{'name'}; - my $hostname = $devices->{$device}->{'address'}; - my $method = $devices->{$device}->{'method'}; - my $username = $devices->{$device}->{'username'}; - my $password = $devices->{$device}->{'password'}; - my $type = $devices->{$device}->{'type'}; - my $port = $devices->{$device}->{'port'}; - - my $tl1 = GRNOC::TL1->new( - username => $username, - password => $password, - type => $type, - host => $hostname, - port => $port, - ctag => 1337); - - $tl1->connect(); - $tl1->login(); - - # alarms cmd - if ($cmd eq "alarms") { +sub getOnsMenuResponse { + my ($cmd, $device) = @_; + my @rows; + my $result; + + my $spam_warning = filterSpam(); + return $spam_warning if ($spam_warning); + + # Get the device from the hash of devices if it exists or return a warning + $device = $devices->{$device} if (exists($devices->{$device}) && defined($devices->{$device})); + if (!defined($device)) { + my $msg = "The requested device \"$device->{'name'}\" does not exist. Please reload the page."; + $logger->warn($msg); + return $msg; + } - @rows = $tl1->get_alarms(); - $result = retrAlmAll(@rows); - } + my $tl1 = tl1Connect($cmd, $device); - # circuits cmd - elsif ($cmd eq "circuits") { + if ($cmd eq "alarms") { + @rows = $tl1->get_alarms(); + $result = retrAlmAll(@rows); + } + elsif ($cmd eq "circuits") { + @rows = $tl1->get_cross_connects(); + $result = retrCrs(@rows); + } + elsif ($cmd eq "inventory") { + @rows = $tl1->get_inventory(); + $result = retrInv(@rows); + } + return $result; +} - @rows = $tl1->get_cross_connects(); - $result = retrCrsAll(@rows); - } - # inventory cmd - elsif ($cmd eq "inventory") { +sub getOmeMenuResponse { + my ($cmd, $device) = @_; + my @rows; + my $result; + + my $spam_warning = filterSpam(); + return $spam_warning if ($spam_warning); + + # Get the device from the hash of devices if it exists or return a warning + $device = $devices->{$device} if (exists($devices->{$device}) && defined($devices->{$device})); + if (!defined($device)) { + my $msg = "The requested device \"$device->{'name'}\" does not exist. Please reload the page."; + $logger->warn($msg); + return $msg; + } - @rows = $tl1->get_inventory(); + my $tl1 = tl1Connect($cmd, $device); - if ($type eq "hdxc") { - $result = retrInventory(@rows); + if ($cmd eq "alarms") { + @rows = $tl1->get_alarms(); + $result = retrAlmAll2(@rows); } - elsif ($type eq "ome") { - $result = retrInventory2(@rows); + elsif ($cmd eq "circuits") { + @rows = $tl1->get_cross_connects(); + $result = retrCrsAll2(@rows); } - else { - $result = retrInv(@rows); + elsif ($cmd eq "inventory") { + @rows = $tl1->get_inventory(); + $result = retrInventory2(@rows); + # ons15454$result = retrInv(@rows); } - } - - return $result; + return $result; } -sub getIosMenuResponse { - my $cmd = shift; - my $device = shift; +sub getHdxcMenuResponse { + my ($cmd, $device) = @_; + my @rows; + my $result; + + my $spam_warning = filterSpam(); + return $spam_warning if ($spam_warning); + + # Get the device from the hash of devices if it exists or return a warning + $device = $devices->{$device} if (exists($devices->{$device}) && defined($devices->{$device})); + if (!defined($device)) { + my $msg = "The requested device \"$device->{'name'}\" does not exist. Please reload the page."; + $logger->warn($msg); + return $msg; + } - if (!$hasIosXML) { - return "IOS XR XML must be installed."; - } + my $tl1 = tl1Connect($cmd, $device); - my $result; + if ($cmd eq "alarms") { + @rows = $tl1->get_alarms(); + $result = retrAlmAll(@rows); + } + elsif ($cmd eq "circuits") { + @rows = $tl1->get_cross_connects(); + $result = retrCrsAll(@rows); + } + elsif ($cmd eq "inventory") { + @rows = $tl1->get_inventory(); + if ($device->{'type'} eq "hdxc") { + $result = retrInventory(@rows); + } + elsif ($device->{'type'} eq "ome") { + $result = retrInventory2(@rows); + } + else { + $result = retrInv(@rows); + } + } + return $result; +} - my $last = GRNOC::RouterProxy::Logger::getLastTime($logfile); - my $now = time(); - my $diff = $now - $last; - if ($diff < $spamSeconds) { - my $wait = $spamSeconds - $diff; - return "Please wait $wait seconds before sending another command."; - } - GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device, $cmd); - # make sure the device exists in the config - if ( !defined( $devices->{$device} ) ) { +sub getIosMenuResponse { + my ($cmd, $device) = @_; + my $result; - return "Requested device is not configured. Please reload the page."; - } + my $spam_warning = filterSpam(); + return $spam_warning if ($spam_warning); - # use IOS XR XML to issue the command - my $name = $devices->{$device}->{'name'}; - my $address = $devices->{$device}->{'address'}; + # Return early if IOS XR XML isn't installed + return "IOS XR XML must be installed" if (!$hasIosXML); - my $cisco = Cisco::IOS_XR->new( - host => $address, - transport => $devices->{$device}->{'method'}, - username => $devices->{$device}->{'username'}, - password => $devices->{$device}->{'password'}, - connection_timeout => $timeout); + # Get the device from the hash of devices if it exists or return a warning + $device = $devices->{$device} if (exists($devices->{$device}) && defined($devices->{$device})); + if (!defined($device)) { + my $msg = "The requested device \"$device->{'name'}\" does not exist. Please reload the page."; + $logger->warn($msg); + return $msg; + } - if ($cmd eq "bgp") { + GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device, $cmd); - my $oper = Cisco::IOS_XR::Data::Operational(); - $result = $oper->BGP->DefaultVRF->NeighborTable->get_keys(); - $result = "
BGP Configuration For $name

" . bgp($result, $oper); - } + # Get the device name to simplify formatting + my $name = $device->{'name'}; - elsif ($cmd eq "isis") { + # Connect to the device + my $cisco = Cisco::IOS_XR->new( + host => $device->{'address'}, + transport => $device->{'method'}, + username => $device->{'username'}, + password => $device->{'password'}, + connection_timeout => $timeout + ); - my $xml = ' + if ($cmd eq "bgp") { + my $oper = Cisco::IOS_XR::Data::Operational(); + $result = $oper->BGP->DefaultVRF->NeighborTable->get_keys(); + $result = "
BGP Configuration For $name

" . bgp($result, $oper); + } + elsif ($cmd eq "isis") { + my $xml = ' @@ -651,13 +554,11 @@ sub getIosMenuResponse { '; - $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); - $result = "
ISIS Configuration For $name

" . isis($result); - } - - elsif ($cmd eq "msdp") { - - my $xml = ' + $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); + $result = "
ISIS Configuration For $name

" . isis($result); + } + elsif ($cmd eq "msdp") { + my $xml = ' @@ -666,13 +567,11 @@ sub getIosMenuResponse { '; - $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); - $result = "
MSDP Configuration For $name

" . msdp($result); - } - - elsif ($cmd eq "interfaces") { - - my $xml = ' + $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); + $result = "
MSDP Configuration For $name

" . msdp($result); + } + elsif ($cmd eq "interfaces") { + my $xml = ' @@ -681,13 +580,11 @@ sub getIosMenuResponse { '; - $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); - $result = "
Interfaces For $name

" . interfaces($result); - } - - elsif ($cmd eq "inventory") { - - my $xml = ' + $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); + $result = "
Interfaces For $name

" . interfaces($result); + } + elsif ($cmd eq "inventory") { + my $xml = ' @@ -695,13 +592,11 @@ sub getIosMenuResponse { '; - $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); - $result = "
Interfaces For $name

" . inventory($result); - } - - elsif ($cmd eq "ipv6Neighbors") { - - my $xml = ' + $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); + $result = "
Interfaces For $name

" . inventory($result); + } + elsif ($cmd eq "ipv6Neighbors") { + my $xml = ' @@ -709,176 +604,100 @@ sub getIosMenuResponse { '; - $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); - $result = "
IPv6 Neighbors For $name

" . ipv6Neighbors($result); - } - - return $result; + $result = XMLin($cisco->send_req($xml)->to_string, forcearray => 1); + $result = "
IPv6 Neighbors For $name

" . ipv6Neighbors($result); + } + return $result; } -sub getMenuResponse { - - my $cmd = shift; - my $device = shift; - - if (!$hasJunoscript) { - return ("Junoscript must be installed.", ""); - } - - my $result; - my $xml; - - my $last = GRNOC::RouterProxy::Logger::getLastTime($logfile); - my $now = time(); - my $diff = $now - $last; - if ($diff < $spamSeconds) { - my $wait = $spamSeconds - $diff; - return "Please wait $wait seconds before sending another command."; - } - GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device, $cmd); - - # make sure the device exists in the config - if (!defined $device) { - return "Requested device $device is not configured. Please reload the page."; - } - - # use JUNOSCRIPT to issue the command - my $name = $device->{'name'}; - my $hostname = $device->{'address'}; - my $method = $device->{'method'}; - my $username = $device->{'username'}; - my $password = $device->{'password'}; - my $type = $device->{'type'}; - - $username = encode("utf8", $username); - $password = encode("utf8", $password); - - my %info = ( - access => $method, - login => $username, - password => $password, - hostname => $hostname); - - my $junos = new JUNOS::Device(%info); - if ($cmd eq "bgp") { - - $result = $junos->command("show bgp summary")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
BGP Summary For $name

" . showBgpSummary($xml); - } - - # show system boot-messages command - elsif ($cmd eq "bootMessages") { - - $result = $junos->command("show system boot-messages")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
System Boot Messages For $name

" . showSystemBootMessages($xml); - } - - # show chassis environment command - elsif ($cmd eq "environment") { - - $result = $junos->command("show chassis environment")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
Chassis Environment For $name

" . showChassisEnvironment($xml); - } - - # show system storge command - elsif ($cmd eq "filesystem") { - - $result = $junos->command("show system storage")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
System Storage For $name

" . showSystemStorage($xml); - } - - # show interfaces detail - elsif ($cmd eq "interfaces") { - - $result = $junos->command("show interfaces")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
Interfaces For $name

" . showInterfaces($xml); - } - - # show chassis hardware command - elsif ($cmd eq "inventory") { - - $result = $junos->command("show chassis hardware")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
Chassis Hardware For $name

" . showChassisHardware($xml); - } - - # show ipv6 neighbors command - elsif ($cmd eq "ipv6Neighbors") { - - $result = $junos->command("show ipv6 neighbors")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
IPv6 Neighbors For $name

" . showIpv6Neighbors($xml); - } - - # show isis adjacency command - elsif ($cmd eq "isis") { - - $result = $junos->command("show isis adjacency")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
ISIS Adjacencies For $name

" . showIsisAdjacency($xml); - } - - # show msdp detail command - elsif ($cmd eq "msdp") { - - $result = $junos->command("show msdp detail")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
MSDP Details For $name

" . showMsdpDetail($xml); - } - - # show multicast statistics command - elsif ($cmd eq "multicastStatistics") { - - $result = $junos->command("show multicast statistics")->toString; +# Helper function to get and format JUNOS command results +sub junosResult { + my ($junos, $cmd, $method, $msg) = @_; + my $result = $junos->command($cmd)->toString; $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
Multicast Statistics For $name

" . showMulticastStatistics($xml); - } - - # show snmp statistics command - elsif ($cmd eq "snmpStatistics") { + my $xml = XMLin($result, forcearray => 1); + $result = "
$msg

" . $method->($xml); +} - $result = $junos->command("show snmp statistics")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
SNMP Statistics For $name

" . showSnmpStatistics($xml); - } - # show version command - elsif ($cmd eq "version") { +sub getMenuResponse { + my ($cmd, $device) = @_; + my $result; + + # Return early if JUNOS Script isn't installed + return ("Junoscript must be installed", "") if (!$hasJunoscript); + + my $spam_warning = filterSpam(); + return $spam_warning if ($spam_warning); + + GRNOC::RouterProxy::Logger::addEntry($logfile, $remoteIP, $device, $cmd); + + # Return a warning if the device doesn't exist + if (!defined($device)) { + my $msg = "The requested device \"$device\" does not exist. Please reload the page."; + $logger->warn($msg); + return $msg; + } - $result = $junos->command("show version")->toString; - $result =~ s/junos://g; - $xml = XMLin($result, forcearray => 1); - $result = "
Version For $name

" . showVersion($xml); - } + # Issue the command with JUNOSCRIPT + my %info = ( + hostname => $device->{'address'}, + access => $device->{'method'}, + login => encode("utf8", $device->{'username'}), + password => encode("utf8", $device->{'password'}), + ); + my $junos = new JUNOS::Device(%info); - return $result; + # Route menu commands to the right JUNOS command and processing method + if ($cmd eq "bgp") { + $result = junosResult($junos, 'show bgp summary', \&showBgpSummary, "BGP Summary for $device->{'name'}"); + } + elsif ($cmd eq "bootMessages") { + $result = junosResult($junos, 'show system boot-messages', \&showSystemBootMessages, "System Boot Messages for $device->{'name'}"); + } + elsif ($cmd eq "environment") { + $result = junosResult($junos, 'show chassis environment', \&showChassisEnvironment, "Chassis Environment for $device->{'name'}"); + } + elsif ($cmd eq "filesystem") { + $result = junosResult($junos, 'show system storage', \&showSystemStorage, "System Storage for $device->{'name'}"); + } + elsif ($cmd eq "interfaces") { + $result = junosResult($junos, 'show interfaces', \&showInterfaces, "Interfaces for $device->{'name'}"); + } + elsif ($cmd eq "inventory") { + $result = junosResult($junos, 'show chassis hardware', \&showChassisHardware, "Chassis Hardware for $device->{'name'}"); + } + elsif ($cmd eq "ipv6Neighbors") { + $result = junosResult($junos, 'show ipv6 neighbors', \&showIpv6Neighbors, "IPv6 Neighbors for $device->{'name'}"); + } + elsif ($cmd eq "isis") { + $result = junosResult($junos, 'show isis adjacency', \&showIsisAdjacency, "ISIS Adjacencies for $device->{'name'}"); + } + elsif ($cmd eq "msdp") { + $result = junosResult($junos, 'show msdp detail', \&showMsdpDetail, "MSDP Details for $device->{'name'}"); + } + elsif ($cmd eq "multicastStatistics") { + $result = junosResult($junos, 'show multicast statistics', \&showMulticastStatistics, "Multicast Statistics for $device->{'name'}"); + } + elsif ($cmd eq "snmpStatistics") { + $result = junosResult($junos, 'show snmp statistics', \&showSnmpStatistics, "SNMP Statistics for $device->{'name'}"); + } + elsif ($cmd eq "version") { + $result = junosResult($junos, 'show version', \&showVersion, "Version for $device->{'name'}"); + } + return $result; } + sub validCommand { my $command = shift; my $args = shift; my $device = shift; my $type = $device->{"type"}; - # Do not allow non alphanumeric-ish chars. This prevents circumventing - # multiple / altered commands. + # Do not allow non alphanumeric-ish chars. + # This prevents circumventing multiple / altered commands. if ($command =~ /[\x00-\x1f]/ || $command =~ /\x7f/ || $args =~ /[\x00-\x1f]/ || $args =~ /\x7f/) { return 0; @@ -888,29 +707,24 @@ sub validCommand { if ($args =~ m/regexp/i) { return 0; } - # Do not allow piping to other commands besides display and match. + # Do not allow piping to other commands besides display and match. if ($args =~ m/\|/ && ($args =~ m/.*\|.*\|.*/ || !($args =~ m/display/ or $args =~ m/match/)) ) { return 0; } - if ($args ne "") { - $command = $command . " " . $args; - } + # Append command arguments to the command if any + $command = $command . " " . $args if ($args ne ""); my $validCommands = $conf->DeviceCommands($device->{"address"}); my $excludeCommands = $conf->DeviceExcludeCommands($device->{"address"}); - # First check to see if this command matches one of the deliberately - # exluded ones. + # Check if the command matches any exluded ones foreach my $excludeCommand (@{$excludeCommands}) { - if ($command =~ /$excludeCommand/) { - return 0; - } + return 0 if ($command =~ /$excludeCommand/); } foreach my $validCommand (@{$validCommands}) { - # For layer2/3, accept anything which has the prefix of a valid - # command. + # For layer2/3, accept anything with the prefix of a valid command if ($type eq "ciena" || $type eq "hdxc" || $type eq "ons15454" || $type eq "ome") { return 1 if ($command eq $validCommand); } else { @@ -918,10 +732,10 @@ sub validCommand { return 1 if ($command =~ m/$validCommand/); } } - return 0; } + sub _parseLocationData { my %args = @_; my $city = $args{'city'}; @@ -930,8 +744,9 @@ sub _parseLocationData { my @loc_array = ($city, $state); my $location_data = ""; - for( my $i = 0; $i <= $#loc_array; $i++) { + for (my $i = 0; $i <= $#loc_array; $i++) { my $loc_element = $loc_array[$i]; + # add opeing paren if first element is defined if($i == 0 && (ref $loc_array[$i] ne ref {} ) ) { $location_data .= "("; @@ -949,7 +764,5 @@ sub _parseLocationData { } } } - return $location_data; - }