1#!/usr/bin/perl 2# vim:ts=4 3# ifstatus.pl v1.0 4# 5# This is an Extension script for the routers.cgi program. Install it 6# in your cgi-bin directory, and modify your MRTG .cfg files to call it: 7# 8# routers.cgi*Extension[targetname]: "Show current interface status" /cgi-bin/ifstatus.cgi camera2-sm.gif 9# 10# See the routers.cgi documentation for how to link this script in to your 11# MRTG .cfg files. This does not require 'insecure' mode in most cases. 12# 13# Remember to change the first line and the default .conf file location below 14# 15# Steve Shipway Jan 2006 16# This script is covered by the terms of the GNU GPL. 17########################################################################### 18# Version 1.0: corrected bug, added number formatting 19########################################################################### 20 21use strict; 22use CGI; 23use Net::SNMP; 24 25my($VERSION) = "v1.0"; 26 27# Variables 28my( $conffile ) = '/u01/etc/routers2.conf'; 29 30my( $device, $community, $targetwindow, $target, $file, $backurl, $ifno ) 31 = ( "","","graph","","","",""); 32my( $routersurl, $msg ); 33my( $q ) = new CGI; 34my( %config, %headeropts ); 35my( $thishost ) = $q->url(); 36my( $NT, $pathsep) = ( 0, '/' ); 37my( %portstat ) = (); 38 39my($SHDESC ) = "1.3.6.1.2.1.2.2.1.2"; 40my($DESC ) = "1.3.6.1.2.1.31.1.1.1.18"; 41my($SYSDESC) = "1.3.6.1.2.1.1.1.0"; 42my($IFINDEX) = "1.3.6.1.2.1.2.2.1.1"; 43my($IFDESCR) = "1.3.6.1.2.1.2.2.1.2"; 44my($IFTYPE ) = "1.3.6.1.2.1.2.2.1.3"; 45my($IFMTU ) = "1.3.6.1.2.1.2.2.1.4"; 46my($IFSPEED) = "1.3.6.1.2.1.2.2.1.5"; 47my($IFADMINSTATUS) = "1.3.6.1.2.1.2.2.1.7"; 48my($IFOPERSTATUS) = "1.3.6.1.2.1.2.2.1.8"; 49my($IFINOCTETS) = "1.3.6.1.2.1.2.2.1.10"; 50my($IFOUTOCTETS) = "1.3.6.1.2.1.2.2.1.16"; 51my($IFINERRORS) = "1.3.6.1.2.1.2.2.1.14"; 52my($IFOUTERRORS) = "1.3.6.1.2.1.2.2.1.20"; 53my($IPIFINDEX) = "1.3.6.1.2.1.4.20.1.2"; 54my($IPROUTEGW) = "1.3.6.1.2.1.4.21.1.7"; 55my($IFDUPLEX) = "1.3.6.1.4.1.9.5.1.4.1.1.10"; 56my($IFNAME) = "1.3.6.1.2.1.31.1.1.1.1"; 57 58my(%DUPLEX) = ( 1=>"Force half duplex", 2=>"Force full duplex", 3=>"Disagreement with device", 4=>"Autonegotiate" ); 59my(%ADMINSTATUS) = ( 1=>"Up", 2=>"Down", 3=>"Testing" ); 60my(%OPERSTATUS) = ( 1=>"Up", 2=>"Down", 3=>"Testing" ); 61 62$thishost =~ /http:\/\/([^\/]+)\//; 63$thishost = $1; 64 65sub fmt($$) { 66 my($n,$d) = @_; 67 my($s) = ''; 68 69 if($n >= 1000000000 ) { 70 $n /= 1000000000; 71 $s = 'G'; 72 } elsif($n >= 1000000 ) { 73 $n /= 1000000; 74 $s = 'M'; 75 } elsif($n >= 1000 ) { 76 $n /= 1000; 77 $s = 'K'; 78 } 79 80 return sprintf('%.'.$d.'f %s',$n,$s); 81} 82 83####################################################################### 84# readconf: pass it a list of section names 85sub readconf(@) 86{ 87 my ($inlist, $i, @secs, $sec); 88 89 @secs = @_; 90 %config = (); 91 92 # set defaults 93 %config = ( 'routers.cgi-confpath' => ".",); 94 95 ( open CFH, "<".$conffile ) || do { 96 errorpage( "Error: unable to open file $conffile"); 97 exit 0; 98 }; 99 100 $inlist=0; 101 $sec = ""; 102 while( <CFH> ) { 103 /^\s*#/ && next; 104 /^\s*\[(\S*)\]/ && do { 105 $sec = $1; $inlist=0; 106 foreach $i ( @secs ) { if ( $i eq $1 ) { $inlist=1; last; } } 107 next; 108 }; 109 if ( $inlist ) { /(\S+)\s*=\s*(\S.*?)\s*$/ and $config{"$sec-$1"}=$2; } 110 } 111 close CFH; 112 113 # Activate NT compatibility options. 114 # $^O is the OS name, NT usually produces 'MSWin32'. By checking for 'Win' 115 # we should be able to cover most possibilities. 116 if ( (defined $config{'web-NT'} and $config{'web-NT'}=~/[1y]/i) 117 or $^O =~ /Win/ or $^O =~ /DOS/i ) { 118 $pathsep = "\\"; 119 $NT = 1; 120 } 121 122 # some path corrections: remove trailing path separators on f/s paths 123 foreach ( qw/dbpath confpath graphpath graphurl/ ) { 124 $config{"routers.cgi-$_"} =~ s/[\/\\]$//; 125 } 126 $config{"routers.cgi-iconurl"}.= '/' 127 if( $config{"routers.cgi-iconurl"} !~ /\/$/); 128 129} 130####################################################################### 131# read $file and get the interface details for $target 132sub read_file() 133{ 134 my( $c, $i, $f ); 135 if( $ifno != "" ) { # we already know it 136 $portstat{'Interface Number'} = $ifno; 137 return if($community) ; 138 } 139 $f = $config{"routers.cgi-confpath"}."$pathsep$file"; 140 if(! -r $f or !$target) { 141 errorpage("Cannot read file $f"); 142 return; 143 } 144 open CFG, "<$f" or return; 145 while( <CFG> ) { 146 if( /^\s*Target\[(\S+)\]\s*:\s*(\S+):(\S+)@([^:\s]+)/i ) { 147 next if($1 ne $target); 148 $c = $3; $i = $2; 149 $community = $c if($c); 150 if( !$ifno and $i =~ /\d+/ ) { $ifno = $i; 151 $portstat{'Interface Number'} = $i; last; } 152 if( $i =~ /^\/([\d\.]+)/ ) { 153 $portstat{'IP Address'} = $1; last; } 154 if( $i =~ /^#(\S+)/ ) { 155 $portstat{'Interface Name'} = $1; last; } 156 last if($ifno); 157 } elsif( /^\s*routers2?\.cgi\*Ifno\[(\S+)\]\s*:\s*(\d+)/i ) { 158 next if($1 ne $target); 159 $ifno = $2; 160 last; 161 } 162 } 163 close CFG; 164 return; 165} 166####################################################################### 167# return error message if there was an error 168# load up the $portstat hash, keyed on description 169sub snmpquery() 170{ 171 my( $tick, $cross ); 172 my( $snmp, $snmperr, $resp, $resp2 ); 173 $tick = $q->img({ src=>($config{'routers.cgi-iconurl'}."tick-sm.gif"), 174 alt=>"Yes", border=>0}); 175 $cross = $q->img({ src=>($config{'routers.cgi-iconurl'}."cross-sm.gif"), 176 alt=>"No", border=>0}); 177 178 ($snmp, $snmperr) = Net::SNMP->session( 179 -hostname=>$device, -community=>$community, 180 -timeout=>4 ); 181 if($snmperr) { return $snmperr; } 182 183 $resp = $snmp->get_request( 184 "$IFDESCR.$ifno", 185 "$IFADMINSTATUS.$ifno", 186 "$IFOPERSTATUS.$ifno", 187 "$IFSPEED.$ifno", 188 "$IFMTU.$ifno", 189 "$IFTYPE.$ifno", 190 "$IFINOCTETS.$ifno", 191 "$IFOUTOCTETS.$ifno", 192 "$IFINERRORS.$ifno", 193 "$IFOUTERRORS.$ifno" 194 ); 195 if(!$resp) { $snmp->close; return "Unable to read device details"; } 196 $portstat{"Description"} = $resp->{"$IFDESCR.$ifno"}; 197 $portstat{"Errors total IN"} = $resp->{"$IFINERRORS.$ifno"}; 198 $portstat{"Errors total OUT"} = $resp->{"$IFOUTERRORS.$ifno"}; 199 $portstat{"Traffic total IN"} = fmt($resp->{"$IFINOCTETS.$ifno"},2)."B"; 200 $portstat{"Traffic total OUT"} = fmt($resp->{"$IFOUTOCTETS.$ifno"},2)."B"; 201 $portstat{"Interface Speed"} = fmt($resp->{"$IFSPEED.$ifno"},0)."bps"; 202 $portstat{"MTU"} = $resp->{"$IFMTU.$ifno"}." bytes"; 203 $portstat{"Admin status"} = 204 ($resp->{"$IFADMINSTATUS.$ifno"}==1?$tick:$cross) 205 ." (".$ADMINSTATUS{$resp->{"$IFADMINSTATUS.$ifno"}}.")"; 206 $portstat{"Operational status"} = 207 ($resp->{"$IFOPERSTATUS.$ifno"}==1?$tick:$cross) 208 ." (".$OPERSTATUS{$resp->{"$IFOPERSTATUS.$ifno"}}.")"; 209 if( !defined $portstat{"Interface Name"} ) { 210 $resp2 = $snmp->get_request( "$IFNAME.$ifno" ); 211 $portstat{"Interface Name"} = $DUPLEX{$resp2->{"$IFNAME.ifno"}} 212 if($resp2); 213 } 214 if( $portstat{"Interface Name"} =~ /(\d+).*\/(\d+)$/ ) { 215 $resp2 = $snmp->get_request( "$IFDUPLEX.$1.$2" ); 216 $portstat{"Duplex"} = $DUPLEX{$resp2->{"$IFDUPLEX.$1.$2"}} if($resp2); 217 } 218 219 $snmp->close; 220 return 0; 221} 222####################################################################### 223sub do_footer() 224{ 225 print $q->hr."\n"; 226 print $q->a({ href=>"javascript:location.reload(true);" }, 227 $q->img({alt=>"Refresh", border=>0, 228 src=>$config{'routers.cgi-iconurl'}."refresh.gif" }))."\n"; 229 print $q->hr.$q->small("$VERSION: Interface Status extension script for routers.cgi")."\n"; 230 print $q->end_html(); 231} 232####################################################################### 233# at this point, %portstat should hold the interface number that we query. 234sub mypage() 235{ 236 my( $javascript ) = "function RefreshMenu() 237 { 238 var mwin; var uopts; 239 mwin = parent.menu; 240 uopts = 'T'; 241 if( parent.menub ) { mwin = parent.menub; uopts = 't'; } 242 mwin.location = '".$routersurl."?if=__none&rtr=" 243 .$q->escape($file)."&page=menu&xmtype=options&uopts='+uopts; 244 }"; 245 246 print $q->start_html({-title=>"Current Interface Status", 247 -script=>$javascript, -onLoad=>"RefreshMenu()"}); 248 249 print $q->h1("Current Interface Status"); 250 251 print "<TABLE border=2 align=center>\n"; 252 foreach ( sort keys %portstat ) { 253 print "<TR><TD>$_</TD><TD>".$portstat{$_}."</TD></TR>\n"; 254 } 255 256 print "</TABLE>\n"; 257 258 do_footer(); 259} 260 261####################################################################### 262sub errorpage($) 263{ 264 my( $javascript ) = "function RefreshMenu() 265 { 266 var mwin; var uopts; 267 mwin = parent.menu; 268 uopts = 'T'; 269 if( parent.menub ) { mwin = parent.menub; uopts = 't'; } 270 mwin.location = '".$routersurl."?if=__none&rtr=" 271 .$q->escape($file)."&page=menu&xmtype=options&uopts='+uopts; 272 }"; 273 274 print $q->start_html({-title=>"Error", 275 -script=>$javascript, -onLoad=>"RefreshMenu()"}); 276 277 print $q->h1("Unable to retrieve interface status"); 278 279 print $q->p($_[0])."\n"; 280 do_footer(); 281 282} 283####################################################################### 284 285# Process parameters 286$device = $q->param('h') if(defined $q->param('h')); 287$file = $q->param('fi') if(defined $q->param('fi')); 288$target = $q->param('ta') if(defined $q->param('ta')); 289$ifno = $q->param('ifno') if(defined $q->param('ifno')); 290$community = $q->param('c') if(defined $q->param('c')); 291$backurl = $q->param('b') if(defined $q->param('b')); 292$targetwindow = $q->param('t') if(defined $q->param('t')); 293$conffile = $q->param('conf') if(defined $q->param('conf')); 294$routersurl = $q->param('url') if(defined $q->param('url')); 295$routersurl = "http://$thishost/cgi-bin/routers2.cgi" if(!$routersurl); 296 297readconf('routers.cgi','web'); 298 299# HTTP headers 300%headeropts = ( -expires=>"now" ); 301$headeropts{target} = $targetwindow if($targetwindow); 302print $q->header(\%headeropts); 303 304read_file; 305 306if(!$target) { 307 errorpage("No target given"); 308} elsif(!$community) { 309 errorpage("Unable to identify an SNMP community for the device."); 310} elsif($ifno == "") { 311 errorpage("Unable to identify a valid interface on the device."); 312} else { 313 if( $msg = snmpquery() ) { 314 errorpage("Unable to SNMP query the device.\n$msg"); 315 } else { 316 mypage(); 317 } 318} 319 320# End 321exit(0); 322