From 25c2b7c2c8a333b276c3499bcce004137d4b4fe0 Mon Sep 17 00:00:00 2001 From: Tar Committer Date: Fri, 24 Nov 2000 22:14:14 +0000 Subject: Imported from rancid-2.1b.tar.gz. --- util/lg/lg.cgi.in | 449 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 449 insertions(+) create mode 100755 util/lg/lg.cgi.in (limited to 'util/lg/lg.cgi.in') diff --git a/util/lg/lg.cgi.in b/util/lg/lg.cgi.in new file mode 100755 index 0000000..0320b7d --- /dev/null +++ b/util/lg/lg.cgi.in @@ -0,0 +1,449 @@ +#!@PERLV_PATH@ +# Looking glass +# vars: query, router, args + +BEGIN { +$me = $0; +$me =~ s/.*\/(\S+)$/$1/; +} + +use CGI qw/:standard/; +use POSIX qw(strftime); +use Sys::Syslog; +use LockFile::Simple qw(lock trylock unlock); + +my($BASEDIR) = "@prefix@"; +my($pingcmd) = "@LG_PING_CMD@"; + +my($query, $max_time_diff, $cache_dir, $cloginrc, @results); +my($type, $router_param, $remote_user, $arg, $router, $mfg); + +if (!defined($ENV{HOME})) { $ENV{HOME} = "."; } + +# read LG configuration file +sub readconf +{ + my($conffile, $cmds); + local(*CONF); + if (defined($env{LG_CONF})) { + $conffile = $env{LG_CONF}; + } else { + $conffile = "$BASEDIR/util/lg/lg.conf"; + } + + if (! -f $conffile) { + return; + } + + if (open(CONF, "< $conffile")) { + while () { + next if (/^\s*(#|$)/); + $cmds .= $_; + } + close(CONF); + eval $cmds; + } else { + printf(STDERR "ERROR: couldn\'t open the configuration file: $conffile: $!\n"); + exit(255); + } + + return; +} +# 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 + open(LOG,">>$file") ; + printf(LOG "$msg"); + close(LOG); + } + return; +} +# run commands on the router +sub DoRsh +{ + my ($router, $mfg, $type, $arg) = @_; + my($ctime) = time(); + + 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 ($?) { + return ("$router is unreachable. Try again later.\n"); + } + if (! $lckobj->lock("$cache_dir/$router")) { + return ("$router is busy. Try again later.\n"); + } + @results = &DoCmd($router, $mfg, $type, $arg); + $lckobj->unlock("$cache_dir/$router"); + return (@results); +} +sub DoCmd +{ + my($rtr, $mfg, $type, $arg) = @_; + local(*CMD); + + if ($mfg =~ /juniper/i) { + open(CMD, "jlogin -f $cloginrc -c \'$juniperCmd{$type} $arg\' $rtr |"); + $cmd = $juniperCmd{$type}; + } else { + open(CMD, "clogin -noenable -f $cloginrc -c \'$ciscoCmd{$type} $arg\' $rtr |"); + $cmd = $ciscoCmd{$type}; + } + while () { + tr/\015//d; + if (/^error:/i) { + dolog(LOG_ERR, $_); + return ($_); + } +# push(@results, $_); + if (/$cmd/) { + ($prompt) = /^(\S*)[\#>]/; +# push(@results, "prompt = $prompt\n\n"); + last; + } + } + while () { + last if /^$prompt[\#>]/; + tr/\015//d; + push(@results, $_); + } + while () {} + close(CMD); + return @results; +} +# convert a 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); +} +# create the page and log the transaction... +sub print_results { + + my($timestr) = strftime("%a %b %e %H:%M:%S %Y %Z", 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; + print $query->start_html("Looking Glass Results - $router"); + + $timestr = strftime("%a %b %e %H:%M:%S %Y %Z", gmtime); + + # add the company image, LG_IMAGE + print $LG_IMAGE; + + print < +

Looking Glass Results - $router +

+
+ +
+ Date: $timestr +

+ Query: $cmdDisp{$type} +
+HEAD + + if ($arg) { print "Argument(s): $arg\n"; } + print "

\n"; + + print < + +

+

+END
+
+    if ($seconds) { print "From cache (number of seconds old (max $max_time_diff)): $seconds\n\n" ; }
+
+    print @results;
+
+    print <
+	
+	
+END
+
+    print $query->end_html;
+    exit;
+
+}  #end sub print_results
+
+
+# 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 no 
+## spaces).  Modify $max_time_diff to set the lifetime for each cache.
+## Currently, cache lifetime is the same for all queries.
+# 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";
+}
+
+# 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 = "$BASEDIR/.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 = split(' ', $arg);
+
+# verify commands, arguments, etc.
+($router, $mfg) = split(':', $router_param);
+if (!defined($type) || !defined($router)) {
+    $results[0] = "You must at least choose a Query and a router.  Try buying a clue.\n";
+    &print_results;
+}
+
+# conversion of command "type" passed from lgform.cgi to the vendor's syntax.
+%ciscoCmd = (	
+		#acl => "sh access-list",
+		#aspath => "sh ip as-path-access-list",
+		#communitylist => "sh ip community-list",
+		damp => "sh ip bgp dampened-paths",
+		framerelay => "sh frame-relay pvc",
+		interface => "sh interface",
+		intbrief => "sh ip interface",
+		log => "sh logging",
+		mbgp => "sh ip mbgp",
+		mbgpsum => "sh ip mbgp summary",
+		regex => "sh ip bgp regex",
+		route => "sh ip route",
+		#routemap => "sh route-map",
+		ping => "ping",
+		prefix => "sh ip bgp",
+		prefixlist => "sh ip prefix-list",
+		summary => "sh ip bgp summary",
+		trace => "traceroute"
+	);
+%juniperCmd = (	
+		#acl => "sh access-list",
+		#aspath => "sh ip as-path-access-list",
+		#communitylist => "sh ip community-list",
+		damp => "show route damping suppressed terse table inet.0",
+		interface => "sh interface",
+		log => "show log messages",
+		mbgp => "sh route table inet.2 terse",
+		mbgpsum => "sh bgp summary",
+		#regex => "sh route table inet.0 aspath-regex",
+		route => "sh route table inet.0",
+		#routemap => "sh route-map",
+		ping => "ping rapid count 5",
+		prefix => "sh route table inet.0",
+		#prefixlist => "sh ip prefix-list",
+		summary => "sh bgp summary",
+		trace => "traceroute"
+	);
+%cmdDisp = (	
+		#acl => "show access-list",
+		#aspath => "show ip as-path-access-list",
+		#communitylist => "show ip community-list",
+		damp => "show ip bgp dampened-paths",
+		log => "show logging",
+		mbgp => "show ip mbgp",
+		mbgpsum => "show ip mbgp summary",
+		regex => "show ip bgp regex",
+		route => "show ip route",
+		#routemap => "show route-map",
+		ping => "ping",
+		prefix => "show ip bgp",
+		prefixlist => "show ip prefix-list",
+		summary => "show ip bgp summary",
+		trace => "traceroute"
+	);
+
+# not all cmds/queries are implemented for junipers
+if ($mfg =~ /juniper/ && ! defined($juniperCmd{$type})) {
+    $results[0] = "$cmdDisp{$type} not implemented for junipers.  sorry.\n";
+    &print_results;
+}
+
+
+if ($type eq "prefix" || $type eq "mbgp" || $type eq "route" ) {
+    if ($arg[0] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+	$results[0] = "The IP address \"$arg[0]\" is not valid and lacking an address would over-burden our router.\n";
+	&print_results;
+    } elsif (defined($arg[1]) && $arg[1] !~ /^\d+\.\d+\.\d+\.\d+$/) {
+	$results[0] = "The IP netmask \"$arg[1]\" is not valid.\n";
+	&print_results;
+    }
+    if ($mfg =~ /juniper/i && defined($arg[1])) {
+	$arg = $arg[0] . "/" . mask2len($arg[1]);
+    }
+} elsif ($type eq "framerelay") {
+    if ($arg[0] > 15 && $arg[0] < 1024) {
+	$arg = $arg[0];
+    } else {
+	undef($arg);
+    }
+} elsif ($type eq "interface") {
+    if ($arg[1] =~ /[-\/0-9:.]+/) {
+	$arg = $arg[0] . " " . $arg[1];
+    } else {
+	if ($arg[0] =~ /^b/i && $mfg =~ /cisco/i) {
+	    $type = "intbrief";
+	    $arg = "brief";
+	} else {
+	    $arg = $arg[0];
+	}
+    }
+} elsif ($type eq "log") {
+    $arg[0] =~ s/^\s*|//;
+    if ($arg[0] =~ /^\s*$/) {
+	shift(@arg);
+    }
+    if ($arg[0] !~ /^\s*$/) {
+	if ($mfg =~ /cisco/i) {
+	    $arg = " | include " . join(' ', @arg);
+	} elsif ($mfg =~ /juniper/i) {
+	    $arg = " | match \"" . join(' ', @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-]*.)*[A-Za-z0-9-]*.(com|edu|net|org)/) {
+	    $results[0] = "That argument ($arg[0]) is not valid.\n";
+	    &print_results;
+	}
+    }
+    $arg = $arg[0];
+} elsif ($type eq "aspath" || $type eq "communitylist") {
+    if ($arg[0] !~ /^\d+$/ || ($arg[0] < 1 && $arg[0] > 199)) {
+	$results[0] = "That argument ($arg[0]) is not valid.\n";
+	&print_results;
+    }
+    $arg = $arg[0];
+} elsif ($type eq "acl") {
+    if ($arg[0] !~ /^\d+$/ || ($arg[0] < 100 && $arg[0] > 199) ||
+					($arg[0] < 1300 && $arg[0] > 2699)) {
+	$results[0] = "That argument ($arg[0]) is not valid.\n";
+	&print_results;
+    }
+    $arg = $arg[0];
+    # don't show the jewels
+    &print_results if ($arg == 98 || $arg == 99);
+} elsif ($type eq "prefixlist" || $type eq "routemap") {
+    if ($arg[0] !~ /^[A-Za-z][^\s\"]*$/) {
+	$results[0] = "That argument ($arg[0]) is not valid.\n";
+	&print_results;
+    }
+    $arg = $arg[0];
+} elsif ($type eq "regex") {
+    $arg = $arg[0];
+    if ($#arg > 1) {
+	for ($n = 1; $n <= $#arg - 1; $n++) { $arg .= " " . $arg[$n]; }
+    }
+    if ($arg !~ /^[0-9_ ^.*+?[\])\(-]*\$?$/ || $arg =~ /^\s*$/) {
+	$results[0] = "That argument ($arg[0]) is not valid.\n";
+	&print_results;
+    }
+    # pathetic excuses for lookups
+    if ($arg =~ /^[_.* ^]*(\*|1|701|1239|1280|1740|3561|5462|10303)+[_\$]*$/ ||
+	$arg =~ /^[_.* ^]*(1|701|1239|1280|1740|3561|5462|10303)+[_ .]*[\[*.]/) {
+	$results[0] = "Get real.  Such a query has potential to over-burden our router.\nLook that up on your own router.\n";
+	&print_results;
+    }
+    # escape any ()
+    $arg =~ s/([\(\)])/\\$1/g;
+} elsif ($type eq "damp" || $type eq "summary" || $type eq "mbgpsum") {
+    undef($arg);
+}
+
+# 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) {
+		open(CACHE,"$file") ; 
+		while () { push(@results, $_); }
+		close CACHE ;
+		$seconds = $dtime;
+		&print_results ; 
+	    }
+	}
+
+	# else, execute command and save to a new cache file
+	open(CACHE,">$file") || die "couldnt create cache file $file" ; 
+
+	@results = &DoRsh($router, $mfg, $type, $arg);
+
+	print CACHE "@results";
+	close CACHE ;
+    } else {
+	@results = &DoRsh($router, $mfg, $type, $arg);
+    }
+    &print_results ; 
+} # end dampened-paths/flap-statistics
+
+@results = &DoRsh($router, $mfg, $type, $arg);
+&print_results ;
+
+exit ; 
-- 
cgit