summaryrefslogtreecommitdiffstats
path: root/bin/lg.cgi.in
diff options
context:
space:
mode:
authorTar Committer <tar@ocjtech.us>2004-01-12 03:17:26 +0000
committerTar Committer <tar@ocjtech.us>2004-01-12 03:17:26 +0000
commit989312339ea2e16579803a48700628c5469e327a (patch)
tree967ee77195819d70f2dc675444e92340bb98e0d6 /bin/lg.cgi.in
parentff168ecfe045c690c24d5bbc5a3062bf9d64120c (diff)
downloadrancid-989312339ea2e16579803a48700628c5469e327a.tar.gz
rancid-989312339ea2e16579803a48700628c5469e327a.tar.xz
rancid-989312339ea2e16579803a48700628c5469e327a.zip
Imported from rancid-2.3.rc1.tar.gz.rancid-2.3.rc1
Diffstat (limited to 'bin/lg.cgi.in')
-rw-r--r--bin/lg.cgi.in867
1 files changed, 867 insertions, 0 deletions
diff --git a/bin/lg.cgi.in b/bin/lg.cgi.in
new file mode 100644
index 0000000..ad08c68
--- /dev/null
+++ b/bin/lg.cgi.in
@@ -0,0 +1,867 @@
+#! @PERLV_PATH@
+##
+## $Id: lg.cgi.in,v 1.47 2004/01/11 03:49:13 heas Exp $
+##
+## Copyright (C) 1997-2004 by Terrapin Communications, Inc.
+## All rights reserved.
+##
+## This software may be freely copied, modified and redistributed
+## without fee for non-commerical purposes provided that this license
+## remains intact and unmodified with any RANCID distribution.
+##
+## There is no warranty or other guarantee of fitness of this software.
+## It is provided solely "as is". The author(s) disclaim(s) all
+## responsibility and liability with respect to this software's usage
+## or its effect upon hardware, computer systems, other software, or
+## anything else.
+##
+## Except where noted otherwise, rancid was written by and is maintained by
+## Henry Kilmer, John Heasley, Andrew Partan, Pete Whiting, and Austin Schutz.
+##
+#
+# The original original lookingglass s/w was written by Ed Kern. It was
+# a single script that used to be available at http://nitrous.digex.net/.
+# Provided by permission and modified beyond recognition.
+#
+# Looking glass
+# vars: query, router, args
+
+BEGIN {
+$me = $0;
+$me =~ s/.*\/(\S+)$/$1/;
+}
+
+use CGI qw/:standard escapeHTML/;
+use POSIX qw(strftime);
+use Sys::Syslog;
+use LockFile::Simple qw(lock trylock unlock);
+
+my($BASEDIR) = "@prefix@";
+my($SYSCONFDIR) = "@sysconfdir@";
+my($pingcmd) = "@LG_PING_CMD@";
+
+my($query, $max_time_diff, $cache_dir, $cloginrc, @results);
+my($type, $router_param, $remote_user, $arg, $router, $mfg);
+
+my($LG_CACHE_DIR, $LG_CLOGINRC, $LG_IMAGE, $LG_LOG, $LG_ROUTERDB, $LG_AS_REG);
+my($LG_BGP_RT, $LG_CACHE_TIME, $LG_SINGLE, $LG_STRIP);
+
+if (!defined($ENV{HOME})) { $ENV{HOME} = "."; }
+
+# note: the following functions are duplicated between lgform.cgi and lg.cgi
+# to avoid the need for module inclusion headaches from within a httpd context.
+# it is just easier to be self-contained.
+# SO, ANY CHANGES HERE SHOULD BE REFLECTED IN THE OTHER .cgi.
+
+# logging
+sub dolog
+{
+ my($level, $msg) = @_;
+
+ if (defined($LG_LOG) && $LG_LOG !~ /\//) {
+ openlog($me, "pid", $LG_LOG);
+ syslog($level, "%s", $msg);
+ closelog;
+ } else {
+ local(*LOG);
+ my($file);
+ if (defined($LG_LOG)) {
+ $file = $LG_LOG;
+ } else {
+ $file = "$cache_dir/lg.log";
+ }
+ # log date, hostname, query, addr
+ if (open(LOG, ">>$file") == 0) {
+ # stderr, if all else fails
+ printf(STDERR "[" . strftime("%a %b %e %H:%M:%S %Y", gmtime) .
+ "] could not open log file $file: $!\n");
+ printf(STDERR $msg);
+ } else {
+ printf(LOG $msg);
+ close(LOG);
+ }
+ }
+ return;
+}
+
+# read LG configuration file
+sub readconf
+{
+ my($conffile, $cmds);
+ local(*CONF);
+ if (defined($ENV{LG_CONF})) {
+ $conffile = $ENV{LG_CONF};
+ } elsif (-e "lg.conf") {
+ $conffile = "lg.conf";
+ } else {
+ $conffile = "$SYSCONFDIR/lg.conf";
+ }
+
+ if (! -f $conffile) {
+ return;
+ }
+
+ if (open(CONF, "< $conffile")) {
+ while (<CONF>) {
+ next if (/^\s*(#|$)/);
+ $cmds .= $_;
+ }
+ close(CONF);
+ eval $cmds;
+ } else {
+ printf(STDERR "ERROR: couldn\'t open the configuration file: " .
+ "$conffile: $!\n");
+ exit(1);
+ }
+
+ return;
+}
+
+# read router.db file
+sub readrouters
+{
+ my($rtrdb);
+ local(*RTR);
+
+ if (defined($LG_ROUTERDB)) {
+ $rtrdb = $LG_ROUTERDB;
+ } else {
+ $rtrdb = "$SYSCONFDIR/router.db";
+ }
+
+ if (! -f $rtrdb) {
+ my(@dirs, $dir);
+ # if the router.db file does not exist, try to compile the list from
+ # the rancid group router.db files.
+ local(*DIR);
+ if (! opendir(DIR, $BASEDIR)) {
+ dolog(LOG_ERR, "ERROR: couldn\'t read $BASEDIR: $!\n");
+ } else {
+ while ($dir = readdir(DIR)) {
+ next if ($dir =~ /^(\.|\.\.|CVS|bin|etc|logs|util)$/);
+ push(@dirs, $dir) if (-d "$BASEDIR/$dir");
+ }
+ closedir(DIR);
+
+ foreach $dir (@dirs) {
+ if (! opendir(DIR, "$BASEDIR/$dir")) {
+ dolog(LOG_ERR, "ERROR: couldn\'t read $BASEDIR/$dir: $!\n");
+ next;
+ }
+ closedir(DIR);
+ next if (! -f "$BASEDIR/$dir/router.db");
+ if (open(RTR, "< $BASEDIR/$dir/router.db")) {
+ while (<RTR>) {
+ next if (/^\s*(#|$)/);
+ # fqdn:mfg:state
+ @record = split('\:', $_);
+ next if ($record[2] !~ /up/i || $record[1] !~ /(cisco|foundry|juniper)/);
+ push(@rtrlist, join(':', ($record[0], $record[1])));
+ $rtrlabels{join(':', ($record[0], $record[1]))} = $record[0];
+ }
+ close(RTR);
+ } else {
+ dolog(LOG_ERR, "ERROR: couldn\'t open the router.db " .
+ "file: $BASEDIR/$dir/router.db: $!\n");
+ }
+ }
+ }
+ } else {
+ if (open(RTR, "< $rtrdb")) {
+ while (<RTR>) {
+ next if (/^\s*(#|$)/);
+ # fqdn:mfg:state
+ @record = split('\:', $_);
+ next if ($record[2] !~ /up/i || $record[1] !~ /(cisco|foundry|juniper)/);
+ push(@rtrlist, join(':', ($record[0], $record[1])));
+ $rtrlabels{join(':', ($record[0], $record[1]))} = $record[0];
+ }
+ close(RTR);
+ } else {
+ dolog(LOG_ERR, "ERROR: couldn\'t open the router.db file: " .
+ "$rtrdb: $!\n");
+ exit(1);
+ }
+ }
+
+ return;
+}
+
+# the remaining functions are particular to lg.cgi.
+
+# return true if $router is a member of @rtrlist
+sub arraymember {
+ my($rtrlist) = shift;
+ my($router) = shift;
+ my($r);
+
+ foreach $r (@$rtrlist) {
+ $r = (split(':', $r))[0];
+ return(1) if ($r eq $router);
+ }
+
+ return(0);
+}
+
+# check reachability and lock file before attempting to connect to device
+# return non-zero on error.
+sub DoRsh
+{
+ my ($router, $mfg, $cmd, $arg) = @_;
+ my($ctime) = time();
+ my($val);
+
+ my($lckobj) = LockFile::Simple->make(-delay => $lock_int,
+ -max => $max_lock_wait, -hold => $max_lock_hold);
+
+ if ($pingcmd =~ /\d$/) {
+ `$pingcmd $router`;
+ } else {
+ `$pingcmd $router 56 1`;
+ }
+ if ($?) {
+ print "$router is unreachable. Try again later.\n";
+ return(-1);
+ }
+ if (! $lckobj->lock("$cache_dir/$router")) {
+ print "$router is busy. Try again later.\n";
+ return(-1);
+ }
+ $val = &DoCmd($router, $mfg, $cmd, $arg);
+ $lckobj->unlock("$cache_dir/$router");
+ return($val);
+}
+
+# run commands on the router. return non-zero on error.
+sub DoCmd
+{
+ my($rtr, $mfg, $cmd, $arg) = @_;
+ local(*CMD);
+
+ if ($mfg =~ /foundry/i) {
+ open(CMD, "sh -c \"flogin -f $cloginrc -c \'$cmd $arg\' $rtr\" 2>&1 |");
+ } elsif ($mfg =~ /juniper/i) {
+ open(CMD, "sh -c \"jlogin -f $cloginrc -c \'$cmd $arg\' $rtr\" 2>&1 |");
+ } else {
+ open(CMD, "sh -c \"clogin -noenable -f $cloginrc -c \'$cmd $arg\' $rtr\" 2>&1 |");
+ }
+ while (<CMD>) {
+ tr/\015//d;
+ if (/^error:/i) {
+ dolog(LOG_ERR, $_);
+ if ($LG_STRIP) { undef(@results); }
+ push(@results, $_);
+ print @results;
+ return(-1);
+ }
+ push(@results, $_);
+ if (/$cmd/) {
+ ($prompt) = /^(\S*)[\#>]/;
+ if ($LG_STRIP) {
+ undef(@results);
+ } else {
+ print @results;
+ }
+ last;
+ }
+ }
+
+ while (<CMD>) {
+ last if /^$prompt[\#>]/;
+ tr/\015//d;
+ print $_;
+ push(@results, $_);
+ }
+ while (<CMD>) {}
+ close(CMD);
+
+ return(0);
+}
+
+##
+# Subroutine: Error
+# Usage: &Error("msg"));
+# Description: displays an error and exits.
+##
+sub Error {
+ my($msg) = @_;
+
+ my($q) = new CGI();
+ print $q->header;
+ if ($LG_STYLE) {
+ print $query->start_html(-title => "LookingGlass Results - $router",
+ -style => {'src' => $LG_STYLE});
+ } else {
+ print $query->start_html(-title => "LookingGlass Results - $router");
+ }
+
+ # add the company image, LG_IMAGE
+ print $LG_IMAGE;
+
+
+ print <<EOF ;
+ <br>
+ <B><FONT SIZE=+2>Looking Glass Error:</FONT></B>
+ <p>
+ $msg
+ <br>
+ <hr>
+ $LG_INFO
+EOF
+
+ print $q->end_html;
+ exit(0);
+}
+
+# convert an ipv4 address mask to prefix length
+sub mask2len {
+ my($mask) = shift;
+ my($a, $b, $c, $d) = split('\.', $mask);
+ my($p, $len);
+
+ $p = ~ (($a << 24) + ($b << 16) + ($c << 8) + $d);
+ for ($len = 32; $p > 0; $len --) {
+ $p = $p >> 1;
+ }
+
+ return($len);
+}
+
+# end the page and exit.
+sub end_page {
+
+ print <<END ;
+ </pre>
+ <!--- end page content --->
+ </body>
+END
+
+ print $query->end_html;
+ exit(0);
+}
+
+# start the page and log the transaction...
+sub start_page {
+ my($mfg) = @_;
+ my($cmd);
+
+ my($timestr) = strftime("%a %b %e %H:%M:%S %Y", gmtime);
+ dolog(LOG_INFO, sprintf("%s %s %s %s\n",
+ $ENV{REMOTE_HOST}, $ENV{REMOTE_ADDR}, $ENV{REMOTE_USER},
+ "- - [$timestr] $type $router $arg"));
+ print $query->header;
+ if ($LG_STYLE) {
+ print $query->start_html(-title =>"LookingGlass form",
+ -style => {'src' => $LG_STYLE});
+ } else {
+ print $query->start_html(-title =>"LookingGlass from");
+ }
+
+ $timestr = strftime("%a %b %e %H:%M:%S %Y %Z", gmtime);
+
+ # add the company image, LG_IMAGE
+ print $LG_IMAGE;
+
+ if ($mfg =~ /foundry/i) {
+ $cmd = $foundryCmd{$type};
+ } elsif ($mfg =~ /juniper/i) {
+ $cmd = $juniperCmd{$type};
+ } else {
+ $cmd = $ciscoCmd{$type};
+ }
+
+ print <<HEAD ;
+ </b></font>
+ <font size=+3><b><h1>Looking Glass Results - $router
+ </b></h1></font>
+ <hr>
+
+ <center>
+ <b>Date:</b> $timestr
+ <p>
+ <b>Query:</b> $cmd
+ <br>
+HEAD
+
+ if ($arg) { print "<b>Argument(s):</b> $arg\n"; }
+ print "</center>\n";
+
+ print <<END ;
+ <!--$cached-->
+ </center>
+ <p>
+ <pre>
+END
+
+ return;
+}
+
+
+# Main()
+# read the configuration file if it exists.
+readconf();
+
+# The script will now cache the results as simple files in the $cache_dir,
+# named after the type of query (queries must, of course, be one word with
+# no spaces). Modify $LG_CACHE_TIME to set the lifetime for cache entries.
+# for most web servers, cache_dir must be writable by uid nobody
+if (defined($LG_CACHE_DIR)) {
+ $cache_dir = $LG_CACHE_DIR;
+} else {
+ $cache_dir = "./tmp";
+}
+
+# read routers table to get @rtrlist
+readrouters();
+
+# when to display cache? max time difference (in seconds)
+if (defined($LG_CACHE_TIME)) {
+ $max_time_diff = $LG_CACHE_TIME;
+} else {
+ $max_time_diff = "600" ;
+}
+
+# max seconds to wait for a 'router' lock to free up
+$max_lock_wait = 30;
+$lock_int = 5;
+$max_lock_hold = 300;
+
+# clogin setup
+if (defined($LG_CLOGINRC)) {
+ $cloginrc = $LG_CLOGINRC;
+} else {
+ $cloginrc = "$ENV(HOME)/.cloginrc";
+}
+
+$query = new CGI;
+
+# get form data and validate
+$type = ($query->param('query'))[0];
+$router_param = ($query->param('router'))[0];
+$remote_user = $ENV{REMOTE_USER};
+$arg = ($query->param('args'))[0];
+# handle multiple args
+$arg =~ s/["'`]//g; # these are BS in any arg for any query
+@arg = split(' ', $arg);
+
+# verify router, commands, arguments, etc.
+($router, $mfg) = split(':', $router_param);
+if (!defined($type) || !defined($router) || $router eq "") {
+ &Error("You must at least choose a Query and a router. Try buying " .
+ "a clue.\n");
+}
+
+if ($arg !~ /^[-A-Za-z0-9|_\/ \.^\$]*$/) {
+ &Error("Funny characters in argument; ignoring.\n");
+}
+if (length($arg) >= 50) {
+ &Error("Argument string too long; ignoring. \n");
+}
+
+if (! arraymember(\@rtrlist, $router)) {
+ my($timestr) = strftime("%a %b %e %H:%M:%S %Y", gmtime);
+ dolog(LOG_WARNING, sprintf("%s %s %s %s\n",
+ $ENV{REMOTE_HOST}, $ENV{REMOTE_ADDR}, $ENV{REMOTE_USER},
+ "- - [$timestr] lg.cgi: attempt to access $router\n"));
+ Error("access to $router not permitted");
+}
+
+# conversion of command "type" passed from lgform.cgi to the vendor's syntax.
+if ($mfg =~ /cisco/i) {
+ %mfgCmd = (
+ # Debug Queries
+ log => "show logging",
+ # Interface Queries
+ framerelay => "show frame-relay pvc",
+ interface => "show interface",
+ intbrief => "show ip interface", # switch in {interface}
+ # Routing Queries
+ damp => "show ip bgp dampened-paths",
+ neighbor => "show ip bgp neighbor",
+ # Multicast Queries
+ mbgp => "show ip mbgp",
+ mbgpsum => "show ip mbgp summary",
+ mneighbor => "show ip bgp neighbor",
+ msdp => "show ip msdp summary",
+ msdpsa => "show ip msdp sa-cache",
+ msess => "show ip sdr",
+ mroute => "show ip mroute",
+ pim_interface => "show ip pim interface",
+ pim_neighbor => "show ip pim neighbor",
+ pim_rp => "show ip pim rp mapping",
+ # IPv6 Queries
+ #
+ #acl => "show access-list",
+ #aspath => "show ip as-path-access-list",
+ #communitylist => "show ip community-list",
+ ping => "ping",
+ prefix => "show ip bgp",
+ prefixlist => "show ip prefix-list",
+ regex => "show ip bgp regex",
+ route => "show ip route",
+ routemap => "show route-map",
+ rpf => "show ip rpf",
+ summary => "show ip bgp summary",
+ trace => "traceroute",
+ v6_bgp => "show bgp ipv6",
+ v6_interface => "show ipv6 interface",
+ v6_summary => "show bgp ipv6 summary"
+ );
+} elsif ($mfg =~ /foundry/i) {
+ %mfgCmd = (
+ # Debug Queries
+ log => "show log",
+ ping => "ping",
+ trace => "traceroute",
+ # Interface Queries
+ #framerelay => "show frame-relay pvc", # no compatible command
+ interface => "show interface",
+ # Routing Queries
+ damp => "show ip bgp dampened-paths",
+ neighbor => "show ip bgp neighbor",
+ #regex => "show ip bgp aspath-regex",
+ route => "show ip route",
+ summary => "show ip bgp summary",
+ # Multicast Queries
+ #mbgp => "show ip mbgp",
+ #mbgpsum => "show bgp summary",
+ #mneighbor => "show ip bgp neighbor",
+ mroute => "show ip mroute",
+ msdp => "show ip msdp summary",
+ msdpsa => "show ip msdp sa-cache",
+ msess => "show ip sdr",
+ pim_interface => "show ip pim interface",
+ pim_neighbor => "show ip pim neighbor",
+ pim_rp => "show ip pim rp mapping",
+ rpf => "show ip rpf",
+ # IPv6 Queries
+ # v6_bgp => "show bgp ipv6",
+ # v6_interface => "show ipv6 interface",
+ # v6_summary => "show bgp ipv6 summary"
+ #
+ #acl => "show access-list",
+ #aspath => "show ip as-path-access-list",
+ #communitylist => "show ip community-list",
+ routemap => "show route-map",
+ prefix => "show ip bgp",
+ prefixlist => "show ip prefix-list"
+ );
+} elsif ($mfg =~ /juniper/i) {
+ %mfgCmd = (
+ # Debug Queries
+ log => "show log messages",
+ ping => "ping rapid count 5",
+ trace => "traceroute",
+ # Interface Queries
+ framerelay => "show frame-relay pvc",
+ interface => "show interface",
+ #intbrief => "show ip interface", # switch in {interface}
+ # Routing Queries
+ damp => "show route damping suppressed terse table inet.0",
+ neighbor => "show bgp neighbor",
+ regex => "show route table inet.0 aspath-regex",
+ summary => "show bgp summary",
+ # Multicast Queries
+ mbgp => "show route table inet.2 terse",
+ mbgpsum => "show bgp summary",
+ mneighbor => "show bgp neighbor",
+ mroute => "show multicast route extensive",
+ msdp => "show msdp",
+ msdpsa => "show msdp source-active",
+ msess => "show multicast sessions",
+ pim_interface => "show pim interface",
+ pim_neighbor => "show pim neighbors",
+ pim_rp => "show pim rps",
+ pim_join => "show pim join",
+ rpf => "show multicast rpf",
+ # IPv6 Queries
+ v6_bgp => "show route table inet6.0",
+ v6_interface => "show interface",
+ v6_summary => "show bgp summary",
+ #
+ #acl => "show access-list",
+ #aspath => "show ip as-path-access-list",
+ #communitylist => "show ip community-list",
+ prefix => "show route table inet.0",
+ prefixlist => "show policy",
+ route => "show route table inet.0 terse",
+ routemap => "show policy"
+ );
+}
+
+# construct Display command from configuration
+%cmdDisp=();
+foreach $qtype (sort keys(%$queries)) {
+ next if (! scalar(%{$queries->{$qtype}}));
+ foreach $sub_type (sort keys(%{$queries->{$qtype}})) {
+ $cmdDisp{$sub_type} = $queries->{$qtype}->{$sub_type};
+ }
+}
+
+# make sure the command is not disabled
+if (! defined($cmdDisp{$type})) {
+ &Error("Unknown command type: $type\n");
+}
+
+# not all cmds/queries are implemented for all platforms
+if (! defined($mfgCmd{$type})) {
+ Error("$cmdDisp{$type} not implemented for $mfg or no suitable " .
+ "equivalent exists. sorry.\n");
+}
+$cmd = $mfgCmd{$type};
+
+# handle each query/command type
+if ($type eq "prefix" || $type eq "mbgp" || $type eq "route" ) {
+ if ($arg[0] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+ &Error("The IP address \"$arg[0]\" is not valid and lacking an " .
+ "address would over-burden our router.\n");
+ } elsif (defined($arg[1]) && $arg[1] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+ &Error("The IP netmask \"$arg[1]\" is not valid.\n");
+ }
+ if ($mfg =~ /juniper/i && defined($arg[1])) {
+ $arg = $arg[0] . "/" . mask2len($arg[1]);
+ }
+} elsif ($type eq "v6_route" ){
+ # XXX: is this check of the address arg correct and pedantic?
+ if ($arg[0] !~ /[0-9a-fA-F:]+$/) {
+ &Error("The IPv6 address \"$arg[0]\" is not valid.\n");
+ }
+} elsif ($type eq "framerelay") {
+ if ($mfg =~ /juniper/) {
+ &Error("Juniper does not have a show frame-relay pvc command. " .
+ "Use show interface.\n");
+ }
+ if ($arg[0] > 15 && $arg[0] < 1024) {
+ $arg = $arg[0];
+ } else {
+ undef($arg);
+ }
+} elsif ($type eq "interface" || $type eq "v6_interface") {
+
+ # XXX: wtf is arg[1]?
+# if ($arg[1] =~ /[-\/0-9:.]+/) {
+# $arg = $arg[0] . " " . $arg[1];
+# } else {
+
+ if ($mfg =~ /(cisco|foundry)/) {
+ if ($arg[0] !~ /^b[^ ]+[0-9]/i && $arg[0] =~ /^b/i) {
+ $type = "intbrief";
+ $arg = "brief";
+ } else {
+ $arg = $arg[0];
+ }
+ } elsif ($mfg =~ /juniper/) {
+ my($optind) = 0;
+ # arg 0 may be an intf name or a display option, but there can
+ # only be 2 args
+ $arg = "";
+ while ($optind <= $#arg && $optind < 2) {
+ $arg[$optind] =~ s/brief/terse/;
+ if ($arg[$optind] =~ /^([a-z0-9]{2}\-\d+\/\d+\/\d+(:\d+)?)/i) {
+ $arg .= " $1";
+ } elsif ($arg[$optind] =~ /^det/i) {
+ $arg .= " detail";
+ } elsif ($arg[$optind] =~ /^ter/i) {
+ $arg .= " terse";
+ } elsif ($arg[$optind] =~ /^ext/i) {
+ $arg .= " extensive";
+ }
+ $optind += 1;
+ }
+ }
+} elsif ($type eq "log") {
+ if ($arg[0] =~ /^\s*\|?$/) {
+ shift(@arg);
+ }
+ $arg[0] =~ s/^\s*\|?//;
+ if ($arg[0] !~ /^\s*$/) {
+ if ($mfg =~ /cisco/i) {
+ $arg = " | include " . join(' ', @arg);
+ } elsif ($mfg =~ /juniper/i) {
+ $arg = " | match \"" . join(' ', @arg) . "\"";
+ } else {
+ undef($arg);
+ }
+ } else {
+ undef($arg);
+ }
+} elsif ($type eq "ping" || $type eq "trace") {
+ if ($arg[0] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+ if ($arg[0] !~ /^[A-Za-z0-9._-]+$/) {
+ &Error("That argument ($arg[0]) is not valid.\n");
+ }
+ }
+ $arg = $arg[0];
+} elsif ($type eq "aspath" || $type eq "communitylist") {
+ if ($arg[0] !~ /^\d+$/ || ($arg[0] < 1 && $arg[0] > 199)) {
+ &Error("That argument ($arg[0]) is not valid.\n");
+ }
+ $arg = $arg[0];
+} elsif ($type eq "acl") {
+ if ($arg[0] !~ /^\d+$/ || ($arg[0] < 100 && $arg[0] > 199) ||
+ ($arg[0] < 1300 && $arg[0] > 2699)) {
+ &Error("That argument ($arg[0]) is not valid.\n");
+ }
+ $arg = $arg[0];
+ # don't show the jewels
+ # XXX: this error msg is useless, but show acl is un-implemented.
+ &Error($mfg) if ($arg == 98 || $arg == 99);
+} elsif ($type eq "prefixlist" || $type eq "routemap") {
+ if ($arg[0] !~ /^[0-9A-Za-z][^\s\"]*$/) {
+ &Error("That argument ($arg[0]) is not valid.\n");
+ }
+ $arg = $arg[0];
+} elsif ($type eq "regex") {
+ # bgp as-path regex
+ $arg = $arg[0];
+ if ($#arg >= 1) {
+ for ($n = 1; $n <= $#arg; $n++) { $arg .= " " . $arg[$n]; }
+ }
+ # remove leading/trailing whitespace
+ $arg =~ s/^\s*//; $arg =~ s/\s*$//;
+ if ($arg !~ /^[0-9_ ^.*+?[\])\(-]*\$?$/ || $arg =~ /^\s*$/) {
+ &Error("That argument ($arg[0]) is not valid.\n");
+ }
+ # pathetic excuses for lookups
+ if ($arg =~ /^[_.* ^]*(\*|1|701|1239|1280|1740|3561|5462|10303)+[_\$]*$/ ||
+ $arg =~ /^[_.* ^]*(1|701|1239|1280|1740|3561|5462|10303)+[_ .]*[\[*.]/) {
+ &Error("Get real. Such a query has potential to over-burden our " .
+ "router.\nLook that up on your own router.\n");
+ }
+ if ($mfg =~ /juniper/) {
+ $arg =~ s/_/ /g;
+ # pre-junos 4.4 does not allow anchors
+ if ($arg =~ /\^\$/) {
+ $arg =~ "()";
+ } else {
+ $arg =~ s/[\$^]/ /g;
+ }
+ $arg = "\"$arg\"";
+ }
+ # escape any ()s
+ $arg =~ s/([\(\)])/\\$1/g;
+} elsif ($type eq "neighbor") {
+ if ($arg[0] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+ if ($arg[0] !~ /([A-Za-z0-9-]*.)*[A-Za-z0-9-]*.(com|edu|net|org)/) {
+ &Error("That argument ($arg[0]) is not valid.\n");
+ }
+ }
+ $arg = $arg[0];
+ if (defined($arg[1]) && $arg[1] =~ /^(a|ro|f|re)/) {
+ if ($mfg =~ /juniper/) {
+ if ($arg[1] =~ /^a/) {
+ if (defined($LG_BGP_RT)) {
+ $cmd = "show route table inet.0 all advertising-protocol ".
+ "bgp";
+ }
+ } elsif ($arg[1] =~ /^f/) {
+ if (defined($LG_BGP_RT)) {
+ $cmd = "show route damping table inet.0 all ".
+ "receive-protocol bgp";
+ }
+ } elsif ($arg[1] =~ /^r/) {
+ if (defined($LG_BGP_RT)) {
+ $cmd = "show route table inet.0 all receive-protocol bgp";
+ }
+ }
+ } else {
+ if ($arg[1] =~ /^a/) {
+ if (defined($LG_BGP_RT)) { $arg .= " advertised-routes"; }
+ } elsif ($arg[1] =~ /^f/) {
+ $arg .= " flap-statistics";
+ } elsif ($arg[1] =~ /^ro/) {
+ if (defined($LG_BGP_RT)) { $arg .= " routes"; }
+ } elsif ($arg[1] =~ /^re/) {
+ if (defined($LG_BGP_RT)) { $arg .= " received-routes"; }
+ }
+ }
+ }
+} elsif ($type eq "mneighbor") {
+ if ($arg[0] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+ if ($arg[0] !~ /([A-Za-z0-9-]*.)*[A-Za-z0-9-]*.(com|edu|net|org)/) {
+ &Error("That argument ($arg[0]) is not valid.\n");
+ }
+ }
+ $arg = $arg[0];
+ if (defined($arg[1]) && $arg[1] =~ /^(a|ro|f|re)/) {
+ if ($mfg =~ /juniper/) {
+ if ($arg[1] =~ /^a/) {
+ $cmd .= " advertised-routes";
+ } elsif ($arg[1] =~ /^f/) {
+ $cmd .= " flap-statistics";
+ } elsif ($arg[1] =~ /^ro/) {
+ $cmd .= " routes";
+ } elsif ($arg[1] =~ /^re/) {
+ $cmd .= " received-routes";
+ }
+ } else {
+ if ($arg[1] =~ /^a/) {
+ $arg .= " advertised-routes";
+ } elsif ($arg[1] =~ /^f/) {
+ $arg .= " flap-statistics";
+ } elsif ($arg[1] =~ /^ro/) {
+ $arg .= " routes";
+ } elsif ($arg[1] =~ /^re/) {
+ $arg .= " received-routes";
+ }
+ }
+ }
+} elsif ($type eq "damp" || $type eq "summary" || $type eq "mbgpsum") {
+ undef($arg);
+}
+
+# make stdout unbuffered, so result page streams.
+$| = 1;
+start_page();
+
+# cache the following
+if ($type eq "summary" || $type eq "mbgpsu" || $type eq "damp"
+ || $type eq "log") {
+ if (!$arg) {
+ # cache requests with no addr/argument
+ local(*CACHE);
+
+ my($file) = "$cache_dir/$type" ;
+ $file =~ s/\s+/_/g;
+ $file .= "_$router";
+
+ if (-e $file) {
+ # see if cache exists
+ @stat = stat($file);
+ $ftime = $stat[9];
+ $dtime = time() - $stat[9];
+
+ # see if we are within cache time
+ if ($dtime <= $max_time_diff) {
+ if (open(CACHE, "<$file") == 0) {
+ dolog(LOG_ERR, "couldnt open cache file $file: $!\n");
+ } else {
+ print "<b>From cache (number of seconds old (max " .
+ "$max_time_diff)):</b> $dtime\n\n";
+ while (<CACHE>) { print $_; }
+ close(CACHE);
+ &end_page();
+ }
+ }
+ }
+
+ # else, execute command and save to a new cache file
+ if (! &DoRsh($router, $mfg, $cmd, $arg)) {
+ if (open(CACHE, ">$file") == 0) {
+ dolog(LOG_ERR, "couldnt create cache file $file: $!\n");
+ exit(1);
+ } else {
+ printf(CACHE "@results");
+ close(CACHE);
+ }
+ }
+ } else {
+ &DoRsh($router, $mfg, $cmd, $arg);
+ }
+ &end_page();
+} else {
+ &DoRsh($router, $mfg, $cmd, $arg);
+ &end_page();
+}
+
+exit(0);