./iog-1.03/ 40755 0 0 0 7743561462 10471 5ustar rootwheel./iog-1.03/Artistic100444 0 0 13737 7743014353 12314 0ustar rootwheel The "Artistic License" Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder as specified below. "Copyright Holder" is whoever is named in the copyright or copyrights for the package. "You" is you, if you're thinking about copying or distributing this Package. "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as uunet.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) give non-standard executables non-standard names, and clearly document the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. You may embed this Package's interpreter within an executable of yours (by linking); this shall be construed as a mere form of aggregation, provided that the complete Standard Version of the interpreter is so embedded. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whoever generated them, and may be sold commercially, and may be aggregated with this Package. If such scripts or library files are aggregated with this Package via the so-called "undump" or "unexec" methods of producing a binary executable image, then distribution of such an image shall neither be construed as a distribution of this Package nor shall it fall under the restrictions of Paragraphs 3 and 4, provided that you do not represent such an executable image as a Standard Version of this Package. 7. C subroutines (or comparably compiled subroutines in other languages) supplied by you and linked into this Package in order to emulate subroutines and variables of the language defined by this Package shall not be considered part of this Package, but are the equivalent of input as in Paragraph 6, provided these subroutines do not change the language in any way that would cause it to fail the regression tests for the language. 8. Aggregation of this Package with a commercial distribution is always permitted provided that the use of this Package is embedded; that is, when no overt attempt is made to make this Package's interfaces visible to the end user of the commercial distribution. Such use shall not be construed as a distribution of this Package. 9. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End ./iog-1.03/ioglogo.gif100644 0 0 6346 7743014353 12715 0ustar rootwheelGIF89avI~~~}}}|||{{{zzzyyyxxxwwwvvvuuutttsssrrrqqqpppooonnnmmmlllkkkjjjiiihhhgggfffeeedddcccbbbaaa```___^^^]]]\\\[[[ZZZYYYXXXWWWVVVUUUTTTSSSRRRQQQPPPOOONNNMMMLLLKKKJJJIIIHHHGGGFFFEEEDDDCCCBBBAAA@@@???>>>===<<<;;;:::999888777666555444333222111000///...---,,,+++***)))((('''&&&%%%$$$###"""!!!  ,vI@HDC#*dHQ"AD2jȱ#>X 4p$;BC A &>x @IGD\0X&;S9=!IĖs hbNBa@jD @DC@Hdaa 8rD. D$< pO ف]} LbB4\!  $1 C nA ݍӫ_>=fLQAB 6 Mq.0FMa8b!*AaFX ,Yފ,Fu4T$,"h0hgTiITTJ訥6A(6"D <9DdGJD_A^$qEБ#APp=rA0S5$A9 ݕmG (IjJtv)A gh@P#: &W@Uz"6V- *BJK!ʁVg{2sb!0:@* )@0`3`A8+AmXfAD"@ 8SB%4aZj1)@ "Q⓯B${ .ڥ*!Vdy.E! (LI>ΈWvέtWFw"DtGZ(`z$AԛЀbAFjy_pv6s 4IlXmrk q[ɚǟ 8G Cr9c0F8B. @!AKFSg:SooDV.K{GYbc{f(@Cԣ:¡EN"Y@ p3R&mtx#NAeI  0B"2c! @ `B,1 G$l˘+) |3C@@o ધ,A`@Z Ao0En*TRil*FkEP}^+0&E 8)Hv(`xQkHjP$z( h`zT,L " d4SB$0L`.\x@6Tib#F_!MA ` 5B8peB7LP[ȷ.2.| W P'?! QbE!-(:A' Tc QFiXIժhDHR(aKxKp,FpA;ԨK8͂*dh m `R fa@ PFY9 x@&MC\25` ѹ@hR:)tA ӋQoJZulUHN @&_&>ddqA@zA!$"XjzU33a-I0L^ h@MpFdXɳHH (Vz*.*Ft5z$ G>i"Cor[dLR[DfUby-n}ǍI)ٟFhhwp ܘ2ڽ #g!^7Zvw %Nnߎ7^) #PcPy^]A2|Pİ2'zN~&wd^- &f wX0qG<@ Iqс¤nBZ|gdCjR"d 9 6!l|XxaclBGI,~$yRB@QVկP@U ˄71?0 u#%6Hf݄6G6\ryO2ltEx8MA380M`x*CtC<0x07w;./iog-1.03/iog.cfg100644 0 0 2256 7743556335 12035 0ustar rootwheel# IOG - Host configuration file # # format: # [name:hostname:community:uptimeOID:uptimedatapath] # name:hostname:community:inOID:outOID:path # # name - name of system (used for file names, use a valid unix file name) # hostname - hostname or IP of switch/host # community - community string for switch/host # inOID - the in octets OID in the format of ifInOctets.# or # use ifHCInOctets.# for SNMPv2c 64-bit counters. # outOID - the out octets OID in the format of ifOutOctets.# or # use ifHCOutOctets.# for SNMPv2c 64-bit counters. # uptimeOID - either sysUpTime.0 (cisco) or sysUpTime # path - the path where all files will be stored. # uptimedatapath - path to keep data file for host uptime info. # # *IMPORTANT*: You must select the proper sysUpTime value for your # device otherwise problems will arrive when these devices reboot. # # ex.: # [switch1:192.168.0.10:public:sysUpTime.0:/www/iog] # sw1-port1:192.168.0.10:public:ifInOctets.1:ifOutOctets.1:/www/iog/ # sw1-port2:192.168.0.10:public:ifInOctets.2:ifOutOctets.2:/www/iog/ # # [switch2:192.168.0.11:public:sysUpTime:/www/iog] # sw2-port20:192.168.0.11:public:ifHCInOctets.20:ifHCOutOctets.20:/www/iog/ # ./iog-1.03/iog100700 0 0 50752 7743330061 11276 0ustar rootwheel#!/usr/bin/perl # # IOG v1.03 - Input/Output Grapher # Copyright (c) 2000-2003 James Dogopoulos # # Please read the "Artistic" license included. # # E-mail iog@dynw.com with any bug reports, # fixes or comments. # BEGIN{ if ($ARGV[0] eq "NT") { $main::OS = 'NT'; } else { $main::OS = 'UNIX'; } $main::SL = { UNIX=>'/', NT=>'\\' }->{$main::OS}; $main::PS = { UNIX=>':', NT=>';' }->{$main::OS}; $main::binpath =""; if ($0 =~ /^(.+\Q${main::SL}\E)/) { $main::binpath="$1"; } else { foreach $pathname ( split ${main::PS}, $ENV{'PATH'}) { if ((($main::OS eq 'NT') && (-e "$pathname${main::SL}$0")) || (-x "$pathname${main::SL}$0")) { $main::binpath=$pathname; last; } } } unshift (@INC,$main::binpath); } use SDBM_File; use BER; use SNMP_Session; use Fcntl; my($inoid,$outoid,$host,$community,$snmpget,$datafile,$cfgfile,%inf); my($inoctets,$outoctets,$path,$iogver,$hostreset,$kbsize,$mbsize,$gbsize); $BER::pretty_print_timeticks="0"; $cfgfile="$main::binpath"."iog.cfg"; $iogver="v1.03"; # Default Byte Sizes $kbsize="1024"; $mbsize="1048576"; $gbsize="1024"; # Date/Time stuff # my @weekdays = qw(Sunday Monday Tuesday Wednesday Thursday Friday Saturday); my @months = qw(January February March April May June July August September October November December); my %days = (1 => "1st", 2 => "2nd", 3 => "3rd", 21 => "21st", 22 => "22nd", 23 => "23rd", 31 => "31st"); my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); $lday = $mday - 1; sub last_mday { my ($month, $year) = @_; ( qw(31 0 31 30 31 30 31 31 30 31 30 31) )[$month] || 28 + (($year % 100 && !($year % 4))|| !($year % 400)); } if ($days{$mday}) { $pday = $days{$mday}; $nday = $days{$lday}; } else { $pday = $mday."th"; $nday = $lday."th"; } # Read config file. # open(CONFIG,$cfgfile) || die("Cannot open $cfgfile!"); while () { s/\s+$//g; # remove whitespace at the end of the line s/\s/ /g; # replace whitespace by space next if /^\s*\#/; # ignore comment lines next if /^\s*$/; # ignore empty lines if ($_ =~ /\[.*.\]/) { chkuptime($_); next; } my($name,$host,$community,$inoid,$outoid,$path) = split(/:/, $_); $path =~ s/\n//; $datafile = "$name".".dat"; my @results = snmpget($host,$community,$inoid,$outoid); next if ($results[0] eq "error"); $inoctets = $results[0]; $outoctets = $results[1]; main($name,$host,$community,$inoid,$outoid,$path,$datafile); } close(CONFIG); # SNMP Get routine. Thanks to Simon Leinen for the SNMP module. # http://www.switch.ch/misc/leinen/snmp/perl/ # sub snmpget { my($host, $community, $inoid, $outoid) = @_; my($response, $bindings, $binding, $value, $oid, $session, @results); my %oidnames = qw(ifInOctets 1.3.6.1.2.1.2.2.1.10 ifOutOctets 1.3.6.1.2.1.2.2.1.16 ifHCInOctets 1.3.6.1.2.1.31.1.1.1.6 ifHCOutOctets 1.3.6.1.2.1.31.1.1.1.10); my ($inoidname,$inoidport) = split(/\./, $inoid); my ($outoidname,$outoidport) = split(/\./, $outoid); $inoid = encode_oid(split(/\./, ($oidnames{$inoidname} . ".$inoidport"))); $outoid = encode_oid(split(/\./, ($oidnames{$outoidname} . ".$outoidport"))); my @oids = ($inoid,$outoid); if ($inoidname =~ /HC/i or $outoidname =~ /HC/i) { $session = SNMPv2c_Session->open($host, $community, 161) or return "error"; } else { $session = SNMP_Session->open($host, $community, 161) or return "error"; }; if ($session->get_request_response (@oids)) { $response = $session->pdu_buffer; ($bindings) = $session->decode_get_response ($response); while ($bindings ne '') { ($binding,$bindings) = decode_sequence ($bindings); ($oid,$value) = decode_by_template ($binding, "%O%@"); push (@results, pretty_print($value)); } return @results; } else { warn "SNMP Error: $SNMP_Session::errmsg\n"; return "error"; } } sub snmpgetup { my($host, $community, $inoid) = @_; my($response, $bindings, $binding, $value, $oid, $result); my %oidnames = qw(sysUpTime 1.3.6.1.2.1.1.3 sysUpTime.0 1.3.6.1.2.1.1.3.0); $inoid = encode_oid(split(/\./, $oidnames{$inoid})); my $session = SNMP_Session->open($host, $community, 161) or return "0"; if ($session->get_request_response ($inoid)) { $response = $session->pdu_buffer; ($bindings) = $session->decode_get_response ($response); while ($bindings ne '') { ($binding,$bindings) = decode_sequence ($bindings); ($oid,$value) = decode_by_template ($binding, "%O%@"); $result = pretty_print($value); } return $result; } else { warn "SNMP Error: $SNMP_Session::errmsg\n"; return 0; } } sub chkuptime { $_ =~ s/\[|\]//g; my($uphost,$upip,$upcommunity,$upoid,$upfile) = split (/:/, $_); my $upresult = snmpgetup($upip,$upcommunity,$upoid); tie(%inf, 'SDBM_File', ($upfile."$main::SL"."uptimes"), O_RDWR|O_CREAT, 0640) or print "WARNING: Error opening uptime database file!\n"; if ($upresult < $inf{$uphost} && $upresult > "1") { $hostreset = "1"; } else { $hostreset = "0"; } if ($upresult > "1") { $inf{$uphost} = $upresult; } untie(%inf); } sub main { my($name,$host,$community,$inoid,$outoid,$path,$datafile) = @_; tie(%inf, 'SDBM_File', ($path."$main::SL".$datafile), O_RDWR|O_CREAT, 0640) or print "Error opening database file for $name at $host\n"; if (-s (($path."$main::SL".$datafile) . ".pag")) { if ($inf{day} != $mday && $hour > "0") { newday(); dailyhtml($name,$host,$path); } if ($inf{month} != $mon) { $newmon = "1"; newday(); dailyhtml($name,$host,$path); newmonth($name,$path); monthlyhtml($name,$host,$path); } if ($inf{year} != ($year + "1900")) { newyear($name,$path); } if (!$newmon) { updatedata(); } if ($inf{day} != $mday) { $newday = "1"; } else { $newday = "0"; } hourlyhtml($name,$host,$path,$newday); } else { createdata(); hourlyhtml($name,$host,$path); } untie(%inf); } # create data file if ! exist # sub createdata { %inf = (lastin => $inoctets, lastout => $outoctets, month => $mon, day => $mday, year => ($year + "1900")); } # # sub newyear { my($name,$path) = @_; my($count); $count = 0; while ($count <= "11") { delete $inf{"m" . $count}; $count++; } # move yearly html file. $oldfile="$path"."$main::SL"."$name"."-months".".html"; $newfile="$path"."$main::SL"."$name"."-year".($year).".html"; if ($main::OS eq "NT") { system("move /Y $oldfile $newfile"); } else { system("mv $oldfile $newfile"); } $inf{year} = ($year + "1900"); } # # sub newmonth { my($name,$path) = @_; my($count,$intotal,$outtotal,$inoct,$outoct); # get MB total for the month and store it. $count = 1; while ($count <= "31") { if ($inf{"d" . $count}) { ($inoct,$outoct) = split(/:/, $inf{"d" . $count}); $intotal += $inoct; $outtotal += $outoct; } $count++; } $intotal = ($intotal / $mbsize); $outtotal = ($outtotal / $mbsize); $inf{"m" . $inf{month}} = "$intotal:$outtotal"; # clear days $count = 1; while ($count <= "31") { delete $inf{"d" . $count}; $count++; } # move monthly html file. $oldfile="$path"."$main::SL"."$name"."-days".".html"; $newfile="$path"."$main::SL"."$name"."-month".($mon).".html"; if ($main::OS eq "NT") { system("move /Y $oldfile $newfile"); } else { system("mv $oldfile $newfile"); } # set $inf{month} to the new month. $inf{month} = $mon; } # newday: # run every time the day of the month changes on the system. # sub newday { my($count,$nmday,$intotal,$outtotal,$inoct,$outoct); # get megabyte total for the day and store it. # $count = 0; while ($count <= "23") { if ($inf{$count}) { ($inoct,$outoct) = split(/:/, $inf{$count}); $intotal += $inoct; $outtotal += $outoct; } $count++; } if ($newmon) { $nmday = last_mday($inf{month}, $inf{year}); } else { $nmday = ($mday - 1); } $inf{"d" . $nmday} = "$intotal:$outtotal:" . ($intotal + $outtotal); # clear hours # $count = 0; while ($count <= "23") { delete $inf{$count}; $count++; } $inf{day} = $mday; } # update DBM file. # sub updatedata { my ($lasthour,$wrapin,$wrapout); my $intwrap="4294967296"; if ($hour eq "0") { $lasthour = "23"; } else { $lasthour = ($hour - "1"); } if ($hostreset == "1") { $inf{lastin} = $inf{lastout} = "0"; } # detect if a counter has wrapped and adjust. # if ($inoctets < $inf{lastin}) { $wrapin = $inoctets; $inoctets = ($intwrap - $inf{lastin}) + $inoctets; $inf{lastin} = "0"; } if ($outoctets < $inf{lastout}) { $wrapout = $outoctets; $outoctets = ($intwrap - $inf{lastout}) + $outoctets; $inf{lastout} = "0"; } $inf{$lasthour} = (($inoctets - $inf{lastin}).":".($outoctets - $inf{lastout})); if ($wrapin) { $inf{lastin} = $wrapin } else { $inf{lastin} = $inoctets } if ($wrapout) { $inf{lastout} = $wrapout } else { $inf{lastout} = $outoctets } } sub footer { print DHTML "


IOG $iogver - Input Output Grapher
-
James Dogopoulos <jd\@dynw.com>
Questions or comments to iog\@dynw.com

"; } # make the hourly html # sub hourlyhtml { my($name,$host,$path,$newday) = @_; # make todays graph # my $enddays = last_mday($mon, ($year + "1900")); my $count = "0"; my ($besthour,$bestday,$inoct,$outoct) = "0"; # find busiest hour # while ($count <= "23") { if ($inf{$count}) { ($inoct,$outoct) = split(/:/, $inf{$count}); } else { $inoct = $outoct = "0"; } if ($inoct > $besthour) { $besthour = $inoct; } if ($outoct > $besthour) { $besthour = $outoct; } $count++; } my $hscalemax = ($besthour / "1000000"); my ($hscaleunit,$intotal,$outtotal) = 0; if ($hscalemax > "0") { $hscaleunit = ("450" / $hscalemax); } open(DHTML, ">>$path".$main::SL."$name".".html") or print "can't open in $name $host $!"; flock(DHTML, 2) or print "can't flock $name $host: $!"; truncate(DHTML, 0); print DHTML "IOG $iogver - $host
"; my $dexist = (-f "$path".$main::SL."$name"."-days.html"); my $mexist = (-f "$path".$main::SL."$name"."-months.html"); if ($newday != "1") { if ($dexist && $mexist) { print DHTML " [ Today | This Month | Previous Months ]

"; } else { if ($dexist && !$mexist) { print DHTML " [ Today | This Month | Previous Months ]

"; } else { if (!$dexist && $mexist) { print DHTML " [ Today | This Month | Previous Months ]

"; } else { print DHTML "[ Today | This Month | Previous Months ]"; } } } } else { if ($dexist && $mexist) { print DHTML " [ This Month | Previous Months ]

"; } else { if ($dexist && !$mexist) { print DHTML " [ This Month | Previous Months ]

"; } else { if (!$dexist && $mexist) { print DHTML " [ This Month | Previous Months ]

"; } } } } if ($newday eq "1") { $tday = "$nday"; } else { $tday = "$pday"; } print DHTML "

$months[$mon] $tday - Network I/O for $name ($host)

"; print DHTML ""; $count = "0"; while ($count <= "23") { my($inwidth,$outwidth); if ($inf{$count}) { ($inoct,$outoct) = split(/:/, $inf{$count}); $intotal += $inoct; $outtotal += $outoct; $inwidth = ($inoct / "1000000" * $hscaleunit); $outwidth = ($outoct / "1000000" * $hscaleunit); } else { $count++; next; } # if day is over 1gb, switch to GB/MB display. # my($gstring,$gbin,$gbout,$mbin,$mbout); $mbin = sprintf("%.1f", $inoct / $mbsize); $mbout = sprintf("%.1f", $outoct / $mbsize); if ($mbin > $gbsize or $mbout > $gbsize) { $gbin = sprintf("%.1f", $mbin / $gbsize); $gbout = sprintf("%.1f", $mbout / $gbsize); $gstring = ""; } else { $gstring = "\n"; print DHTML $gstring; $count++; } $intotal = sprintf("%.f", ($intotal / $mbsize)); $outtotal = sprintf("%.f", ($outtotal / $mbsize)); print DHTML "
In: $gbin GB ($mbin MB)
Out: $gbout GB ($mbout MB)
In: $mbin MB (". sprintf("%.f", $inoct / $kbsize)." KB)
Out: $mbout MB (".sprintf("%.f", $outoct / $kbsize)." KB)"; } $inwidth = (sprintf("%.f", $inwidth) + 1); $outwidth = (sprintf("%.f", $outwidth) + 1); print DHTML "
"."$count".":00
\n"; print DHTML "

"; if ($intotal > $gbsize or $outtotal > $gbsize) { my $gbtotal = sprintf("%.1f", ($intotal + $outtotal) / $gbsize); print DHTML "Today's Total: $gbtotal GB
In: $intotal MB - Out: $outtotal MB
"; } else { print DHTML "Today's Total: ".($intotal + $outtotal)." MB
In: $intotal MB - Out: $outtotal MB
"; } footer(); flock(DHTML, 8); close(DHTML); } sub monthlyhtml { my ($name,$host,$path) = @_; my ($bestmonth,$m_intotal,$m_outtotal,$m_total); my $count = 0; # find busiest month while ($count <= "11") { if ($inf{"m" . $count}) { ($m_intotal,$m_outtotal) = split(/:/, $inf{"m" . $count}); if ($m_intotal > $bestmonth) { $bestmonth = $m_intotal; } if ($m_outtotal > $bestmonth) { $bestmonth = $m_outtotal; } } $count++; } my $mscalemax = $bestmonth; my ($mscaleunit,$intotal,$outtotal) = 0; if ($mscalemax > "0") { $mscaleunit = ("450" / $mscalemax); } open(DHTML, ">>$path".$main::SL."$name"."-months.html") or print "can't open $name $host $!"; flock(DHTML, 2) or print "can't flock $name $host : $!"; truncate(DHTML, 0); print DHTML "IOG $iogver - $host
"; my $dexist = (-f "$path".$main::SL."$name"."-days.html"); if ($dexist) { print DHTML "[ Today | This Month | Previous Months ]

"; } else { print DHTML "[ Today | This Month | Previous Months ]

"; } print DHTML "

Monthly Network I/O for $name ($host)

"; print DHTML ""; $count = "0"; while ($count <= "11") { my($inwidth,$outwidth,$intotal,$outtotal,$inoct,$outoct,$mtotal); if ($inf{"m" . $count}) { ($inoct,$outoct,$mtotal) = split(/:/, $inf{"m" . $count}); $intotal += $inoct; $outtotal += $outoct; $inwidth = ($inoct * $mscaleunit); $outwidth = ($outoct * $mscaleunit); } else { $count++; next; } # if day is over 1gb, switch to GB/MB display. # my($gstring,$gbin,$gbout,$gbtotal,$mbin,$mbout); $mbin = sprintf("%.f", $inoct); $mbout = sprintf("%.f", $outoct); $gbin = sprintf("%.1f", $mbin / $gbsize); $gbout = sprintf("%.1f", $mbout / $gbsize); $gbtotal = sprintf("%.1f", ($gbin + $gbout)); $gstring = ""; $inwidth = (sprintf("%.f", $inwidth) + 1); $outwidth = (sprintf("%.f", $outwidth) + 1); if (-f "$path".$main::SL."$name"."-month".($count + "1").".html") { $mlink = "$months[$count]"; } else { $mlink = "$months[$count]"; } print DHTML "\n"; print DHTML $gstring; $count++ } print DHTML "
In: $gbin GB ($mbin MB)
Out: $gbout GB ($mbout MB)
$mlink
$gbtotal GB

\n"; print DHTML "

"; footer(); flock(DHTML, 8); close(DHTML); } sub dailyhtml { my ($bestday,$d_intotal,$d_outtotal) = 0; my ($name,$host,$path) = @_; my $count = 1; my $endday = last_mday($inf{month}, $inf{year}); if ($endday eq $mday) { $lastday="1"; } else { $lastday="0"; } # fix math errors from previous sub if ($newmon) { $mon--; } # move Today's html file unless it's a new month. if (!$newmon) { $oldfile="$path"."$main::SL"."$name".".html"; $newfile="$path"."$main::SL"."$name"."-day".($mday - "1").".html"; if ($main::OS eq "NT") { system("move /Y $oldfile $newfile"); } else { system("mv $oldfile $newfile"); } } # find busiest day (should be merged with totals) while ($count <= $endday) { if ($inf{"d" . $count}) { ($d_intotal,$d_outtotal) = split(/:/, $inf{"d" . $count}); if ($d_intotal > $bestday) { $bestday = $d_intotal; } if ($d_outtotal > $bestday) { $bestday = $d_outtotal; } } $count++; } my $dscalemax = ($bestday / "1000000"); my ($dscaleunit,$intotal,$outtotal) = 0; if ($dscalemax > "0") { $dscaleunit = ("450" / $dscalemax); } open(DHTML, ">>$path".$main::SL."$name"."-days.html") or print "can't open $name $host $!"; flock(DHTML, 2) or print "can't flock $name $host : $!"; truncate(DHTML, 0); print DHTML "IOG $iogver - $host
"; if (-f "$path".$main::SL."$name"."-months.html") { print DHTML "[ Today | This Month | Previous Months ]

"; } else { print DHTML "[ Today | This Month | Previous Months ]

"; } print DHTML "

$months[$mon] - Network I/O for $name ($host)

"; print DHTML ""; $count = "1"; while ($count <= $endday) { my($inwidth,$outwidth,$inoct,$outoct,$pday); if ($inf{"d" . $count}) { ($inoct,$outoct) = split(/:/, $inf{"d" . $count}); $intotal += $inoct; $outtotal += $outoct; $inwidth = ($inoct / "1000000" * $dscaleunit); $outwidth = ($outoct / "1000000" * $dscaleunit); } else { $count++; next; } # if day is over 1gb, switch to GB/MB display. # my($gstring,$gbin,$gbout,$mbin,$mbout); $mbin = sprintf("%.f", $inoct / $mbsize); $mbout = sprintf("%.f", $outoct / $mbsize); if ($mbin > $gbsize or $mbout > $gbsize) { $gbin = sprintf("%.1f", $mbin / $gbsize); $gbout = sprintf("%.1f", $mbout / $gbsize); $gstring = ""; } else { $gstring = "\n"; print DHTML $gstring; $count++; } $intotal = sprintf("%.f", ($intotal / $mbsize)); $outtotal = sprintf("%.f", ($outtotal / $mbsize)); my $gbtotal = sprintf("%.1f", (($intotal + $outtotal) / $gbsize)); print DHTML "
In: $gbin GB ($mbin MB)
Out: $gbout GB ($mbout MB)
In: $mbin MB (". sprintf("%.f", $inoct / $kbsize)." KB)
Out: $mbout MB (".sprintf("%.f", $outoct / $kbsize)." KB)"; } $inwidth = (sprintf("%.f", $inwidth) + 1); $outwidth = (sprintf("%.f", $outwidth) + 1); if ($days{$count}) { $pday = $days{$count}; } else { $pday = $count."th"; } if (-f "$path".$main::SL."$name"."-day".$count.".html" && $lastday eq "0" && ($newmon ne "1")) { $pday = "$pday"; } print DHTML "
$pday
\n"; print DHTML "

"; print DHTML "Monthly Total: $gbtotal GB
In: $intotal MB - Out: $outtotal MB
"; footer(); flock(DHTML, 8); close(DHTML); # reverse math errors if ($newmon) { $mon++; } } # END # # IOG v1.03 - Input/Output Grapher # Copyright 2000-2003 (c) James Dogopoulos # ./iog-1.03/in.gif100644 0 0 51 7743014353 11607 0ustar rootwheelGIF89a,S;./iog-1.03/howto-iog.html100644 0 0 47132 7743014353 13407 0ustar rootwheel

IOG HowTo

Author:  Sean Kelly <sean@inabiaf.com>
Contributor:
  sme-iog-howto
Release supported: SME 5.x
License: GPL
Last updated: Wednesday, April 16, 2003 5:57 PM




Problem:  You want to install IOG on SME 5.x to monitor the bandwidth consumed by your SME server.
Solution:
  Follow this HowTo




STEP 1: Download IOG

Go to http://www.dynw.com/iog and download iog-1.01.tgz . Copy it up to your SME server by whatever means you are comfortable.




STEP 2: Download and install net-snmp and net-snmp-utils

SME does not come with SNMPd installed out of the box. You will need snmp-tools as well, especially if you want to get the metrics from other SME servers (and do other things, more on that later).

For SME 5.x, grab the appropriate version of ucd-snmp and ucd-snmp-utils from Sassous Efoe Boris's howto on installing Cacti on SME (http://www.speedfactor.ath.cx/howto/) and follow that portion of his howto to install them (as plagiarised below ;-)


Fetch them:

For E-SMITH/SME 5.x
shell>
wget ftp://speedfactor.ath.cx/cacti/RPMS/ucd-snmp-4.2.3-1.7.0.4.i386.rpm
shell> wget ftp://speedfactor.ath.cx/cacti/RPMS/ucd-snmp-utils-4.2.3-1.7.0.4.i386.rpm

Only For SME 5.6
shell>
wget ftp://speedfactor.ath.cx/cacti/RPMS/ucd-snmp-4.2.1-7.i386.rpm
shell> wget ftp://speedfactor.ath.cx/cacti/RPMS/ucd-snmp-utils-4.2.1-7.i386.rpm

Or if the first site is unavalaible try this:
shell> wget ftp://ftp.e-smith.org/pub/e-smith/contrib/SassouEfoeBoris/RPMS/i386/ucd-snmp-4.2.3-1.7.0.4.i386.rpm
shell> wget ftp://ftp.e-smith.org/pub/e-smith/contrib/SassouEfoeBoris/RPMS/i386/ucd-snmp-utils-4.2.3-1.7.0.4.i386.rpm



Now install them:

For E-SMITH/SME 5.X
shell>
rpm -ivh --nodeps ucd-snmp-4.2.3-1.7.0.4.i386.rpm
shell> rpm -ivh --nodeps ucd-snmp-utils-4.2.3-1.7.0.4.i386.rpm

Only for SME 5.6
shell>
rpm -ivh --nodeps --force ucd-snmp-4.2.1-7.i386.rpm
shell> rpm -ivh --nodeps --force ucd-snmp-utils-4.2.1-7.i386.rpm

Configure Ucd-snmp for e-smith

shell> mv /etc/snmp/snmpd.conf /etc/snmp/snmpd.conf.old
shell> echo > /etc/snmp/snmpd.conf
shell> ln -s /lib/libcrypto.so.0.9.6b /lib/libcrypto.so.1
shell> service snmpd restart
shell> ln -s /etc/init.d/snmpd /etc/rc7.d/S92snmpd
shell> ln -s /etc/init.d/snmpd /etc/rc0.d/K92snmpd
shell> ln -s /etc/init.d/snmpd /etc/rc6.d/K92snmpd


WARNING:
The "mv /etc/snmp/snmpd.conf /etc/snmp/snmpd.conf.old" command is to force net-snmp to start in such a way that it only listens to requests from 127.0.0.1, or localhost. SNMP has known security holes, so it is important that this command is run - your machine may be left vulnerable if you don't do this.


STEP 3: Untar IOG to a safe place

shell> mkdir /opt/iog
shell> cp ./iog-1.01.tgz /opt/iog
shell> cd /opt/iog
shell> tar -xvzf iog-1.01.tgz
shell> cp iog-1.01/* .




STEP 4:  Create an ibay for IOG to live in

Create an ibay (called "iog" or whatever) for the web page and the iog data to live in. No special CGI or other permissions are required for this ibay.

Copy the .gif files from your /opt/iog directory into your ibay/html directory (nominally /home/e-smith/files/ibays/iog/html).


shell> cp ./iog-1.01/*.gif /home/e-smith/files/ibays/iog/html





STEP 5: Edit iog.cfg to reflect your system

First off, let's look at the guts of iog.cfg:

# ex.:
# [switch1:192.168.0.10:public:sysUpTime.0:/www/snmp]
# sw1-port1:192.168.0.10:public:ifInOctets.1:ifOutOctets.1:/www/snmp/
# sw1-port2:192.168.0.10:public:ifInOctets.2:ifOutOctets.2:/www/snmp/
#
# [switch2:192.168.0.11:public:sysUpTime:/www/snmp]
# sw2-port20:192.168.0.11:public:ifHCInOctets.20:ifHCOutOctets.20:/www/snmp/
#


If for example we wanted to monitor the internal and external ports of our gateway we would make an entry like:

my_gateway_name:127.0.0.1:public:sysUpTime.0:/home/e-smith/files/ibays/iog/html]
Gateway-external-ethernet:127.0.0.1:public:ifInOctets.1:ifOutOctets.1:/home/e-smith/files/ibays/iog/html
Gateway-internal-ethernet:127.0.0.1:public:ifInOctets.2:ifOutOctets.2:/home/e-smith/files/ibays/iog/html


Here is where the snmp-utils comes in. The ifInOctets.1 part in the above entries is the OID (Object Identifier) in the MIB (Management Information Base) for the counter (in octets or bytes) of the first interface reported by your machine's SNMPd. The only way to be sure of what the actual interface index is is to use SNMPWALK to walk the OIDs on your machine and view the results.

For example:

shell> snmpwalk 127.0.0.1 public | grep ifDescr
interfaces.ifTable.ifEntry.ifDescr.1 = lo
interfaces.ifTable.ifEntry.ifDescr.2 = eth0
interfaces.ifTable.ifEntry.ifDescr.3 = eth1
host.hrSWRun.hrSWRunTable.hrSWRunEntry.hrSWRunParameters.6658 = "ifDescr"


I know (or I should know;-) which interface is inside (eth0,) and which interface is outside (eth1). As the ifDescr values correspond to ifInOctets and ifOutOctets values, I would change the lines in iog.cfg to read:

[my_gateway_name:127.0.0.1:public:sysUpTime.0:/home/e-smith/files/ibays/iog/html]
Gateway-external-ethernet:127.0.0.1:public:ifInOctets.3:ifOutOctets.3:/home/e-smith/files/ibays/iog/html
Gateway-internal-ethernet:127.0.0.1:public:ifInOctets.2:ifOutOctets.2:/home/e-smith/files/ibays/iog/html


... as ifInOctets.3 corresponds to ifDescr.3, which is the interface number for eth1, which is my server's external interface.

If your entry is index:127.0.0.1:public:ifInOctets.3:ifOutOctets.3:/home/e-smith/files/ibays/iog/html then this will create index.html, replacing the default "Under Construction" page in the ibay. This is useful if you only want to monitor one interface, like your server's external ethernet.


Now, while you have the chance, you can remove snmp-utils as the snmp_session.PM file in iog looks after that stuff for you. To do this, run...


shell> rpm -e ucd-snmp-utils





 STEP 6:  Create the crontab entries to run IOG

You now need to run iog every hour. Assuming you put the iog files in /opt/iog, do this:

shell> mkdir -p /etc/e-smith/templates-custom/etc/crontab/
shell> echo "0 * * * * root /opt/iog/iog" > /etc/e-smith/templates-custom/etc/crontab/iog
shell> /sbin/e-smith/expand-template /etc/crontab



Do not run iog every five minutes (as per mrtg and cacti etc) as this will give you very weird statistics for your traffic!



STEP 7: Wait for a few hours...

You should, after a few hours, be able to go to http://mysmeserver/iog/Gateway-external-ethernet.html and http://mysmeserver/iog/Gateway-internal-ethernet.html to see the results. There should be nice graphs there, with drill-down levels as time goes on.

Each interface line you created in your iog.cfg will create an html page with the title being the part before the first colon, eg Gateway-internal-ethernet.html, Gateway-external-ethernet.html, etc. If you are monitoring a whole bunch of interfaces you may want to modify the default index.html to point to these individual files.





Other possibilities:

Given that IOG uses SNMP to gather the statistics, it should be possible to gather stats from any snmp-enabled device as long as you know what the appropriate ifDescr indices are. You could use it to track the i/o on any server in your network if you wished, or on the kid's PC in their room (if you enabled snmp on it).



 

./iog-1.03/SNMP_Session.pm100444 0 0 71623 7743014353 13423 0ustar rootwheel# -*- mode: Perl -*- ###################################################################### ### SNMP Request/Response Handling ###################################################################### ### Copyright (c) 1995-2002, Simon Leinen. ### ### This program is free software; you can redistribute it under the ### "Artistic License" included in this distribution (file "Artistic"). ###################################################################### ### The abstract class SNMP_Session defines objects that can be used ### to communicate with SNMP entities. It has methods to send ### requests to and receive responses from an agent. ### ### Two instantiable subclasses are defined: ### SNMPv1_Session implements SNMPv1 (RFC 1157) functionality ### SNMPv2c_Session implements community-based SNMPv2. ###################################################################### ### Created by: Simon Leinen ### ### Contributions and fixes by: ### ### Matthew Trunnell ### Tobias Oetiker ### Heine Peters ### Daniel L. Needles ### Mike Mitchell ### Clinton Wong ### Alan Nichols ### Mike McCauley ### Andrew W. Elble ### Brett T Warden : pretty UInteger32 ### Michael Deegan ### Sergio Macedo ### Jakob Ilves (/IlvJa) : PDU capture ###################################################################### package SNMP_Session; require 5.002; use strict; use Exporter; use vars qw(@ISA $VERSION @EXPORT $errmsg $suppress_warnings); use Socket; use BER; use Carp; sub map_table ($$$ ); sub map_table_4 ($$$$); sub map_table_start_end ($$$$$$); sub index_compare ($$); sub oid_diff ($$); $VERSION = '0.95'; @ISA = qw(Exporter); @EXPORT = qw(errmsg suppress_warnings index_compare oid_diff recycle_socket); my $default_debug = 0; ### Default initial timeout (in seconds) waiting for a response PDU ### after a request is sent. Note that when a request is retried, the ### timeout is increased by BACKOFF (see below). ### my $default_timeout = 2.0; ### Default number of attempts to get a reply for an SNMP request. If ### no response is received after TIMEOUT seconds, the request is ### resent and a new response awaited with a longer timeout (see the ### documentation on BACKOFF below). The "retries" value should be at ### least 1, because the first attempt counts, too (the name "retries" ### is confusing, sorry for that). ### my $default_retries = 5; ### Default backoff factor for SNMP_Session objects. This factor is ### used to increase the TIMEOUT every time an SNMP request is ### retried. ### my $default_backoff = 1.0; ### Default value for maxRepetitions. This specifies how many table ### rows are requested in getBulk requests. Used when walking tables ### using getBulk (only available in SNMPv2(c) and later). If this is ### too small, then a table walk will need unnecessarily many ### request/response exchanges. If it is too big, the agent may ### compute many variables after the end of the table. It is ### recommended to set this explicitly for each table walk by using ### map_table_4(). ### my $default_max_repetitions = 12; ### Default value for "avoid_negative_request_ids". ### ### Set this to non-zero if you have agents that have trouble with ### negative request IDs, and don't forget to complain to your agent ### vendor. According to the spec (RFC 1905), the request-id is an ### Integer32, i.e. its range is from -(2^31) to (2^31)-1. However, ### some agents erroneously encode the response ID as an unsigned, ### which prevents this code from matching such responses to requests. ### my $default_avoid_negative_request_ids = 0; ### Whether all SNMP_Session objects should share a single UDP socket. ### $SNMP_Session::recycle_socket = 0; my $the_socket; $SNMP_Session::errmsg = ''; $SNMP_Session::suppress_warnings = 0; sub get_request { 0 | context_flag }; sub getnext_request { 1 | context_flag }; sub get_response { 2 | context_flag }; sub set_request { 3 | context_flag }; sub trap_request { 4 | context_flag }; sub getbulk_request { 5 | context_flag }; sub inform_request { 6 | context_flag }; sub trap2_request { 7 | context_flag }; sub standard_udp_port { 161 }; sub open { return SNMPv1_Session::open (@_); } sub timeout { $_[0]->{timeout} } sub retries { $_[0]->{retries} } sub backoff { $_[0]->{backoff} } sub set_timeout { my ($session, $timeout) = @_; croak ("timeout ($timeout) must be a positive number") unless $timeout > 0.0; $session->{'timeout'} = $timeout; } sub set_retries { my ($session, $retries) = @_; croak ("retries ($retries) must be a non-negative integer") unless $retries == int ($retries) && $retries >= 0; $session->{'retries'} = $retries; } sub set_backoff { my ($session, $backoff) = @_; croak ("backoff ($backoff) must be a number >= 1.0") unless $backoff == int ($backoff) && $backoff >= 1.0; $session->{'backoff'} = $backoff; } sub encode_request_3 ($$$@) { my($this, $reqtype, $encoded_oids_or_pairs, $i1, $i2) = @_; my($request); local($_); $this->{request_id} = ($this->{request_id} == 0x7fffffff) ? ($this->{avoid_negative_request_ids} ? 0x00000000 : -0x80000000) : $this->{request_id}+1; foreach $_ (@{$encoded_oids_or_pairs}) { if (ref ($_) eq 'ARRAY') { $_ = &encode_sequence ($_->[0], $_->[1]) || return $this->ber_error ("encoding pair"); } else { $_ = &encode_sequence ($_, encode_null()) || return $this->ber_error ("encoding value/null pair"); } } $request = encode_tagged_sequence ($reqtype, encode_int ($this->{request_id}), defined $i1 ? encode_int ($i1) : encode_int_0, defined $i2 ? encode_int ($i2) : encode_int_0, encode_sequence (@{$encoded_oids_or_pairs})) || return $this->ber_error ("encoding request PDU"); return $this->wrap_request ($request); } sub encode_get_request { my($this, @oids) = @_; return encode_request_3 ($this, get_request, \@oids); } sub encode_getnext_request { my($this, @oids) = @_; return encode_request_3 ($this, getnext_request, \@oids); } sub encode_getbulk_request { my($this, $non_repeaters, $max_repetitions, @oids) = @_; return encode_request_3 ($this, getbulk_request, \@oids, $non_repeaters, $max_repetitions); } sub encode_set_request { my($this, @encoded_pairs) = @_; return encode_request_3 ($this, set_request, \@encoded_pairs); } sub encode_trap_request ($$$$$$@) { my($this, $ent, $agent, $gen, $spec, $dt, @pairs) = @_; my($request); local($_); foreach $_ (@pairs) { if (ref ($_) eq 'ARRAY') { $_ = &encode_sequence ($_->[0], $_->[1]) || return $this->ber_error ("encoding pair"); } else { $_ = &encode_sequence ($_, encode_null()) || return $this->ber_error ("encoding value/null pair"); } } $request = encode_tagged_sequence (trap_request, $ent, $agent, $gen, $spec, $dt, encode_sequence (@pairs)) || return $this->ber_error ("encoding trap PDU"); return $this->wrap_request ($request); } sub encode_v2_trap_request ($@) { my($this, @pairs) = @_; return encode_request_3($this, trap2_request, \@pairs); } sub decode_get_response { my($this, $response) = @_; my @rest; @{$this->{'unwrapped'}}; } sub decode_trap_request ($$) { my ($this, $trap) = @_; my ($snmp_version, $community, $ent, $agent, $gen, $spec, $dt, $request_id, $error_status, $error_index, $bindings); ($snmp_version, $community, $ent, $agent, $gen, $spec, $dt, $bindings) = decode_by_template ($trap, "%{%i%s%*{%O%A%i%i%u%{%@", trap_request); if (! defined ($snmp_version)) { ($snmp_version, $community, $request_id, $error_status, $error_index, $bindings) = decode_by_template ($trap, "%{%i%s%*{%i%i%i%{%@", trap2_request); return $this->error_return ("v2 trap request contained errorStatus/errorIndex " .$error_status."/".$error_index) if defined $error_status && defined $error_index && ($error_status != 0 || $error_index != 0); } if (!defined $snmp_version) { return $this->error_return ("BER error decoding trap:\n ".$BER::errmsg); } return ($community, $ent, $agent, $gen, $spec, $dt, $bindings); } sub wait_for_response { my($this) = shift; my($timeout) = shift || 10.0; my($rin,$win,$ein) = ('','',''); my($rout,$wout,$eout); vec($rin,$this->sockfileno,1) = 1; select($rout=$rin,$wout=$win,$eout=$ein,$timeout); } sub get_request_response ($@) { my($this, @oids) = @_; return $this->request_response_5 ($this->encode_get_request (@oids), get_response, \@oids, 1); } sub set_request_response ($@) { my($this, @pairs) = @_; return $this->request_response_5 ($this->encode_set_request (@pairs), get_response, \@pairs, 1); } sub getnext_request_response ($@) { my($this,@oids) = @_; return $this->request_response_5 ($this->encode_getnext_request (@oids), get_response, \@oids, 1); } sub getbulk_request_response ($$$@) { my($this,$non_repeaters,$max_repetitions,@oids) = @_; return $this->request_response_5 ($this->encode_getbulk_request ($non_repeaters,$max_repetitions,@oids), get_response, \@oids, 1); } sub trap_request_send ($$$$$$@) { my($this, $ent, $agent, $gen, $spec, $dt, @pairs) = @_; my($req); $req = $this->encode_trap_request ($ent, $agent, $gen, $spec, $dt, @pairs); ## Encoding may have returned an error. return undef unless defined $req; $this->send_query($req) || return $this->error ("send_trap: $!"); return 1; } sub v2_trap_request_send ($$$@) { my($this, $trap_oid, $dt, @pairs) = @_; my @sysUptime_OID = ( 1,3,6,1,2,1,1,3 ); my @snmpTrapOID_OID = ( 1,3,6,1,6,3,1,1,4,1 ); my($req); unshift @pairs, [encode_oid (@snmpTrapOID_OID,0), encode_oid (@{$trap_oid})]; unshift @pairs, [encode_oid (@sysUptime_OID,0), encode_timeticks ($dt)]; $req = $this->encode_v2_trap_request (@pairs); ## Encoding may have returned an error. return undef unless defined $req; $this->send_query($req) || return $this->error ("send_trap: $!"); return 1; } sub request_response_5 ($$$$$) { my ($this, $req, $response_tag, $oids, $errorp) = @_; my $retries = $this->retries; my $timeout = $this->timeout; my ($nfound, $timeleft); ## Encoding may have returned an error. return undef unless defined $req; $timeleft = $timeout; while ($retries > 0) { $this->send_query ($req) || return $this->error ("send_query: $!"); # IlvJa # Add request pdu to capture_buffer push @{$this->{'capture_buffer'}}, $req if (defined $this->{'capture_buffer'} and ref $this->{'capture_buffer'} eq 'ARRAY'); # wait_for_response: ($nfound, $timeleft) = $this->wait_for_response($timeleft); if ($nfound > 0) { my($response_length); $response_length = $this->receive_response_3 ($response_tag, $oids, $errorp); if ($response_length) { # IlvJa # Add response pdu to capture_buffer push (@{$this->{'capture_buffer'}}, substr($this->{'pdu_buffer'}, 0, $response_length) ) if (defined $this->{'capture_buffer'} and ref $this->{'capture_buffer'} eq 'ARRAY'); # return $response_length; } elsif (defined ($response_length)) { goto wait_for_response; # A response has been received, but for a different # request ID or from a different IP address. } else { return undef; } } else { ## No response received - retry --$retries; $timeout *= $this->backoff; $timeleft = $timeout; } } # IlvJa # Add empty packet to capture_buffer push @{$this->{'capture_buffer'}}, "" if (defined $this->{'capture_buffer'} and ref $this->{'capture_buffer'} eq 'ARRAY'); # $this->error ("no response received"); } sub map_table ($$$) { my ($session, $columns, $mapfn) = @_; return $session->map_table_4 ($columns, $mapfn, $session->default_max_repetitions ()); } sub map_table_4 ($$$$) { my ($session, $columns, $mapfn, $max_repetitions) = @_; return $session->map_table_start_end ($columns, $mapfn, "", undef, $max_repetitions); } sub map_table_start_end ($$$$$$) { my ($session, $columns, $mapfn, $start, $end, $max_repetitions) = @_; my @encoded_oids; my $call_counter = 0; my $base_index = $start; do { foreach (@encoded_oids = @{$columns}) { $_=encode_oid (@{$_},split '\.',$base_index) || return $session->ber_error ("encoding OID $base_index"); } if ($session->getnext_request_response (@encoded_oids)) { my $response = $session->pdu_buffer; my ($bindings) = $session->decode_get_response ($response); my $smallest_index = undef; my @collected_values = (); my @bases = @{$columns}; while ($bindings ne '') { my ($binding, $oid, $value); my $base = shift @bases; ($binding, $bindings) = decode_sequence ($bindings); ($oid, $value) = decode_by_template ($binding, "%O%@"); my $out_index; $out_index = &oid_diff ($base, $oid); my $cmp; if (!defined $smallest_index || ($cmp = index_compare ($out_index,$smallest_index)) == -1) { $smallest_index = $out_index; grep ($_=undef, @collected_values); push @collected_values, $value; } elsif ($cmp == 1) { push @collected_values, undef; } else { push @collected_values, $value; } } (++$call_counter, &$mapfn ($smallest_index, @collected_values)) if defined $smallest_index; $base_index = $smallest_index; } else { return undef; } } while (defined $base_index && (!defined $end || index_compare ($base_index, $end) < 0)); $call_counter; } sub index_compare ($$) { my ($i1, $i2) = @_; $i1 = '' unless defined $i1; $i2 = '' unless defined $i2; if ($i1 eq '') { return $i2 eq '' ? 0 : 1; } elsif ($i2 eq '') { return 1; } elsif (!$i1) { return $i2 eq '' ? 1 : !$i2 ? 0 : 1; } elsif (!$i2) { return -1; } else { my ($f1,$r1) = split('\.',$i1,2); my ($f2,$r2) = split('\.',$i2,2); if ($f1 < $f2) { return -1; } elsif ($f1 > $f2) { return 1; } else { return index_compare ($r1,$r2); } } } sub oid_diff ($$) { my($base, $full) = @_; my $base_dotnot = join ('.',@{$base}); my $full_dotnot = BER::pretty_oid ($full); return undef unless substr ($full_dotnot, 0, length $base_dotnot) eq $base_dotnot && substr ($full_dotnot, length $base_dotnot, 1) eq '.'; substr ($full_dotnot, length ($base_dotnot)+1); } sub pretty_address { my($addr) = shift; my($port,$ipaddr) = unpack_sockaddr_in($addr); return sprintf ("[%s].%d",inet_ntoa($ipaddr),$port); } sub version { $VERSION; } sub error_return ($$) { my ($this,$message) = @_; $SNMP_Session::errmsg = $message; unless ($SNMP_Session::suppress_warnings) { $message =~ s/^/ /mg; carp ("Error:\n".$message."\n"); } return undef; } sub error ($$) { my ($this,$message) = @_; my $session = $this->to_string; $SNMP_Session::errmsg = $message."\n".$session; unless ($SNMP_Session::suppress_warnings) { $session =~ s/^/ /mg; $message =~ s/^/ /mg; carp ("SNMP Error:\n".$SNMP_Session::errmsg."\n"); } return undef; } sub ber_error ($$) { my ($this,$type) = @_; my ($errmsg) = $BER::errmsg; $errmsg =~ s/^/ /mg; return $this->error ("$type:\n$errmsg"); } package SNMPv1_Session; use strict qw(vars subs); # see above use vars qw(@ISA); use SNMP_Session; use Socket; use BER; use IO::Socket; use Carp; @ISA = qw(SNMP_Session); sub snmp_version { 0 } sub open { my($this, $remote_hostname,$community,$port, $max_pdu_len,$local_port,$max_repetitions, $local_hostname) = @_; my($remote_addr,$socket); $community = 'public' unless defined $community; $port = SNMP_Session::standard_udp_port unless defined $port; $max_pdu_len = 8000 unless defined $max_pdu_len; $max_repetitions = $default_max_repetitions unless defined $max_repetitions; if (defined $remote_hostname) { $remote_addr = inet_aton ($remote_hostname) or return $this->error_return ("can't resolve \"$remote_hostname\" to IP address"); } if ($SNMP_Session::recycle_socket && defined $the_socket) { $socket = $the_socket; } else { $socket = IO::Socket::INET->new(Proto => 17, Type => SOCK_DGRAM, LocalAddr => $local_hostname, LocalPort => $local_port) || return $this->error_return ("creating socket: $!"); $the_socket = $socket if $SNMP_Session::recycle_socket; } $remote_addr = pack_sockaddr_in ($port, $remote_addr) if defined $remote_addr; bless { 'sock' => $socket, 'sockfileno' => fileno ($socket), 'community' => $community, 'remote_hostname' => $remote_hostname, 'remote_addr' => $remote_addr, 'max_pdu_len' => $max_pdu_len, 'pdu_buffer' => '\0' x $max_pdu_len, 'request_id' => $default_avoid_negative_request_ids ? (int (rand 0x8000) << 16) + int (rand 0x10000) : (int (rand 0x10000) << 16) + int (rand 0x10000) - 0x80000000, 'timeout' => $default_timeout, 'retries' => $default_retries, 'backoff' => $default_backoff, 'debug' => $default_debug, 'error_status' => 0, 'error_index' => 0, 'default_max_repetitions' => $max_repetitions, 'use_getbulk' => 1, 'lenient_source_address_matching' => 1, 'lenient_source_port_matching' => 1, 'avoid_negative_request_ids' => $default_avoid_negative_request_ids, 'capture_buffer' => undef, }; } sub open_trap_session (@) { my ($this, $port) = @_; $port = 162 unless defined $port; return $this->open (undef, "", 161, undef, $port); } sub sock { $_[0]->{sock} } sub sockfileno { $_[0]->{sockfileno} } sub remote_addr { $_[0]->{remote_addr} } sub pdu_buffer { $_[0]->{pdu_buffer} } sub max_pdu_len { $_[0]->{max_pdu_len} } sub default_max_repetitions { defined $_[1] ? $_[0]->{default_max_repetitions} = $_[1] : $_[0]->{default_max_repetitions} } sub debug { defined $_[1] ? $_[0]->{debug} = $_[1] : $_[0]->{debug} } sub close { my($this) = shift; ## Avoid closing the socket if it may be shared with other session ## objects. if (! defined $the_socket || $this->sock ne $the_socket) { close ($this->sock) || $this->error ("close: $!"); } } sub wrap_request { my($this) = shift; my($request) = shift; encode_sequence (encode_int ($this->snmp_version), encode_string ($this->{community}), $request) || return $this->ber_error ("wrapping up request PDU"); } my @error_status_code = qw(noError tooBig noSuchName badValue readOnly genErr noAccess wrongType wrongLength wrongEncoding wrongValue noCreation inconsistentValue resourceUnavailable commitFailed undoFailed authorizationError notWritable inconsistentName); sub unwrap_response_5b { my ($this,$response,$tag,$oids,$errorp) = @_; my ($community,$request_id,@rest,$snmpver); ($snmpver,$community,$request_id, $this->{error_status}, $this->{error_index}, @rest) = decode_by_template ($response, "%{%i%s%*{%i%i%i%{%@", $tag); return $this->ber_error ("Error decoding response PDU") unless defined $snmpver; return $this->error ("Received SNMP response with unknown snmp-version field $snmpver") unless $snmpver == $this->snmp_version; if ($this->{error_status} != 0) { if ($errorp) { my ($oid, $errmsg); $errmsg = $error_status_code[$this->{error_status}] || $this->{error_status}; $oid = $oids->[$this->{error_index}-1] if $this->{error_index} > 0 && $this->{error_index}-1 <= $#{$oids}; $oid = $oid->[0] if ref($oid) eq 'ARRAY'; return ($community, $request_id, $this->error ("Received SNMP response with error code\n" ." error status: $errmsg\n" ." index ".$this->{error_index} .(defined $oid ? " (OID: ".&BER::pretty_oid($oid).")" : ""))); } else { if ($this->{error_index} == 1) { @rest[$this->{error_index}-1..$this->{error_index}] = (); } } } ($community, $request_id, @rest); } sub send_query ($$) { my ($this,$query) = @_; send ($this->sock,$query,0,$this->remote_addr); } ## Compare two sockaddr_in structures for equality. This is used when ## matching incoming responses with outstanding requests. Previous ## versions of the code simply did a bytewise comparison ("eq") of the ## two sockaddr_in structures, but this didn't work on some systems ## where sockaddr_in contains other elements than just the IP address ## and port number, notably FreeBSD. ## ## We allow for varying degrees of leniency when checking the source ## address. By default we now ignore it altogether, because there are ## agents that don't respond from UDP port 161, and there are agents ## that don't respond from the IP address the query had been sent to. ## sub sa_equal_p ($$$) { my ($this, $sa1, $sa2) = @_; my ($p1, $a1) = sockaddr_in ($sa1); my ($p2, $a2) = sockaddr_in ($sa2); if (! $this->{'lenient_source_address_matching'}) { return 0 if $a1 ne $a2; } if (! $this->{'lenient_source_port_matching'}) { return 0 if $p1 != $p2; } return 1; } sub receive_response_3 { my ($this, $response_tag, $oids, $errorp) = @_; my ($remote_addr); $remote_addr = recv ($this->sock,$this->{'pdu_buffer'},$this->max_pdu_len,0); return $this->error ("receiving response PDU: $!") unless defined $remote_addr; return $this->error ("short (".length $this->{'pdu_buffer'} ." bytes) response PDU") unless length $this->{'pdu_buffer'} > 2; my $response = $this->{'pdu_buffer'}; ## ## Check whether the response came from the address we've sent the ## request to. If this is not the case, we should probably ignore ## it, as it may relate to another request. ## if (defined $this->{'remote_addr'}) { if (! $this->sa_equal_p ($remote_addr, $this->{'remote_addr'})) { if ($this->{'debug'} && !$SNMP_Session::recycle_socket) { carp ("Response came from ".&SNMP_Session::pretty_address($remote_addr) .", not ".&SNMP_Session::pretty_address($this->{'remote_addr'})) unless $SNMP_Session::suppress_warnings; } return 0; } } $this->{'last_sender_addr'} = $remote_addr; my ($response_community, $response_id, @unwrapped) = $this->unwrap_response_5b ($response, $response_tag, $oids, $errorp); if ($response_community ne $this->{community} || $response_id ne $this->{request_id}) { if ($this->{'debug'}) { carp ("$response_community != $this->{community}") unless $SNMP_Session::suppress_warnings || $response_community eq $this->{community}; carp ("$response_id != $this->{request_id}") unless $SNMP_Session::suppress_warnings || $response_id == $this->{request_id}; } return 0; } if (!defined $unwrapped[0]) { $this->{'unwrapped'} = undef; return undef; } $this->{'unwrapped'} = \@unwrapped; return length $this->pdu_buffer; } sub receive_trap { my ($this) = @_; my ($remote_addr, $iaddr, $port, $trap); $remote_addr = recv ($this->sock,$this->{'pdu_buffer'},$this->max_pdu_len,0); return undef unless $remote_addr; ($port, $iaddr) = sockaddr_in($remote_addr); $trap = $this->{'pdu_buffer'}; return ($trap, $iaddr, $port); } sub describe { my($this) = shift; print $this->to_string (),"\n"; } sub to_string { my($this) = shift; my ($class,$prefix); $class = ref($this); $prefix = ' ' x (length ($class) + 2); ($class .(defined $this->{remote_hostname} ? " (remote host: \"".$this->{remote_hostname}."\"" ." ".&SNMP_Session::pretty_address ($this->remote_addr).")" : " (no remote host specified)") ."\n" .$prefix." community: \"".$this->{'community'}."\"\n" .$prefix." request ID: ".$this->{'request_id'}."\n" .$prefix."PDU bufsize: ".$this->{'max_pdu_len'}." bytes\n" .$prefix." timeout: ".$this->{timeout}."s\n" .$prefix." retries: ".$this->{retries}."\n" .$prefix." backoff: ".$this->{backoff}.")"); ## sprintf ("SNMP_Session: %s (size %d timeout %g)", ## &SNMP_Session::pretty_address ($this->remote_addr),$this->max_pdu_len, ## $this->timeout); } ### SNMP Agent support ### contributed by Mike McCauley ### sub receive_request { my ($this) = @_; my ($remote_addr, $iaddr, $port, $request); $remote_addr = recv($this->sock, $this->{'pdu_buffer'}, $this->{'max_pdu_len'}, 0); return undef unless $remote_addr; ($port, $iaddr) = sockaddr_in($remote_addr); $request = $this->{'pdu_buffer'}; return ($request, $iaddr, $port); } sub decode_request { my ($this, $request) = @_; my ($snmp_version, $community, $requestid, $errorstatus, $errorindex, $bindings); ($snmp_version, $community, $requestid, $errorstatus, $errorindex, $bindings) = decode_by_template ($request, "%{%i%s%*{%i%i%i%@", SNMP_Session::get_request); if (defined $snmp_version) { # Its a valid get_request return(SNMP_Session::get_request, $requestid, $bindings, $community); } ($snmp_version, $community, $requestid, $errorstatus, $errorindex, $bindings) = decode_by_template ($request, "%{%i%s%*{%i%i%i%@", SNMP_Session::getnext_request); if (defined $snmp_version) { # Its a valid getnext_request return(SNMP_Session::getnext_request, $requestid, $bindings, $community); } ($snmp_version, $community, $requestid, $errorstatus, $errorindex, $bindings) = decode_by_template ($request, "%{%i%s%*{%i%i%i%@", SNMP_Session::set_request); if (defined $snmp_version) { # Its a valid set_request return(SNMP_Session::set_request, $requestid, $bindings, $community); } # Something wrong with this packet # Decode failed return undef; } package SNMPv2c_Session; use strict qw(vars subs); # see above use vars qw(@ISA); use SNMP_Session; use BER; use Carp; @ISA = qw(SNMPv1_Session); sub snmp_version { 1 } sub open { my $session = SNMPv1_Session::open (@_); return bless $session; } ## map_table_start_end using get-bulk ## sub map_table_start_end ($$$$$$) { my ($session, $columns, $mapfn, $start, $end, $max_repetitions) = @_; my @encoded_oids; my $call_counter = 0; my $base_index = $start; my $ncols = @{$columns}; my @collected_values = (); if (! $session->{'use_getbulk'}) { return SNMP_Session::map_table_start_end ($session, $columns, $mapfn, $start, $end, $max_repetitions); } $max_repetitions = $session->default_max_repetitions unless defined $max_repetitions; for (;;) { foreach (@encoded_oids = @{$columns}) { $_=encode_oid (@{$_},split '\.',$base_index) || return $session->ber_error ("encoding OID $base_index"); } if ($session->getbulk_request_response (0, $max_repetitions, @encoded_oids)) { my $response = $session->pdu_buffer; my ($bindings) = $session->decode_get_response ($response); my @colstack = (); my $k = 0; my $j; my $min_index = undef; my @bases = @{$columns}; my $n_bindings = 0; my $binding; ## Copy all bindings into the colstack. ## The colstack is a vector of vectors. ## It contains one vector for each "repeater" variable. ## while ($bindings ne '') { ($binding, $bindings) = decode_sequence ($bindings); my ($oid, $value) = decode_by_template ($binding, "%O%@"); push @{$colstack[$k]}, [$oid, $value]; ++$k; $k = 0 if $k >= $ncols; } ## Now collect rows from the column stack: ## ## Iterate through the column stacks to find the smallest ## index, collecting the values for that index in ## @collected_values. ## ## As long as a row can be assembled, the map function is ## called on it and the iteration proceeds. ## $base_index = undef; walk_rows_from_pdu: for (;;) { my $min_index = undef; for ($k = 0; $k < $ncols; ++$k) { $collected_values[$k] = undef; my $pair = $colstack[$k]->[0]; unless (defined $pair) { $min_index = undef; last walk_rows_from_pdu; } my $this_index = SNMP_Session::oid_diff ($columns->[$k], $pair->[0]); if (defined $this_index) { my $cmp = !defined $min_index ? -1 : SNMP_Session::index_compare ($this_index, $min_index); if ($cmp == -1) { for ($j = 0; $j < $k; ++$j) { unshift (@{$colstack[$j]}, [$min_index, $collected_values[$j]]); $collected_values[$j] = undef; } $min_index = $this_index; } if ($cmp <= 0) { $collected_values[$k] = $pair->[1]; shift @{$colstack[$k]}; } } } ($base_index = undef), last if !defined $min_index; last if defined $end && index_compare ($min_index, $end) >= 0; &$mapfn ($min_index, @collected_values); ++$call_counter; $base_index = $min_index; } } else { return undef; } last if !defined $base_index; last if defined $end and index_compare ($base_index, $end) >= 0; } $call_counter; } 1; ./iog-1.03/README100644 0 0 12650 7743562117 11470 0ustar rootwheel// IOG v1.03 - Input/Output Grapher - README // // Official Homepage: http://www.dynw.com/iog/ // Comments, bug reports to: iog@dynw.com // // Copyright (c) 2000-2003 James Dogopoulos // // Contributors: // Simon Leinen - SNMPlib // Files: Artistic - Artistic License *READ* *.gif - IOG image files. iog - IOG execution file. iog.cfg - IOG Configuration file. README - THIS FILE BER.pm - Module by Simon Leinen SNMP_Session.pm - Module by Simon Leinen howto-iog.html - How-to by Sean Kelly http://www.inabiaf.com/howto-iog/ index.php - Index script by Preston Carter About: IOG is a network I/O byte grapher made to graph cumulative KB/MB/GB totals for hours/days and months. It is intended to be simple, fast (support thousands of hosts) and integrate well with MRTG. Data for each host is updated hourly and HTML graphs are created. It uses a data consolidation algorithm which allows for a small, non-growing database file for each host. No external graphing libs or executables are required. IOG has been used in several production ISP environments, including at the authors company, Dynamic Internet (dyni.net). MRTG: http://ee-staff.ethz.ch/~oetiker/webtools/mrtg/mrtg.html Comments: 64-bit SNMPv2c counters can now be used, use ifHCInOctets.# and ifHCOutOctets.# in iog.cfg. NT support has been added (tested under win2k), to enable full NT support pass the command line argument "NT" to iog. ex.) "perl iog NT" You will need to add entries to "at" to make it run once per hour. Thorough performance testing has not been done, but IOG should be able to handle >1000 hosts/ports adequately. If you are running on a semi-large network with at least 200 ports, please report your results to iog@dynw.com. *IMPORTANT*: You must select the proper sysUpTime value for your device otherwise problems will arrive when these devices reboot. Installation: Required... * WindowsNT/2000/XP with Perl/ActivePerl or your favorite UNIX OS with Perl. * A web browser (if you intend to let people view these pages through the world wide web). * A switch/router/device with an SNMPd/server configured. 1.) Untar/gz into your desired location. copy all .gif files to any directory that will contain HTML (path in .cfg). 2.) Edit "iog.cfg" and follow the examples to set-up your hosts. 3.) Add a crontab to run "iog" EVERY HOUR (NOT every 5 minutes). 0 * * * * /path/to/iog ..or an "at" entry on NT. 4.) Decide how you want your users to view the stats. Perhaps you want to add a type of authentication to view the graphs (.htaccess)? 5.) Watch it run and report bugs and performance info to iog@dynw.com. Try to include detailed info including OS type, Perl version etc. Upgrading: From 1.0rcX - When upgrading, the first hour might be in-accurate due to a minor change in db storage code. From v0.99 - Make a copy of your iog.cfg and copy over all the files in this directory. From v0.98 or earlier - The format of the iog.cfg file has changed, please see iog.cfg! Donations: No need for donations, but if you feel like doing something generous, send some business to the author's company at www.dyni.net or you can donate to the creator of SNMPlib or MRTG, they also produce great free software. Changes: v1.03 * Fixed bug which causes router/switch reboots to potentially cause large negative values for that particular hour. v1.02 * Added newer SNMP module that fixes compatibility with some switches. Included how-to by Sean Kelly. v1.01 * Fixed small "NE" bug by changing to lower-case. v1.00 * Previous months and days are now saved and linked to provide a more historical view of usage. * Added 64-bit SNMPv2c counter support, backwards compatible with SNMPv1. * Added easier way to change KB/MB/GB size to increase accuracy. v0.99 * Added uptime polling to detect hosts that have reset and adjust counters accordingly. (NOTE: Config file format has changed.) * Fixed bug that caused iog to die when a hostname could not be resolved. * Fixed reporting bug for hosts that are unreachable. v0.98 * Fixed bug causing January to not graph properly. * Changed "This Year" text to "Previous Months". v0.97 * Fixed interface counter wrap bug, previous fix was not complete. v0.96 * Fixed problem with in-accurate reporting when an interface counter wraps (every 4GB). File name is now displayed on front of HTML. v0.95 * Failed SNMPGets no longer reset counter to zero. v0.9 * 0KB cells are no longer displayed. * Problem with top navigation during hour 1:00 has been corrected. * "months" graph now displays GB total for In+Out. v0.8 * Fixed bug in monthly graph creation, totals were not being calculated properly. * Minor changes in MB/GB display. v0.7 * Preliminary NT support added. * MB(KB) now scales to GB(MB) when >1000mb to better display stats for busy hosts/ports. v0.6 * Fixed 0kb bars under Netscape. * Now detects when a hosts octet counters have reset to prevent negative totals from being displayed. * Navbar now only displays reports which are available. * HTML is now generated at first run, to avoid confusion. * Improved documentation. v0.5 * First public release. (10/12/2000) v0.4 * v0.1 - v0.3 * Internal development releases. ./iog-1.03/BER.pm100444 0 0 62734 7743014353 11556 0ustar rootwheel### -*- mode: Perl -*- ###################################################################### ### BER (Basic Encoding Rules) encoding and decoding. ###################################################################### ### Copyright (c) 1995-2002, Simon Leinen. ### ### This program is free software; you can redistribute it under the ### "Artistic License" included in this distribution (file "Artistic"). ###################################################################### ### This module implements encoding and decoding of ASN.1-based data ### structures using the Basic Encoding Rules (BER). Only the subset ### necessary for SNMP is implemented. ###################################################################### ### Created by: Simon Leinen ### ### Contributions and fixes by: ### ### Andrzej Tobola : Added long String decode ### Tobias Oetiker : Added 5 Byte Integer decode ... ### Dave Rand : Added SysUpTime decode ### Philippe Simonet : Support larger subids ### Yufang HU : Support even larger subids ### Mike Mitchell : New generalized encode_int() ### Mike Diehn : encode_ip_address() ### Rik Hoorelbeke : encode_oid() fix ### Brett T Warden : pretty UInteger32 ### Bert Driehuis : Handle SNMPv2 exception codes ### Jakob Ilves (/IlvJa) : PDU decoding ###################################################################### package BER; require 5.002; use strict; use vars qw(@ISA @EXPORT $VERSION $pretty_print_timeticks $errmsg); use Exporter; $VERSION = '0.95'; @ISA = qw(Exporter); @EXPORT = qw(context_flag constructor_flag encode_int encode_int_0 encode_null encode_oid encode_sequence encode_tagged_sequence encode_string encode_ip_address encode_timeticks encode_uinteger32 encode_counter32 encode_counter64 encode_gauge32 decode_sequence decode_by_template pretty_print pretty_print_timeticks hex_string hex_string_of_type encoded_oid_prefix_p errmsg); ### Variables ## Bind this to zero if you want to avoid that TimeTicks are converted ## into "human readable" strings containing days, hours, minutes and ## seconds. ## ## If the variable is zero, pretty_print will simply return an ## unsigned integer representing hundredths of seconds. ## $pretty_print_timeticks = 1; ### Prototypes sub encode_header ($$); sub encode_int_0 (); sub encode_int ($); sub encode_oid (@); sub encode_null (); sub encode_sequence (@); sub encode_tagged_sequence ($@); sub encode_string ($); sub encode_ip_address ($); sub encode_timeticks ($); sub pretty_print ($); sub pretty_using_decoder ($$); sub pretty_string ($); sub pretty_intlike ($); sub pretty_unsignedlike ($); sub pretty_oid ($); sub pretty_uptime ($); sub pretty_uptime_value ($); sub pretty_ip_address ($); sub pretty_generic_sequence ($); sub hex_string ($); sub hex_string_of_type ($$); sub decode_oid ($); sub decode_by_template; sub decode_by_template_2; sub decode_sequence ($); sub decode_int ($); sub decode_intlike ($); sub decode_unsignedlike ($); sub decode_intlike_s ($$); sub decode_string ($); sub decode_length ($); sub encoded_oid_prefix_p ($$); sub decode_subid ($$$); sub decode_generic_tlv ($); sub error (@); sub template_error ($$$); sub version () { $VERSION; } ### Flags for different types of tags sub universal_flag { 0x00 } sub application_flag { 0x40 } sub context_flag { 0x80 } sub private_flag { 0xc0 } sub primitive_flag { 0x00 } sub constructor_flag { 0x20 } ### Universal tags sub boolean_tag { 0x01 } sub int_tag { 0x02 } sub bit_string_tag { 0x03 } sub octet_string_tag { 0x04 } sub null_tag { 0x05 } sub object_id_tag { 0x06 } sub sequence_tag { 0x10 } sub set_tag { 0x11 } sub uptime_tag { 0x43 } ### Flag for length octet announcing multi-byte length field sub long_length { 0x80 } ### SNMP specific tags sub snmp_ip_address_tag { 0x00 | application_flag } sub snmp_counter32_tag { 0x01 | application_flag } sub snmp_gauge32_tag { 0x02 | application_flag } sub snmp_timeticks_tag { 0x03 | application_flag } sub snmp_opaque_tag { 0x04 | application_flag } sub snmp_nsap_address_tag { 0x05 | application_flag } sub snmp_counter64_tag { 0x06 | application_flag } sub snmp_uinteger32_tag { 0x07 | application_flag } ## Error codes (SNMPv2 and later) ## sub snmp_nosuchobject { context_flag | 0x00 } sub snmp_nosuchinstance { context_flag | 0x01 } sub snmp_endofmibview { context_flag | 0x02 } #### Encoding sub encode_header ($$) { my ($type,$length) = @_; return pack ("C C", $type, $length) if $length < 128; return pack ("C C C", $type, long_length | 1, $length) if $length < 256; return pack ("C C n", $type, long_length | 2, $length) if $length < 65536; return error ("Cannot encode length $length yet"); } sub encode_int_0 () { return pack ("C C C", 2, 1, 0); } sub encode_int ($) { return encode_intlike ($_[0], int_tag); } sub encode_uinteger32 ($) { return encode_intlike ($_[0], snmp_uinteger32_tag); } sub encode_counter32 ($) { return encode_intlike ($_[0], snmp_counter32_tag); } sub encode_counter64 ($) { return encode_intlike ($_[0], snmp_counter64_tag); } sub encode_gauge32 ($) { return encode_intlike ($_[0], snmp_gauge32_tag); } sub encode_intlike ($$) { my ($int, $tag)=@_; my ($sign, $val, @vals); $sign = ($int >= 0) ? 0 : 0xff; if (ref $int && $int->isa ("Math::BigInt")) { for(;;) { $val = $int->bmod (256); unshift(@vals, $val); return encode_header ($tag, $#vals + 1).pack ("C*", @vals) if ($int >= -128 && $int < 128); $int = $int - $sign; $int = $int / 256; } } else { for(;;) { $val = $int & 0xff; unshift(@vals, $val); return encode_header ($tag, $#vals + 1).pack ("C*", @vals) if ($int >= -128 && $int < 128); $int -= $sign; $int = int($int / 256); } } } sub encode_oid (@) { my @oid = @_; my ($result,$subid); $result = ''; ## Ignore leading empty sub-ID. The favourite reason for ## those to occur is that people cut&paste numeric OIDs from ## CMU/UCD SNMP including the leading dot. shift @oid if $oid[0] eq ''; return error ("Object ID too short: ", join('.',@oid)) if $#oid < 1; ## The first two subids in an Object ID are encoded as a single ## byte in BER, according to a funny convention. This poses ## restrictions on the ranges of those subids. In the past, I ## didn't check for those. But since so many people try to use ## OIDs in CMU/UCD SNMP's format and leave out the mib-2 or ## enterprises prefix, I introduced this check to catch those ## errors. ## return error ("first subid too big in Object ID ", join('.',@oid)) if $oid[0] > 2; $result = shift (@oid) * 40; $result += shift @oid; return error ("second subid too big in Object ID ", join('.',@oid)) if $result > 255; $result = pack ("C", $result); foreach $subid (@oid) { if ( ($subid>=0) && ($subid<128) ){ #7 bits long subid $result .= pack ("C", $subid); } elsif ( ($subid>=128) && ($subid<16384) ){ #14 bits long subid $result .= pack ("CC", 0x80 | $subid >> 7, $subid & 0x7f); } elsif ( ($subid>=16384) && ($subid<2097152) ) {#21 bits long subid $result .= pack ("CCC", 0x80 | (($subid>>14) & 0x7f), 0x80 | (($subid>>7) & 0x7f), $subid & 0x7f); } elsif ( ($subid>=2097152) && ($subid<268435456) ){ #28 bits long subid $result .= pack ("CCCC", 0x80 | (($subid>>21) & 0x7f), 0x80 | (($subid>>14) & 0x7f), 0x80 | (($subid>>7) & 0x7f), $subid & 0x7f); } elsif ( ($subid>=268435456) && ($subid<4294967296) ){ #32 bits long subid $result .= pack ("CCCCC", 0x80 | (($subid>>28) & 0x0f), #mask the bits beyond 32 0x80 | (($subid>>21) & 0x7f), 0x80 | (($subid>>14) & 0x7f), 0x80 | (($subid>>7) & 0x7f), $subid & 0x7f); } else { return error ("Cannot encode subid $subid"); } } encode_header (object_id_tag, length $result).$result; } sub encode_null () { encode_header (null_tag, 0); } sub encode_sequence (@) { encode_tagged_sequence (sequence_tag, @_); } sub encode_tagged_sequence ($@) { my ($tag,$result); $tag = shift @_; $result = join '',@_; return encode_header ($tag | constructor_flag, length $result).$result; } sub encode_string ($) { my ($string)=@_; return encode_header (octet_string_tag, length $string).$string; } sub encode_ip_address ($) { my ($addr)=@_; my @octets; if (length $addr == 4) { ## Four bytes... let's suppose that this is a binary IP address ## in network byte order. return encode_header (snmp_ip_address_tag, length $addr).$addr; } elsif (@octets = ($addr =~ /^([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)$/)) { return encode_ip_address (pack ("CCCC", @octets)); } else { return error ("IP address must be four bytes long or a dotted-quad"); } } sub encode_timeticks ($) { my ($tt) = @_; return encode_intlike ($tt, snmp_timeticks_tag); } #### Decoding sub pretty_print ($) { my ($packet) = @_; my ($type,$rest); return undef unless defined $packet; my $result = ord (substr ($packet, 0, 1)); return pretty_intlike ($packet) if $result == int_tag; return pretty_unsignedlike ($packet) if $result == snmp_counter32_tag || $result == snmp_gauge32_tag || $result == snmp_counter64_tag || $result == snmp_uinteger32_tag; return pretty_string ($packet) if $result == octet_string_tag; return pretty_oid ($packet) if $result == object_id_tag; return ($pretty_print_timeticks ? pretty_uptime ($packet) : pretty_unsignedlike ($packet)) if $result == uptime_tag; return pretty_ip_address ($packet) if $result == snmp_ip_address_tag; return "(null)" if $result == null_tag; return error ("Exception code: noSuchObject") if $result == snmp_nosuchobject; return error ("Exception code: noSuchInstance") if $result == snmp_nosuchinstance; return error ("Exception code: endOfMibView") if $result == snmp_endofmibview; # IlvJa # pretty print sequences and their contents. my $ctx_cons_flags = context_flag | constructor_flag; if($result == (&constructor_flag | &sequence_tag) # sequence || $result == (0 | $ctx_cons_flags) #get_request || $result == (1 | $ctx_cons_flags) #getnext_request || $result == (2 | $ctx_cons_flags) #get_response || $result == (3 | $ctx_cons_flags) #set_request || $result == (4 | $ctx_cons_flags) #trap_request || $result == (5 | $ctx_cons_flags) #getbulk_request || $result == (6 | $ctx_cons_flags) #inform_request || $result == (7 | $ctx_cons_flags) #trap2_request ) { my $pretty_result = pretty_generic_sequence($packet); $pretty_result =~ s/^/ /gm; #Indent. my $seq_type_desc = { (constructor_flag | sequence_tag) => "Sequence", (0 | $ctx_cons_flags) => "GetRequest", (1 | $ctx_cons_flags) => "GetNextRequest", (2 | $ctx_cons_flags) => "GetResponse", (3 | $ctx_cons_flags) => "SetRequest", (4 | $ctx_cons_flags) => "TrapRequest", (5 | $ctx_cons_flags) => "GetbulkRequest", (6 | $ctx_cons_flags) => "InformRequest", (7 | $ctx_cons_flags) => "Trap2Request", }->{($result)}; return $seq_type_desc . "{\n" . $pretty_result . "\n}"; } return sprintf ("#", $result); } sub pretty_using_decoder ($$) { my ($decoder, $packet) = @_; my ($decoded,$rest); ($decoded,$rest) = &$decoder ($packet); return error ("Junk after object") unless $rest eq ''; return $decoded; } sub pretty_string ($) { pretty_using_decoder (\&decode_string, $_[0]); } sub pretty_intlike ($) { my $decoded = pretty_using_decoder (\&decode_intlike, $_[0]); $decoded; } sub pretty_unsignedlike ($) { return pretty_using_decoder (\&decode_unsignedlike, $_[0]); } sub pretty_oid ($) { my ($oid) = shift; my ($result,$subid,$next); my (@oid); $result = ord (substr ($oid, 0, 1)); return error ("Object ID expected") unless $result == object_id_tag; ($result, $oid) = decode_length (substr ($oid, 1)); return error ("inconsistent length in OID") unless $result == length $oid; @oid = (); $subid = ord (substr ($oid, 0, 1)); push @oid, int ($subid / 40); push @oid, $subid % 40; $oid = substr ($oid, 1); while ($oid ne '') { $subid = ord (substr ($oid, 0, 1)); if ($subid < 128) { $oid = substr ($oid, 1); push @oid, $subid; } else { $next = $subid; $subid = 0; while ($next >= 128) { $subid = ($subid << 7) + ($next & 0x7f); $oid = substr ($oid, 1); $next = ord (substr ($oid, 0, 1)); } $subid = ($subid << 7) + $next; $oid = substr ($oid, 1); push @oid, $subid; } } join ('.', @oid); } sub pretty_uptime ($) { my ($packet,$uptime); ($uptime,$packet) = &decode_unsignedlike (@_); pretty_uptime_value ($uptime); } sub pretty_uptime_value ($) { my ($uptime) = @_; my ($seconds,$minutes,$hours,$days,$result); ## We divide the uptime by hundred since we're not interested in ## sub-second precision. $uptime = int ($uptime / 100); $days = int ($uptime / (60 * 60 * 24)); $uptime %= (60 * 60 * 24); $hours = int ($uptime / (60 * 60)); $uptime %= (60 * 60); $minutes = int ($uptime / 60); $seconds = $uptime % 60; if ($days == 0){ $result = sprintf ("%d:%02d:%02d", $hours, $minutes, $seconds); } elsif ($days == 1) { $result = sprintf ("%d day, %d:%02d:%02d", $days, $hours, $minutes, $seconds); } else { $result = sprintf ("%d days, %d:%02d:%02d", $days, $hours, $minutes, $seconds); } return $result; } sub pretty_ip_address ($) { my $pdu = shift; my ($length, $rest); return error ("IP Address tag (".snmp_ip_address_tag.") expected") unless ord (substr ($pdu, 0, 1)) == snmp_ip_address_tag; $pdu = substr ($pdu, 1); ($length,$pdu) = decode_length ($pdu); return error ("Length of IP address should be four") unless $length == 4; sprintf "%d.%d.%d.%d", unpack ("CCCC", $pdu); } # IlvJa # Returns a string with the pretty prints of all # the elements in the sequence. sub pretty_generic_sequence ($) { my ($pdu) = shift; my $rest; my $type = ord substr ($pdu, 0 ,1); my $flags = context_flag | constructor_flag; return error (sprintf ("Tag 0x%x is not a valid sequence tag",$type)) unless ($type == (&constructor_flag | &sequence_tag) # sequence || $type == (0 | $flags) #get_request || $type == (1 | $flags) #getnext_request || $type == (2 | $flags) #get_response || $type == (3 | $flags) #set_request || $type == (4 | $flags) #trap_request || $type == (5 | $flags) #getbulk_request || $type == (6 | $flags) #inform_request || $type == (7 | $flags) #trap2_request ); my $curelem; my $pretty_result; # Holds the pretty printed sequence. my $pretty_elem; # Holds the pretty printed current elem. my $first_elem = 'true'; # Cut away the first Tag and Length from $packet and then # init $rest with that. (undef, $rest) = decode_length(substr $pdu, 1); while($rest) { ($curelem,$rest) = decode_generic_tlv($rest); $pretty_elem = pretty_print($curelem); $pretty_result .= "\n" if not $first_elem; $pretty_result .= $pretty_elem; # The rest of the iterations are not related to the # first element of the sequence so.. $first_elem = '' if $first_elem; } return $pretty_result; } sub hex_string ($) { &hex_string_of_type ($_[0], octet_string_tag); } sub hex_string_of_type ($$) { my ($pdu, $wanted_type) = @_; my ($length); return error ("BER tag ".$wanted_type." expected") unless ord (substr ($pdu, 0, 1)) == $wanted_type; $pdu = substr ($pdu, 1); ($length,$pdu) = decode_length ($pdu); hex_string_aux ($pdu); } sub hex_string_aux ($) { my ($binary_string) = @_; my ($c, $result); $result = ''; for $c (unpack "C*", $binary_string) { $result .= sprintf "%02x", $c; } $result; } sub decode_oid ($) { my ($pdu) = @_; my ($result,$pdu_rest); my (@result); $result = ord (substr ($pdu, 0, 1)); return error ("Object ID expected") unless $result == object_id_tag; ($result, $pdu_rest) = decode_length (substr ($pdu, 1)); return error ("Short PDU") if $result > length $pdu_rest; @result = (substr ($pdu, 0, $result + (length ($pdu) - length ($pdu_rest))), substr ($pdu_rest, $result)); @result; } # IlvJa # This takes a PDU and returns a two element list consisting of # the first element found in the PDU (whatever it is) and the # rest of the PDU sub decode_generic_tlv ($) { my ($pdu) = @_; my (@result); my ($elemlength,$pdu_rest) = decode_length (substr($pdu,1)); @result = (# Extract the first element. substr ($pdu, 0, $elemlength + (length ($pdu) - length ($pdu_rest) ) ), #Extract the rest of the PDU. substr ($pdu_rest, $elemlength) ); @result; } sub decode_by_template { my ($pdu) = shift; local ($_) = shift; return decode_by_template_2 ($pdu, $_, 0, 0, @_); } my $template_debug = 0; sub decode_by_template_2 { my ($pdu, $template, $pdu_index, $template_index); local ($_); $pdu = shift; $template = $_ = shift; $pdu_index = shift; $template_index = shift; my (@results); my ($length,$expected,$read,$rest); return undef unless defined $pdu; while (0 < length ($_)) { if (substr ($_, 0, 1) eq '%') { print STDERR "template $_ ", length $pdu," bytes remaining\n" if $template_debug; $_ = substr ($_,1); ++$template_index; if (($expected) = /^(\d*|\*)\{(.*)/) { ## %{ $template_index += length ($expected) + 1; print STDERR "%{\n" if $template_debug; $_ = $2; $expected = shift | constructor_flag if ($expected eq '*'); $expected = sequence_tag | constructor_flag if $expected eq ''; return template_error ("Unexpected end of PDU", $template, $template_index) if !defined $pdu or $pdu eq ''; return template_error ("Expected sequence tag $expected, got ". ord (substr ($pdu, 0, 1)), $template, $template_index) unless (ord (substr ($pdu, 0, 1)) == $expected); $pdu = substr ($pdu,1); (($length,$pdu) = decode_length ($pdu)) || return template_error ("cannot read length", $template, $template_index); return template_error ("Expected length $length, got ".length $pdu , $template, $template_index) unless length $pdu == $length; } elsif (($expected,$rest) = /^(\*|)s(.*)/) { ## %s $template_index += length ($expected) + 1; ($expected = shift) if $expected eq '*'; (($read,$pdu) = decode_string ($pdu)) || return template_error ("cannot read string", $template, $template_index); print STDERR "%s => $read\n" if $template_debug; if ($expected eq '') { push @results, $read; } else { return template_error ("Expected $expected, read $read", $template, $template_index) unless $expected eq $read; } $_ = $rest; } elsif (($rest) = /^A(.*)/) { ## %A $template_index += 1; { my ($tag, $length, $value); $tag = ord (substr ($pdu, 0, 1)); return error ("Expected IP address, got tag ".$tag) unless $tag == snmp_ip_address_tag; ($length, $pdu) = decode_length (substr ($pdu, 1)); return error ("Inconsistent length of InetAddress encoding") if $length > length $pdu; return template_error ("IP address must be four bytes long", $template, $template_index) unless $length == 4; $read = substr ($pdu, 0, $length); $pdu = substr ($pdu, $length); } print STDERR "%A => $read\n" if $template_debug; push @results, $read; $_ = $rest; } elsif (/^O(.*)/) { ## %O $template_index += 1; $_ = $1; (($read,$pdu) = decode_oid ($pdu)) || return template_error ("cannot read OID", $template, $template_index); print STDERR "%O => ".pretty_oid ($read)."\n" if $template_debug; push @results, $read; } elsif (($expected,$rest) = /^(\d*|\*|)i(.*)/) { ## %i $template_index += length ($expected) + 1; print STDERR "%i\n" if $template_debug; $_ = $rest; (($read,$pdu) = decode_int ($pdu)) || return template_error ("cannot read int", $template, $template_index); if ($expected eq '') { push @results, $read; } else { $expected = int (shift) if $expected eq '*'; return template_error (sprintf ("Expected %d (0x%x), got %d (0x%x)", $expected, $expected, $read, $read), $template, $template_index) unless ($expected == $read) } } elsif (($rest) = /^u(.*)/) { ## %u $template_index += 1; print STDERR "%u\n" if $template_debug; $_ = $rest; (($read,$pdu) = decode_unsignedlike ($pdu)) || return template_error ("cannot read uptime", $template, $template_index); push @results, $read; } elsif (/^\@(.*)/) { ## %@ $template_index += 1; print STDERR "%@\n" if $template_debug; $_ = $1; push @results, $pdu; $pdu = ''; } else { return template_error ("Unknown decoding directive in template: $_", $template, $template_index); } } else { if (substr ($_, 0, 1) ne substr ($pdu, 0, 1)) { return template_error ("Expected ".substr ($_, 0, 1).", got ".substr ($pdu, 0, 1), $template, $template_index); } $_ = substr ($_,1); $pdu = substr ($pdu,1); } } return template_error ("PDU too long", $template, $template_index) if length ($pdu) > 0; return template_error ("PDU too short", $template, $template_index) if length ($_) > 0; @results; } sub decode_sequence ($) { my ($pdu) = @_; my ($result); my (@result); $result = ord (substr ($pdu, 0, 1)); return error ("Sequence expected") unless $result == (sequence_tag | constructor_flag); ($result, $pdu) = decode_length (substr ($pdu, 1)); return error ("Short PDU") if $result > length $pdu; @result = (substr ($pdu, 0, $result), substr ($pdu, $result)); @result; } sub decode_int ($) { my ($pdu) = @_; my $tag = ord (substr ($pdu, 0, 1)); return error ("Integer expected, found tag ".$tag) unless $tag == int_tag; decode_intlike ($pdu); } sub decode_intlike ($) { decode_intlike_s ($_[0], 1); } sub decode_unsignedlike ($) { decode_intlike_s ($_[0], 0); } my $have_math_bigint_p = 0; sub decode_intlike_s ($$) { my ($pdu, $signedp) = @_; my ($length,$result); $length = ord (substr ($pdu, 1, 1)); my $ptr = 2; $result = unpack ($signedp ? "c" : "C", substr ($pdu, $ptr++, 1)); if ($length > 5 || ($length == 5 && $result > 0)) { require 'Math/BigInt.pm' unless $have_math_bigint_p++; $result = new Math::BigInt ($result); } while (--$length > 0) { $result *= 256; $result += unpack ("C", substr ($pdu, $ptr++, 1)); } ($result, substr ($pdu, $ptr)); } sub decode_string ($) { my ($pdu) = shift; my ($result); $result = ord (substr ($pdu, 0, 1)); return error ("Expected octet string, got tag ".$result) unless $result == octet_string_tag; ($result, $pdu) = decode_length (substr ($pdu, 1)); return error ("Short PDU") if $result > length $pdu; return (substr ($pdu, 0, $result), substr ($pdu, $result)); } sub decode_length ($) { my ($pdu) = shift; my ($result); my (@result); $result = ord (substr ($pdu, 0, 1)); if ($result & long_length) { if ($result == (long_length | 1)) { @result = (ord (substr ($pdu, 1, 1)), substr ($pdu, 2)); } elsif ($result == (long_length | 2)) { @result = ((ord (substr ($pdu, 1, 1)) << 8) + ord (substr ($pdu, 2, 1)), substr ($pdu, 3)); } else { return error ("Unsupported length"); } } else { @result = ($result, substr ($pdu, 1)); } @result; } #### OID prefix check ### encoded_oid_prefix_p OID1 OID2 ### ### OID1 and OID2 should be BER-encoded OIDs. ### The function returns non-zero iff OID1 is a prefix of OID2. ### This can be used in the termination condition of a loop that walks ### a table using GetNext or GetBulk. ### sub encoded_oid_prefix_p ($$) { my ($oid1, $oid2) = @_; my ($i1, $i2); my ($l1, $l2); my ($subid1, $subid2); return error ("OID tag expected") unless ord (substr ($oid1, 0, 1)) == object_id_tag; return error ("OID tag expected") unless ord (substr ($oid2, 0, 1)) == object_id_tag; ($l1,$oid1) = decode_length (substr ($oid1, 1)); ($l2,$oid2) = decode_length (substr ($oid2, 1)); for ($i1 = 0, $i2 = 0; $i1 < $l1 && $i2 < $l2; ++$i1, ++$i2) { ($subid1,$i1) = &decode_subid ($oid1, $i1, $l1); ($subid2,$i2) = &decode_subid ($oid2, $i2, $l2); return 0 unless $subid1 == $subid2; } return $i2 if $i1 == $l1; return 0; } ### decode_subid OID INDEX ### ### Decodes a subid field from a BER-encoded object ID. ### Returns two values: the field, and the index of the last byte that ### was actually decoded. ### sub decode_subid ($$$) { my ($oid, $i, $l) = @_; my $subid = 0; my $next; while (($next = ord (substr ($oid, $i, 1))) >= 128) { $subid = ($subid << 7) + ($next & 0x7f); ++$i; return error ("decoding object ID: short field") unless $i < $l; } return (($subid << 7) + $next, $i); } sub error (@) { $errmsg = join ("",@_); return undef; } sub template_error ($$$) { my ($errmsg, $template, $index) = @_; return error ($errmsg."\n ".$template."\n ".(' ' x $index)."^"); } 1; ./iog-1.03/out.gif100644 0 0 51 7743014353 12010 0ustar rootwheelGIF89a,S;./iog-1.03/index.php100644 0 0 1657 7743561742 12420 0ustar rootwheel Click on host to view transfer stats

"; $directory = "./"; $handle = opendir('.'); closedir($handle); $handle=opendir('.'); $counter = 0; while ($file = readdir($handle)) { // Filter by extension type $the_type = strrchr($file, "."); $allow_file = eregi("html",$the_type); if ($file != "." and $file != ".." and $allow_file) { // Get name without extension if ($a=strpos($file,'.')) { $ext=substr($file,$a); // . inside $file=substr($file,0,$a); $myfiles[$counter] = $file; // Test for presence of -days, -months $ok=(strpos($file,'-month')===FALSE); $ok=($ok AND (strpos($file,'-day')===FALSE)); // if ok, memorize and print if ($ok) { echo "$file
"; $counter++; } } } } closedir($handle); ?>