I've hacked the script below together to let me generate traps to a test server. What I really need is something that will generate traps at a large scale so that I can check my tools on the receiving end to find out where the bottleneck is, such as UDP, Net::SNMP, Perl, etc.
I had hoped this script would let me generate something like 10k events/second but I am sadly mistaken.
Does anyone know if I can do this in Perl or have a suggestion of another way to do it?
#! /usr/bin/perl
use strict;
use warnings;
use Log::Fast;
use FindBin;
use Getopt::Long;
use File::Basename;
use Cwd qw(abs_path);
my $ROOT_DIR = abs_path("$FindBin::Bin/..");
use POSIX qw/strftime/;
use Net::SNMP qw(:ALL);
use Time::HiRes qw( time sleep );
#FIXME - I had to add below for Perl 5.10 users.
# on Perl 5.10, I would get the following when running:
# perl -e"autoflush STDOUT, 1;"
# Can't locate object method "autoflush" via package "IO::Handle" at -e line 1.
use FileHandle;
# Create default logger, will reconfigure it as soon as we read configuration from database
my $log = Log::Fast->global();
my $myname = $0;
$myname =~ s{.*/}{}; # leave just program name without path
# Command line options
my $options = {
debug => 0,
verbose => 0,
logfile => "./$myname.log",
help => 0,
community => "public",
trapsource => "127.0.0.1",
timelimit => 1,
};
sub usage_and_exit {
my ($exit_code) = #_;
print STDERR qq{
This program is used to generate SNMP traps to a specified host at a specified rate
Usage: $myname [-o --option]
-h : this (help) message
-d : debug level (0-5) (0 = disabled [default])
-v : Also print results to STDERR
-l : log file (defaults to local dir
-r : Rate (events/sec)
-ts : host to generate messages FROM
-td : host to generate messages TO
-tl : Run for this many seconds (default 1)
-c : community
Example: $myname -td 192.168.28.29 -r 1 -tl 5 -v
};
exit($exit_code);
}
GetOptions(
'debug|d=i' => \$options->{debug},
'help|h!' => \$options->{help},
'verbose|v!' => \$options->{verbose},
'logfile|l=s' => \$options->{logfile},
'rate|r=i' => \$options->{rate},
'trapsource|ts=s' => \$options->{trapsource},
'trapdest|td=s' => \$options->{trapdest},
'community|c=s' => \$options->{community},
'timelimit|tl=i' => \$options->{timelimit},
) or usage_and_exit(1); # got some invalid options
if ( $options->{help} ) {
usage_and_exit(0);
}
# Reconfigure log to use logfile (as we finally got it from $settings), also
# set proper level and output based on $options{verbose} and $options{debug}
setup_log();
# Finally we are initialized, announce this to the world :-)
$log->INFO("Program initialized successfully");
my $date = strftime "%Y-%m-%d %H:%M:%S", localtime;
# start func
my $period = 1 / $options->{rate};
my $start = time();
my $limit = time() + $options->{timelimit};
my $total = $options->{rate} * $options->{timelimit};
$log->INFO("Generating $options->{rate} trap(s) every second for $options->{timelimit} seconds (1 every $period seconds, $total total events)");
while($start < $limit) {
my $elapsed = time() - $start;
if ($elapsed < $period) {
sleep($period - $elapsed);
my ($session, $error) = Net::SNMP->session(
-hostname => $options->{trapdest},
-community => $options->{community},
-port => SNMP_TRAP_PORT, # Need to use port 162
-version => 'snmpv2c'
);
if (!defined($session)) {
$log->INFO("ERROR: %s.", $error);
exit 1;
}
my $result = $session->snmpv2_trap(
-varbindlist => [
'1.3.6.1.2.1.1.3.0', TIMETICKS, 600,
'1.3.6.1.6.3.1.1.4.1.0', OBJECT_IDENTIFIER, '1.3.6.1.4.1.326',
'1.3.6.1.6.3.18.1.3.0', IPADDRESS, $options->{trapsource}
]
);
if (!defined($result)) {
$log->INFO("ERROR: %s.", $session->error());
} else {
$log->INFO("SNMPv2-Trap-PDU sent from $options->{trapsource} to $options->{trapdest}.");
}
} else {
$start = time();
}
}
#-------------------------------------------
# There should only be subs from here down
#-------------------------------------------
# =================================================================================================
# Helper functions
# =================================================================================================
# commify not used yet
sub commify {
my $text = reverse $_[0];
$text =~ s/(\d\d\d)(?=\d)(?!\d*\.)/$1,/g;
return scalar reverse $text;
}
sub setup_log {
my $log_dir = dirname($options->{logfile});
# Create log dir, and build log path if not provided by command line option
if ( !-d $log_dir ) {
mkdir( $log_dir, 0755 ) or die("mkdir $log_dir: $!");
}
if ( !$options->{logfile} ) {
$options->{logfile} = $log_dir . "/" . basename( $0, '.pl' ) . '.log';
}
my $log_options = {};
# Set up output to file or both file and stderr
if ( $options->{verbose} ) {
# make multiplexer FH sending data both to file and STDERR
open( my $fh, '>>:tee', $options->{logfile}, \*STDERR )
or die("$options->{logfile}: $!");
$fh->autoflush(1);
$log_options->{fh} = $fh;
}
else {
open( my $fh, '>>', $options->{logfile} ) or die("$options->{logfile}: $!");
$log_options->{fh} = $fh;
}
# Setup extra information to put in every log line, depending on debug level
if ( $options->{debug} > 1 ) {
$log_options->{prefix} = "%D %T %S [%L] ";
}
else {
$log_options->{prefix} = "%D %T [%L] ";
}
$log_options->{level} = $options->{debug} > 0 ? 'DEBUG' : 'INFO';
$log->config($log_options);
$SIG{__WARN__} = sub {
my $msg = shift;
$msg =~ s/\n//;
$log->WARN($msg);
};
$log->INFO("Starting logging to $options->{logfile} with pid $$");
}
sub DEBUG {
my ( $level, #log_args ) = #_;
if ( $options->{debug} >= $level ) {
$log->DEBUG(#log_args);
}
}
Perhaps use something like Parallel::ForkManager ? In addition, with specific regard to testing scalability of your SNMP collector, you'll probably be interested in the use case of receiving the traps from many HOSTS, not just a single host sending traps at a high rate. For that, you might want to look at using pssh.
One problem might be the slowness of Net::SNMP in pure-perl - perhaps exectuting snmptest or snmptrap via the shell might be faster ? Worth a try.
Related
Morning SO,
I'm working on redesigning a Perl script designed by an external software vendor. It uses Perl, which I've never written in before. Basically all it does is read a line in, and then send a syslog packet to the a destination host containing that line. I need to modify it so Perl will keep reading and concat'ing until it reaches "". The problem is, it loops on the first line of a given file, and therefore never reaches the send stage. Any guidance on this? I went back and read the original script again, and it doesn't look to have a mechanism for iterating through each line.
Edit: OK - so apparently I've gone stupid and can't understand basic iterative logic. Fixed the looping problem, now to fix the syslog sending problem. It reads the data in correctly, but never executes the syslog send request, which implies it's not getting into the if statements.
Program should eventually enter here: if($lineRead eq $check){//do something;}
#!/usr/bin/perl -w
use strict;
use warnings;
use lib qw(.);
use lib qw(<removed>);
use Syslog;
use Time::HiRes qw( time sleep usleep );
use Getopt::Std;
# create log entries at a fixed rate (n per sec)
# Option defautls
my $me = $0;
$me =~ s|.*/||;
my %options = (
d => "127.0.0.1", # host
p => 514, # port
f => "readme.syslog", # filename
b => 0, # burst
v => 0, # verbose
t => 0, # tcp vs. udp
l => 0, # loop option
# u => "127.0.0.2", # new IP to send
);
my $theProto='tcp';
# Help
sub HELP_MESSAGE {
print <<EOF;
$me [-d <host>] [-p <port>] [-f filename] [-u <IP>] [-l] [-t] [-b] [-n NAME] [-v] <messages per second>
Options:
-d : destination syslog host (default 127.0.0.1)
-p : destination port (default 514)
-f : filename to read (default readme.syslog)
-b : burst the same message for 20% of the delay time
-t : use TCP instead of UDP for sending syslogs
-v : verbose, display lines read in from file
-n : use NAME for object name in syslog header
-l : loop indefinately
-u : use this IP as spoofed sender (default is NOT to send IP header)
EOF
}
getopts('vbtlu:d:p:n:f:', \%options);
unless (#ARGV) {
print STDERR "Need an event rate.\n";
HELP_MESSAGE;
exit 1;
}
my $nmsg = shift #ARGV;
if (!($nmsg =~ /^\d+$/)) {
print "Invalid number of messages per second.\n";
HELP_MESSAGE;
exit 1;
}
if ($options{t}) { $theProto='tcp'; }
my $syslog = new Syslog(
name => $options{n}, # prog name for syslog header
facility => 'local6',
priority => 'info',
loghost => $options{d},
port => $options{p},
proto => $theProto,
);
sub doitall() { # for purpose of infinate looping
open(F,$options{f}) or die("Unable to open file: $options{f}\n");
print STDERR "generating $nmsg messages per second to $options{d}:$options{p}\n";
print STDERR "Ctrl-c to stop\n";
# delay in milliseconds
my $delay = 1.0/$nmsg;
my $resolution = 0.2;
my $burst = $nmsg * $resolution;
my $check = "</Event>";
my $lineRead;
my $payload="a";
if ($options{b}) {
print "Sending $burst messages every ", int ($delay * 1000), "ms\n";
}
while (<F>) {
#print $lineRead;
if ($options{v}) {
print "Read in: $_\n";
}
$lineRead=$_;
if($lineRead eq $check){
$payload = join $payload, $lineRead;
if ($options{b}) {
for (my $i = 0 ; $i < $burst; $i++) {
if ($options{u}) { print $payload; $syslog->send($payload, host=> $options{u}); }
else { print $payload; $syslog->send($payload); }
}
} else {
if ($options{u}) { print $payload; $syslog->send($payload, host=> $options{u}); }
else { print $payload; $syslog->send($payload); }
}
if ($delay > 0) {
if ($options{v}) {
print "waiting for ", int($delay * 1000), "ms ...\n";
}
usleep (1000000*$delay);
}
$lineRead = "a";
$payload = "a";
}
else{
$payload = join $payload, $lineRead;
}
}
close(F);
} # end of the subroutine
if ($options{l}) {
while (1) { doitall(); }
} else { doitall(); }
exit 0;
I was using this in the perl script, where it is login to a couple of servers and trying to change the password for the servers through a remote host. But the problem is that the password is not getting changed on both the servers as well as i am not finding a way to check if the new passwords are passed to the servers using expect. i am posting that part of the code where it is checking for the prompt and trying to change the password.
#!/usr/bin/perl
package Session;
use strict;
use warnings;
use Expect;
use IO::Pty;
use Data::Dumper;
use Time::HiRes qw(usleep);
use Switch;
use YAML;
use feature 'say';
my $host1 = $ARGV[0];
my $host2 = $ARGV[1];
my $host1_adapter_name = $ARGV[2];
my $host2_adapter_name = $ARGV[3];
my $exp = Expect->new;
my ($selfObj) = #_;
my $str = "{$host1}\{root} # ";
my $cmdStr; my $result; my $dev_id;
my $timeout = 10;
my $min = 192;
my $range = 32;
my $host1_dev_id = _adapter($host1_adapter_name);
my $host2_dev_id = _adapter($host2_adapter_name);
my #hosts = ("$host1", "$host2");
print ("host2 name is=$host2------");
foreach my $n (#hosts)
{
print ("value of n is $n\n");
if ( $n eq $host1 )
{
_login($n,$host1_dev_id);
}
if ( $n eq $host2)
{
print ("inside 2nd if-----\n");
_login($n,$host2_dev_id);
}
}
sub _login
{
my ($host,$host_dev_id) = #_;
my $exit = 1;
$exp->raw_pty(1);
$exp = Expect->spawn("telnet $host") or die "unable to connect , Please check the connection & retry again: $!\n";
if (!defined($exp))
{
print "Please check the connection & retry again\n";
return -1;
}
`sleep 2 `;
$exp->expect($timeout,
[
qr'[lL]ogin:[\s]?[a]?[s]?[\s]?$',
sub
{
$exp->send("root\r");
`sleep 3 `;
exp_continue;
}
],
[
qr'[pP]assword:[\s]?$',
sub
{
$exp->send("That11NeverWork!\r");
exp_continue;
}
],
[
qr '[#>:][\s]?$',
sub {
$cmdStr = "passwd\r";
$result =_run_cmd($cmdStr);
qr'root\'s New password:\s*';
$exp->send("raym0nd24");
qr'Enter the new password again:\s*';
$exp->send("raym0nd24");
# $exp->send('passwd:\s*',5);
$exit = 0;
exp_continue;
}
],
[
eof =>
sub
{
print("FileName : Session.pm , ERROR: premature EOF in command execution.\n");
}
],
'-re', qr'[#$>:]\s?$', # wait for shell prompt, then exit expect
);
}
#############################################################
#############################################################################
sub _adapter
{
my ($adapter_name) = #_;
print "Adapter name: $adapter_name\n";
chomp($adapter_name);
switch($adapter_name){
case "AUSTIN" {$dev_id="e414571614102004"}
case "CX5" {$dev_id="b315191014103506"}
case "CX4" {$dev_id="b31513101410f704"}
case "CX4_EG10" {$dev_id="b315151014101f06"}
case "CX4_EG25" {$dev_id="b315151014101e06"}
case "CX3" {$dev_id="RoCE"}
case "CX2" {$dev_id="b315506714106104"}
case "CX3_PRO" {$dev_id="RoCE"}
case "CX3_PRO1" {$dev_id="b31507101410e704"}
case "HOUSTON_LR" {$dev_id="df1020e214104004"}
case "HOUSTON_SR" {$dev_id="df1020e214100f04"}
case "HOUSTON_Cu" {$dev_id="df1020e214103d04"}
case "SHINER_S" {$dev_id="e4148a1614109304"}
case "SHINER_T" {$dev_id="e4148e1614109204"}
case "SLATE_SR" {$dev_id="df1020e21410e304"}
case "SLATE_CU" {$dev_id="df1020e21410e404"}
case "EVERGLADES" {$dev_id="b315151014101e06"}
else { print "Adapter not in list\n"}
}
return $dev_id;
}
#######################################################################################
##########################################################
sub _run_cmd
{
my $output; my $output1;
my ($cmdStr) = #_;
$exp->send($cmdStr ."\r");
$exp->expect(21, '-re', $str);
$output = $exp->exp_before();
$exp->clear_accum();
my #PdAt_val = split("\r?\n", $output);
foreach my $line1 (#PdAt_val)
{
chomp($line1);
if ( $line1 =~ /(\(\d+\))(\s*root\s*\#\s*)/)
{
if ( $1 =~ /\((\d+)\)/)
{
if ($1 != 0)
{
print("*************** Command $cmdStr didn't ran sucessfully ***************\n");
exit;
}
}
}
}
return $output;
}
######################################################################
There are individual solutions for different systems. So some systems got from their god the must have highlevel restrictions. So the regular says, that you cant login as root directly. To step up the long way to the stage you can use sudo or su. I didnt see that mind in your lines.
# The simpliest way is to use what you have!
sub passwd
{
my $user = #_[0];
my $password = #_[1];
#
# as root
my $execline = qq~passwd $user:$password~;
#
# as root with second password
my $execline = qq~passwd $user:$password\n$password~;
#
# for microsoft certified ubuntu noobs, kidding mint's
my $execline = qq~sudo $password && passwd $user:$password~;
#
# for apple greyed, debian nerds, solaris freaks
my $execline = qq~su $password && passwd $user:$password~;
#
my $return = system("$execline");
}
print &passwd("root","the magical word");
#
# elseif read this.url([to get the higher experience][1]);
[1]: https://stackoverflow.com/questions/714915/using-the-passwd-command-from-within-a-shell-script
I'm a newb' on Perl, and try to do a simple script's launcher in Perl with Curses (Curses::UI)
On Stackoverflow I found a solution to print (in Perl) in real time the output of a Bash script.
But I can't do this with my Curses script, to write this output in a TextEditor field.
For example, the Perl script :
#!/usr/bin/perl -w
use strict;
use Curses::UI;
use Curses::Widgets;
use IO::Select;
my $cui = new Curses::UI( -color_support => 1 );
[...]
my $process_tracking = $container_middle_right->add(
"text", "TextEditor",
-readonly => 1,
-text => "",
);
sub launch_and_read()
{
my $s = IO::Select->new();
open my $fh, '-|', './test.sh';
$s->add($fh);
while (my #readers = $s->can_read()) {
for my $fh (#readers) {
if (eof $fh) {
$s->remove($fh);
next;
}
my $l = <$fh>;
$process_tracking->text( $l );
my $actual_text = $process_tracking->text() . "\n";
my $new_text = $actual_text . $l;
$process_tracking->text( $new_text );
$process_tracking->cursor_to_end();
}
}
}
[...]
$cui->mainloop();
This script contains a button to launch launch_and_read().
And the test.sh :
#!/bin/bash
for i in $( seq 1 5 )
do
sleep 1
echo "from $$ : $( date )"
done
The result is my application freeze while the bash script is executed, and the final output is wrote on my TextEditor field at the end.
Is there a solution to show in real time what's happened in the Shell script, without blocking the Perl script ?
Many thanks, and sorry if this question seems to be stupid :x
You can't block. Curses's loop needs to run to process events. So you must poll. select with a timeout of zero can be used to poll.
my $sel;
sub launch_child {
$sel = IO::Select->new();
open my $fh, '-|', './test.sh';
$sel->add($fh);
}
sub read_from_child {
if (my #readers = $sel->can_read(0)) {
for my $fh (#readers) {
my $rv = sysread($fh, my $buf, 64*1024);
if (!$rv) {
$sel->remove($fh);
close($fh);
next;
}
... add contents of $buf to the ui here ...
}
}
}
launch_child();
$cui->set_timer(read_from_child => \&read_from_child, 1);
$cui->mainloop();
Untested.
Note that I switched from readline (<>) to sysread since the former blocks until a newline is received. Using blocking calls like read or readline defies the point of using select. Furthermore, using buffering calls like read or readline can cause select to say nothing is waiting when there actually is. Never use read and readline with select.
I've been trying to write a script that filters packets out of a device and from a specific ip address over that device.
I want data to be like the output i get from wireshark when you select a specific device and you use the ip.src==xx.xx.xx.xx
my program so far is like this
#!/usr/bin/perl -w
my $interface='eth1';
sub process_pkt #Packet processing routine
{
my ($user_data,$header, $packet) = #_;
my $minipacket = substr($packet,0,54);
print ("\n## raw: ###\n");
print ($minipacket);
print ("\n==Byte# / Hex / Dec / Bin==\n");
for ($i=0;$i<55;$i++)
{
$hexval = unpack('H2',substr($packet,$i,1));
$decval = hex(unpack('H2',substr($packet,$i,1)));
printf ("%03s-%02s-%03s-%08b\n", $i, $hexval, $decval, $decval);
}
}
# ######################################################################
# Here we are invoking the NetPcap module and looping through forever.
Net::PcapUtils::loop(\&process_pkt,
SNAPLEN => 65536, #Size of data to get from packet
PROMISC => 1, #Put in promiscuous mode
FILTER => 'tcp', #only pass TCP packets
DEV => $interface, );
and I am getting output
now i want to filter out packets that are received on the eth1 device and from the soruce ip of xx.xx.xx.xx
can we use the filter option in Net::PcapUtils::loop to do that?
and then i want packets of data length xx
...
i tried going through the documentation in cpan.org
but all i find is the options available.. i couldn't find any examples..
can someone please help me out?
improvements:
can i use something like
FILTER => 'ip src xx.xx.xx.xx'
after the
FILTER => 'tcp'
line in the code?
and can i somehow include the data length of the packet so as to filter the packets of data length = 86?
Alternative program i am using to get the payload of the packet:
#!/usr/bin/perl -w
# #########################
#
use Net::PcapUtils;
use NetPacket::Ethernet qw(:strip);
use NetPacket::IP;
use NetPacket::TCP;
use NetPacket::IP qw(:strip);
my $interface= 'eth1';
my $snaplen= 65536;
my $filter='tcp';
my $promisc = 1;
my $timeout = 10000 ;
my $err;
sub process_pkt
{
my ($user_data,$header,$packet) = #_;
$ip= NetPacket::IP->decode(eth_strip($packet));
$tcp= NetPacket::TCP->decode($ip->{data});
$payload = $tcp->{data};
print ("payload: \n ".$payload." \n----end-----\n");
for($i=0;$i<55;$i++){
$hexval = unpack('H2',substr($payload,$i,1));
open (MYFILE, '>>perldata1.txt');
print MYFILE ($i." :hex: ". $hexval."\n");
close (MYFILE);
}
}
Net::PcapUtils::loop(\&process_pkt,
SNAPLEN => 65536,
PROMISC => 1,
FILTER => 'tcp',
FILTER => 'ip src 129.7.236.40',
DEV => $interface, );
but am still not able to figure out how to get the length of the data field. :(
Thanks.
#!/usr/bin/perl -w
# #########################
#
use Net::PcapUtils;
use NetPacket::Ethernet qw(:strip);
use NetPacket::IP;
use NetPacket::TCP;
use NetPacket::IP qw(:strip);
use strict;
use Data::Dumper;
#use warnings;
my $interface= 'eth1';
my $snaplen= 65536;
my $filter='tcp';
my $promisc = 1;
my $timeout = 10000 ;
my $err;
my #array;
sub process_pkt
{
my ($user_data,$header,$packet) = #_;
my $ip= NetPacket::IP->decode(eth_strip($packet));
my $tcp= NetPacket::TCP->decode($ip->{data});
my $payload = $tcp->{data};
if(length($payload)==32)
{
for(my $decode=0;$decode<32;$decode++)
{
$array[$decode] = unpack('H2',substr($payload,$decode,1));
}
my $length= scalar(#array);
open (MYFILE, '>doorstatus.tab');
if($array[22] eq '0c')
{
print MYFILE ( " Decision: Granted\n");
}
elsif($array[22] eq '04')
{
print MYFILE ("Decision: Denied\n");
}
elsif($array[22] eq '0d')
{
print MYFILE ("Decision: Locked\n");
}
else
{
print MYFILE ("Decision: unknown \n");
}
#print MYFILE ( " Data: \n".Dumper(\#array)." \n");
close (MYFILE);
}
}
Net::PcapUtils::loop(\&process_pkt,
SNAPLEN => 65536,
PROMISC => 1,
FILTER => 'tcp',
FILTER => 'ip src xx.xx.xx.xx',
DEV => $interface, );
The code filters the data coming from a specific source into an array and you can do any thing with it,
This is the code that I used to walk through the table in net:snmp using perl:
#! /usr/local/bin/perl
use strict;
use warnings;
use Net::SNMP qw(:snmp);
my $OID_hrSystem = '1.3.6.1.2.1.25.1';
my $OID_ifPhysAddress = '1.3.6.1.2.1.2.2.1.6';
my ($session, $error) = Net::SNMP->session(
-hostname => shift || 'localhost',
-community => shift || 'public',
-nonblocking => 1,
-translate => [-octetstring => 0],
-version => 'snmpv2c',
);
if (!defined $session) {
printf "ERROR: %s.\n", $error;
exit 1;
}
my %table; # Hash to store the results
my $result = $session->get_bulk_request(
-varbindlist => [ $OID_hrSystem ],
-callback => [ \&table_callback, \%table ],
-maxrepetitions => 10,
);
if (!defined $result) {
printf "ERROR: %s\n", $session->error();
$session->close();
exit 1;
}
# Now initiate the SNMP message exchange.
snmp_dispatcher();
$session->close();
# Print the results, specifically formatting ifPhysAddress.
for my $oid (oid_lex_sort(keys %table)) {
if (!oid_base_match($OID_ifPhysAddress, $oid)) {
printf "%s = %s\n", $oid, $table{$oid};
} else {
printf "%s = %s\n", $oid, unpack 'H*', $table{$oid};
}
}
exit 0;
sub table_callback
{
my ($session, $table) = #_;
my $list = $session->var_bind_list();
if (!defined $list) {
printf "ERROR: %s\n", $session->error();
return;
}
# Loop through each of the OIDs in the response and assign
# the key/value pairs to the reference that was passed with
# the callback. Make sure that we are still in the table
# before assigning the key/values.
my #names = $session->var_bind_names();
my $next = undef;
while (#names) {
$next = shift #names;
if (!oid_base_match($OID_hrSystem, $next)) {
return; # Table is done. chakri
}
$table->{$next} = $list->{$next};
}
# Table is not done, send another request, starting at the last
# OBJECT IDENTIFIER in the response. No need to include the
# calback argument, the same callback that was specified for the
# original request will be used.
my $result = $session->get_bulk_request(
-varbindlist => [ $next ],
-maxrepetitions => 10,
);
if (!defined $result) {
printf "ERROR: %s.\n", $session->error();
}
return;
}
Output is:
1.3.6.1.2.1.25.1.1.0 = 1 hour, 12:00.77
1.3.6.1.2.1.25.1.2.0 = �
+
1.3.6.1.2.1.25.1.3.0 = 1536
1.3.6.1.2.1.25.1.4.0 = BOOT_IMAGE=/boot/vmlinuz-3.0.0-14-generic root=UUID=5c4c8d22-3cea-4410-aaad-f297c75d217e ro quiet splash vt.handoff=7
1.3.6.1.2.1.25.1.5.0 = 1
1.3.6.1.2.1.25.1.6.0 = 133
1.3.6.1.2.1.25.1.7.0 = 0
But the required output for me is as follows:
hrSystemUptime.0 = 1:08:54.36
hrSystemDate.0 = 2011-12-14,16:0:2.0,+1:0
hrSystemInitialLoadDevice.0 = 1536
hrSystemInitialLoadParameters.0 = "BOOT_IMAGE=/boot/vmlinuz-3.0.0-14-generic root=UUID=5c4c8d22-3cea-4410-aaad-f297c75d217e ro quiet splash vt.handoff=7"
hrSystemNumUsers.0 = 1
hrSystemProcesses.0 = 133
hrSystemMaxProcesses.0 = 0
The main thing in the output is I want mib names to be printed in the output instead of the mib values
You could use the SNMP module (available on Ubuntu as libsnmp-perl) which offers a tied hash to loaded MIBs, %SNMP::MIB. Here's some example code:
use SNMP;
SNMP::initMib();
print "$SNMP::MIB{'1.3.6.1.2.1.25.1.1.0'}{label} = \n";
#Should print "hrSystemUptime = "
Because %SNMP::MIB is a tied hash, you can't just do a lookup and assign to a lexical variable, i.e. my $oid = $SNMP::MIB{$oidstr}. You have to access it directly every time.
There is lots of other information that it loads from the MIB, including data type, which could help with the issue it looks like you have with hrSystemDate. Also, see the man page for mib_api if you need to load specific MIBs. The ones you used in your example loaded by default on my system, though.
have you tried the snmpget command on your server? When I run snmpget direcly on CLI, the result cames with the name:
Ex: /usr/local/bin/snmpget -O Q -v 2c -c Community x.x.x.x .1.3.6.1.2.1.31.1.1.1.6.100663301
IF-MIB::ifHCInOctets.100663301 = 152528664859348
If it works for you, you might want to exectute the command in the PERL code, instead of using the LIB. Then you just have to handle with the output.
Also, tou can use snmptranslate to tranlate your OIDs:
Ex: /usr/local/bin/snmptranslate 1.3.6.1.2.1.25.1.1
HOST-RESOURCES-MIB::hrSystemUptime
More Info -> http://www.net-snmp.org/wiki/index.php/TUT:snmptranslate
EDIT
Why don't you:
my $pathSnmpTranslate = '/your/path/to/snmptranslate';
for my $oid (oid_lex_sort(keys %table)) {
my $oidTrans = `$pathSnmpTranslate $oid`;
if (!oid_base_match($OID_ifPhysAddress, $oid)) {
printf "%s = %s\n", $oidTrans, $table{$oid};
} else {
printf "%s = %s\n", $oidTrans, unpack 'H*',$table{$oid};
}
}
On my machine it worked:
> /xxx % /usr/local/bin/snmptranslate 1.3.6.1.2.1.25.1.1
HOST-RESOURCES-MIB::hrSystemUptime
> /xxx % /usr/local/bin/snmptranslate 1.3.6.1.2.1.25.1.1.0
HOST-RESOURCES-MIB::hrSystemUptime.0