use FindBin; die unless ($FindBin::Script =~ m/^(.*?)\.PL$/); open(STDOUT, ">$1") or die "open \"$1\": $!"; print __END__ #! /usr/local/bin/perl # junipoll - a JUNIper router snmp POLLer (for firewall filter counters) # Copyright (C) 2002-2005 Dave Plonka # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # $Id: junipoll.PL,v 1.18 2005/05/19 19:39:33 dplonka Exp $ # Dave Plonka , original May 22 2002 # { CONFIGURATION SECTION BEGIN ################################################ # { these can be specified from the command line: my @peer = (); # [community@]host [...] my $default_community = 'public'; my $verbose = 0; # } # } CONFIGURATION SECTION END ################################################## use Altoids; # http://net.doit.wisc.edu/~plonka/Altoids/ use RRDs; # http://ee-staff.ethz.ch/~oetiker/webtools/rrdtool/ use Getopt::Std; use FindBin; # convert the RCS revision to a reasonable Exporter VERSION: my $VERSION; '$Revision: 1.18 $' =~ m/(\d+)\.(\d+)/ && (( $VERSION ) = sprintf("%d.%03d", $1, $2)); usage(2) if !getopts('vc:nmhV'); if ($opt_v or $opt_n) { $verbose = 1 } if ($opt_c) { $default_community = $opt_c } if (@ARGV) { @peer = @ARGV } if ($opt_V) { print <<_EOF_ This is $FindBin::Script version $VERSION Copyright 2002-2003, Dave Plonka This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. _EOF_ ; exit(0); } usage(0) if $opt_h; usage(2) unless @peer; # map the OIDs (as defined in their MIB): my $hints = map_oids(); $snmp = Altoids->new($hints); die unless ref($snmp); foreach my $peer (@peer) { if ($peer =~ m/^(\S+)\@(\S+)$/) { $community = $1; $host = $2 } else { $community = $default_community; $host = $peer } if (!$snmp->open($host, $community, 161)) { warn "$_: open failed.\n"; next } %retblock = $snmp->walk('jnxFWCounterPacketCount', 'jnxFWCounterByteCount'); my $when = time; if (-1 == $retblock{-1}) { warn "$_: get failed.\n"; next } hashprint($host, %retblock) if $verbose; $snmp->close(); my($filter, $counter_hr, %results, $counter, $hr); while (($filter, $counter_hr) = each(%{$retblock{jnxFWCounterPacketCount}})) { while (($counter, $hr) = each(%$counter_hr)) { # magic-number "2" means "counter" (from "JUNIPER-FIREWALL-MIB") $results{"${host}_${filter}_${counter}"}{WHEN} = $when; $results{"${host}_${filter}_${counter}"}{pkts} = $hr->{2}; $results{"${host}_${filter}_${counter}"}{bytes} = $retblock{jnxFWCounterByteCount}{$filter}{$counter}{2}; } } updateRRDs(\%results) unless $opt_n; } exit; sub updateRRDs { my $results = shift @_; my($name, $hr); while (my($name, $hr) = each %{$results}) { my $file = "$name.rrd"; $file =~ s|/|_|g; createGeneralRRD($file, $hr->{WHEN}, $opt_m? qw(COUNTER ds0 COUNTER ds1) : qw(COUNTER pkts COUNTER bytes) ) unless -f $file; my @values = (); push(@values, $hr->{pkts}, $hr->{bytes}); updateRRD($file, $hr->{WHEN}, @values); } } sub createGeneralRRD { my $file = shift; die if '' eq $file; my $when = shift; die if -1 == $when; die unless @_; # DS types and names are required my $time_t = $when; my $startwhen = $time_t - 300; my($name, $type, @DS); while (($type = shift(@_)) && ($name = shift(@_))) { push(@DS, "DS:${name}:${type}:400:U:U") } RRDs::create($file, '--start', $startwhen, '--step', 300, @DS, qw( RRA:AVERAGE:0:1:105408 RRA:AVERAGE:0:6:600 RRA:AVERAGE:0:24:600 RRA:AVERAGE:0:288:1827 RRA:MAX:0:24:600 RRA:MAX:0:288:1827 ) ); my $err=RRDs::error; warn "ERROR creating $file: $err\n" if $err; } sub updateRRD { my $file = shift; die if '' eq $file; my $when = shift; die if -1 == $when; my @values = @_; if ($verbose) { print "RRDs::update $file $when @values ...\n" } # strip off leading '+' signs otherwise, as of rrdtool-1.0.46, # update complains "not a simple integer" grep { s/^\+// } @values; RRDs::update($file, $when . ':' . join(':', @values)); my $err=RRDs::error; if ($err) { warn "ERROR updating $file: $err\n" } } sub map_oids { # { These OIDs were glommed from Juniper's mib: # http://www.juniper.net/techpubs/software/junos53/swconfig53-net-mgmt/html/mib-firewall.txt # $hints = { sysDescr => { # from "RFC1213-MIB" humanoid => 'iso.org.dod.internet.mgmt.mib-2.system.sysDescr', oid => '1.3.6.1.2.1.1.1', rhs => 'string', }, iso => { oid => '1', humanoid => 'iso', }, org => { oid => '1.3', humanoid => 'iso.org', }, dod => { oid => '1.3.6', humanoid => 'iso.org.dod', }, internet => { oid => '1.3.6.1', humanoid => 'iso.org.dod.internet', }, mgmt => { oid => '1.3.6.1.2', humanoid => 'iso.org.dod.internet.mgmt', }, private => { oid => '1.3.6.1.4', humanoid => 'iso.org.dod.internet.private', }, enterprises => { oid => '1.3.6.1.4.1', humanoid => 'iso.org.dod.internet.private.enterprises', }, # { The following were glommed from "JUNIPER-FIREWALL-MIB": juniperMIB => { oid => '1.3.6.1.4.1.2636', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB', }, jnxMibs => { oid => '1.3.6.1.4.1.2636.3', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs', }, jnxFirewalls => { oid => '1.3.6.1.4.1.2636.3.5', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls', }, jnxFirewallCounterTable => { oid => '1.3.6.1.4.1.2636.3.5.2', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable', }, # INDEX of jnxFWCounterFilterName, jnxFWCounterName, jnxFWCounterType jnxFirewallCounterEntry => { oid => '1.3.6.1.4.1.2636.3.5.2.1', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable.jnxFirewallCounterEntry', lhs => ['nstring', 'nstring', 'index'], }, jnxFWCounterFilterName => { oid => '1.3.6.1.4.1.2636.3.5.2.1.1', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable.jnxFirewallCounterEntry.jnxFWCounterFilterName', lhs => ['nstring', 'nstring', 'index'], }, jnxFWCounterName => { oid => '1.3.6.1.4.1.2636.3.5.2.1.2', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable.jnxFirewallCounterEntry.jnxFWCounterName', lhs => ['nstring', 'nstring', 'index'], }, jnxFWCounterType => { oid => '1.3.6.1.4.1.2636.3.5.2.1.3', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable.jnxFirewallCounterEntry.jnxFWCounterType', lhs => ['nstring', 'nstring'], rhstrans => { 1 => 'other(1)', 2 => 'counter(2)', 3 => 'policer(3)', } }, jnxFWCounterPacketCount => { oid => '1.3.6.1.4.1.2636.3.5.2.1.4', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable.jnxFirewallCounterEntry.jnxFWCounterPacketCount', lhs => ['nstring', 'nstring', 'index'], }, jnxFWCounterByteCount => { oid => '1.3.6.1.4.1.2636.3.5.2.1.5', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable.jnxFirewallCounterEntry.jnxFWCounterByteCount', lhs => ['nstring', 'nstring', 'index'], }, jnxFWCounterDisplayFilterName => { oid => '1.3.6.1.4.1.2636.3.5.2.1.6', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable.jnxFirewallCounterEntry.jnxFWCounterDisplayFilterName', lhs => ['nstring', 'nstring', 'index'], }, jnxFWCounterDisplayName => { oid => '1.3.6.1.4.1.2636.3.5.2.1.7', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable.jnxFirewallCounterEntry.jnxFWCounterDisplayName', lhs => ['nstring', 'nstring', 'index'], }, jnxFWCounterDisplayType => { oid => '1.3.6.1.4.1.2636.3.5.2.1.6', humanoid => 'iso.org.dod.internet.private.enterprises.juniperMIB.jnxMibs.jnxFirewalls.jnxFirewallCounterTable.jnxFirewallCounterEntry.jnxFWCounterDisplayType', lhs => ['nstring', 'nstring'], rhstrans => { 1 => 'other(1)', 2 => 'counter(2)', 3 => 'policer(3)', } }, # } }; return $hints } ################################################################################ sub usage { print STDERR <<_EOF_ usage: $FindBin::Script [-v|n|V] [-m] [-c default_community] [community@]host [...] -v - verbose (mnemonic: 'v'erbose) -n - don't create or update RRD files, just show counters (implies "-v") (mnemonic: 'n'o, don't do anything) -m - name the data sources "ds0" and "ds1", rather than "pkts" and "bytes", respectively, ala MRTG when "LogFormat: rrdtool" is set. (mnemonic: 'm'rtg mode) -h - shows this usage information (mnemonic: 'h'elp) -V - show info about this $FindBin::Script version (mnemonic: 'V'ersion) _EOF_ ; exit $_[0] } ################################################################################ sub hashprint { my $prefix = shift @_; my %hash = @_; my ($val, $key); my $delim = ($opt_d? $opt_d : '.'); while (($key, $val) = each(%hash)) { if ('HASH' eq ref($val)) { hashprint($prefix? $prefix . $delim . $key : $key, %{$val}) } else { print $prefix, $delim, "$key = $val\n" } } }