Perl / Net::SNMP : script too slow, need to optimize - perl

I would like to optimize my perl script because it is a bit slow for displaying informations about the network.
I don't know what can be changed or ameliorated to boost the script execution.
I manipulate several hashes, to get : mac add, index, etc... I think it's a bit heavy, but no other choice.
Moreover, I do a lot of SNMP request and the handling of errors is maybe not great.
I copy/paste my script and its module.
Thanks in advance for reading my code.
It takes in args :
interface name (ex. FastEthernet0/9 or FastEthernet0/1...)
hostname : ip of the switch
community (often =public)
Hope this is comprehensible.
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long;
use SnmpUtil;
use AdresseMac;
use Net::SNMP;
use Net::SNMP::Interfaces;
my $ifname;
my $hostname;
my $community;
my $version = 1;
GetOptions( "ifname=s" => \$ifname,
"host=s" => \$hostname,
"community=s" => \$community,
"protocol:s" => \$version);
my $interfaces = Net::SNMP::Interfaces->new(Hostname => $hostname, Community => $community);
my $inter = $interfaces->interface($ifname);
#Get interface $ifname
my $ifindex = $inter->index();
#Vitesse
my $vitesse = $inter->ifHighSpeed();
#Alias
my $ifalias = $inter->ifAlias();
#Seek for VLANs
my $vlan_trouve;
#Listing all VLANS
my $vmVlan = "1.3.6.1.4.1.9.9.68.1.2.2.1.2"; #OID of vlan table
my $vlans = SnmpUtil->new($hostname, $community);
my %vl = $vlans->requeteTable($vmVlan);
$vlans->deconnexion();
#Get the good VLAN corresponding to index interface
$vlan_trouve = $vl{$ifindex};
#Listing : port VLAN <-> #mac
my $dot1dTpFdbAddress = "1.3.6.1.2.1.17.4.3.1.1";
my $dot = SnmpUtil->new($hostname, $community."#".$vlan_trouve);
my %dot1address = $dot->requeteTable($dot1dTpFdbAddress);
#Listing : numPortBridge <-> port VLAN
my $dot1dTpFdbPort = "1.3.6.1.2.1.17.4.3.1.2";
my %portdot = reverse($dot->requeteTable($dot1dTpFdbPort));
#Listing : num Port bridge <-> ID port switch
my $dot1dBasePortIfIndex = "1.3.6.1.2.1.17.1.4.1.2";
my %dotindex = reverse($dot->requeteTable($dot1dBasePortIfIndex));
#Duplex (auto, half or full)
my $oid_cisco_duplex = "1.3.6.1.2.1.10.7.2.1.19.".$ifindex;
my $duplex = $dot->requete($oid_cisco_duplex);
if ($duplex==1) {
$duplex= "Auto";
}
elsif ($duplex==2) {
$duplex = "Half";
}
elsif ($duplex==3) {
$duplex= "Full";
}
#Close connection
$dot->deconnexion();
#Go back up, to find mac add
my $numportbridge = $dotindex{$ifindex};
if (!defined($numportbridge)) {
print "Erreur : $ifindex not found in list : num Port bridge <-> ID port switch\n";
exit 2;
}
my $portVlan = $portdot{$numportbridge};
if (!defined($portVlan)) {
print "Erreur : $numportbridge not found in list : numPortBridge <-> ports du VLAN\n";
exit 3;
}
my $add = uc($dot1address{$portVlan});
if (!defined($add)) {
print "Erreur : $portVlan not found in list : ports du VLAN <-> \#mac\n";
exit 4;
}
$add =~ s/^0X//g;
printf "<b>Port : $ifname</b><br/>Index $ifindex on VLAN : $vlan_trouve<br/>\#mac : $add<br/>Speed=$vitesse Mbps Alias=$ifalias<br/>Duplex: $duplex\n";
Here's SnmpUtil.pm :
#!/usr/bin/perl
use strict;
use warnings;
use Net::SNMP;
package SnmpUtil;
our ($session, $error);
sub new {
my ($classe, $hostname, $community) = #_;
my $this = {
"hostname" => $hostname,
"community" => $community
};
bless($this, $classe);
$this->{connexion} = $this->connexion;
return $this;
}
sub connexion {
my ($this) = #_;
($session, $error) = Net::SNMP->session(
-hostname => $this->{hostname},
-community => $this->{community},
-version => "1",
-timeout => 3,
);
request_error_connexion() if (!defined($session));
}
sub request_error_connexion {
my ($this) = #_;
print "Erreur : can't connect to host\n";
print "Erreur : $error\n";
if ($error =~ /The argument "-community" is unknown/)
{
# protocol SNMP version 3 not working
exit 3; # code ret final = 3*256 = 768
}
else
{
exit 1; # code retour final = 1*256 = 256
}
}
sub request_error {
my ($this) = #_;
print "Error : no answer from host\n";
printf "Erreur : %s\n",$session->error;
if ($session->error =~ /No response from remote host/)
{
#host ok, bad community or host refuse connection
$session->close;
exit 2; # code retour final = 2*256 = 512
}
else
{
#can not find table
$session->close;
exit 4; # code retour final = 4*256 = 1024
}
}
sub requeteTable {
my ($this, $oid) = #_;
my $result = $session->get_table( -baseoid => $oid );
request_error() if (!defined($result));
my %tab = ();
foreach my $i (Net::SNMP::oid_lex_sort(keys %{$result})) {
my $index = $i;
$index =~ s/$oid.//;
$tab{ $index } = $result->{$i};
#print $index."--".$result->{$i}."\n";
}
return %tab;
}
sub requete {
my ($this, $oid) = #_;
my $result = $session->get_request($oid);
request_error() if (!defined($result));
return $result->{$oid};
}
sub deconnexion {
my ($this) = #_;
$session->close();
}
1;
AdresseMac.pm module is useless, it's just to convert dec to hex & vice-versa.
Thanks for your help,
big reward for the one who find optimization ;)
PS: forgot to say, I work on cisco switch 2960.

You may not like this answer, but one of the reasons that Net-SNMP supports a perl module (called just SNMP) written using C-bindings rather than the all-in-perl module implementation done in Net::SNMP is that the C-bindings are significantly faster. Giovanni Marzot, who wrote the initial implementation of the Net-SNMP C-binding binding, measured the C/perl-binding implementation to be up to 10 times faster than the all-perl version. And if you starting getting into the authenticated/encrypted SNMPv3 then it gets even faster. I don't know if this is the source of your problems, however. Just a data point. A perl profiler would really let you know.
Another point to consider: if you're querying lots of hosts, think about architecting your code so that you can send multiple queries out at a time using asynchronous requests and using GetBulk requests using SNMPv2c as well. These two optimizations will greatly increase the speed as well.
Updated with links per request:
Net-SNMP: http://www.net-snmp.org/ and download: http://www.net-snmp.org/download.html .
The net-snmp toolkit comes with it's perl module. Configure Net-SNMP using --with-perl-modules
Net-SNMP's perl FAQ: http://www.net-snmp.org/wiki/index.php/FAQ:Perl
A mildly out of date man page: http://metacpan.org/pod/SNMP
Note that Net-SNMP has a gettable() function you may be interested in that does lots of optimizations.

Related

My code to change the password from remote server is not working

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

Perl SNMP trap generator for scale testing?

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.

Perls File::VirusScan using Daemon::ClamAV::Clamd says did not get PING response from clamd

First let me state, clamd has been proven to respond correctly:
$ echo PING | nc -U /var/run/clamav/clamd.sock
PONG
the scanner was setup as follows:
#set up a Clamav scanner
use File::VirusScan;
use File::VirusScan::ResultSet;
my $scanner = File::VirusScan->new({
engines => {
'-Daemon::ClamAV::Clamd' => {
socket_name => '/var/run/clamav/clamd.sock',
},
},
});
and the whole script works fine on a Solaris 11 box. I'm running this on a Linux CentOS 5.3 (Final) I did have a problem installing File::VirusScan from CPAN, the latest version 0.102 won't compile and CPAN testers seems to confirm this as 435 fails out of 437. So I downloaded the prev 0.101 version from CPAN, the version I'm also running in Solaris and manually installed apparently ok
perl -v
This is perl, v5.8.8 built for x86_64-linux-thread-multi
sub scanner {
$|++; # buffer disabled
(my $path, my $logClean) = #_;
my $recurse = 5;
print color "yellow";
print "[i] Building file scan queue - recurse deepth $recurse \n";
print color "green";
print "SCAN QUEUE:0";
#Get list of files
if( $rootPath){
use File::Find::Rule;
my $finder = File::Find::Rule->maxdepth($recurse)->file->relative->start("$$path");
while( my $file = $finder->match() ){
$|++;
#$file = substr($file,length($rootPath)); #remove path bloat
push(#scanList,"/$file");
print "\rSCAN QUEUE:" .scalar(#scanList); #update screen
}
}else{
push(#scanList,"$$path");
}
print "\rSCANING:0";
#set up a Clamav scanner
use File::VirusScan;
use File::VirusScan::ResultSet;
my $scanner = File::VirusScan->new({
engines => {
'-Daemon::ClamAV::Clamd' => {
socket_name => '/var/run/clamav/clamd.sock',
},
},
});
#scan each file
my $scanning = 0;
my $complete = -1;
foreach $scanFile (#scanList){
$scanning++;
##################################################
#scan this file
$results = $scanner->scan($rootPath.$scanFile);
##################################################
#array of hashes
my $centDone = int(($scanning/scalar(#scanList))*100);
if($centDone > $complete){
$complete = $centDone;
}
if($centDone < 100){
#\r to clear/update line
$format = "%-9s %-60s %-15s %-5s";
printf $format, ("\rSCANING:", substr($scanFile,-50), "$scanning/".scalar(#scanList), "$centDone%");
}else{
print "\rSCAN COMPLETE ";
}
# array ref
foreach $result (#$results) {
#array of pointers to hashes
#print 'data:'
#print 'state:'
if($$result{state} ne "clean"){
if($$result{data} =~ /^Clamd returned error: 2/){
$$result{data} = "File too big to scan";
}
push(#scanResults,[$scanFile,$$result{state},$$result{data}]); # results
}elsif($$logClean){
push(#scanResults,[$scanFile,$$result{state},$$result{data}]);
}
unless($$result{state} eq "clean"){
print color "red";
print "\r$scanFile,$$result{state},$$result{data}\n";
print color "green";
print "\rSCANING: $scanning/".scalar(#scanList)." : $centDone%";
if($$result{state} eq "virus"){
push(#scanVirus,scalar(#scanResults)-1); #scanResuts index of virus
}elsif($$result{state} eq "error"){
push(#scanError,scalar(#scanResults)-1); #scanResuts index of Error
}
}
}
} print "\n";
}
Looking at the source code for the Clamd package the following script should approximate the call it is attempting and will hopefully give you a better idea of how it's failing. Try saving it to a separate file (like test.pl) and run it using "perl test.pl":
use IO::Socket::UNIX;
use IO::Select;
my $socket_name = '/var/run/clamav/clamd.sock';
my $sock = IO::Socket::UNIX->new(Peer => $socket_name);
if(!defined($sock)) {
die("Couldn't create socket for path $socket_name");
}
my $s = IO::Select->new($sock);
if(!$s->can_write(5)) {
$sock->close;
die("Timeout waiting to write PING to clamd daemon at $socket_name");
}
if(!$sock->print("SESSION\nPING\n")) {
$sock->close;
die('Could not ping clamd');
}
if(!$sock->flush) {
$sock->close;
die('Could not flush clamd socket');
}
if(!$s->can_read($self->{5})) {
$sock->close;
die("Timeout reading from clamd daemon at $socket_name");
}
my $ping_response;
if(!$sock->sysread($ping_response, 256)) {
$sock->close;
die('Did not get ping response from clamd');
}
if(!defined $ping_response || $ping_response ne "PONG\n") {
$sock->close;
die("Unexpected response from clamd: $ping_response");
}
It looks like the various antivirus engines need to be installed separately from the File::VirusScan base library. Does the following return an error?
perl -mFile::VirusScan::Engine::Daemon::ClamAV::Clamd -e ''
If it displays an error that it can't locate Clamd.pm, you need to install that engine module.
If it doesn't display an error, you'll need to post more details, such as the code you're actually using to perform the scan and/or the error output (if any).

mib name printing from mib values in perl

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

Perl Irssi scripting: How to send msg to a specific channel?

I need to establish this single task with Irssi Perl script. I have my own channel and I want to sent msg directly to that channel in certain scenarios.
My experience with Perl is quite limited so I haven't got this one. I am confused how to manage different chatnets and channels in Irssi Perl scripting. So how I can send message for example channel #testchan#Quakenet for example?
Test one:
server->command("^MSG $info{'#testchan'} $info{'Test message.'}");
Test two (tuto about scripting):
sub away_describe_pub_channels {
my($net, $channel) = #_;
my ($text) = #_;
my $c = Irssi::server_find_chatnet("QuakeNet")->channel_find("testchan");
$c->command("DESCRIBE $channel $text")
}
here is an example is used for a bot :)
#==========================BEGINNING OF PARMS======================================
#name of the channels where this feature will be used
my #channels = ("foo","bar");
#the public commands
#help
my $cmd_help = '!help';
#new ticket
my $cmd_newticket = "!stack";
my %url_newticket = ( 'foo'=>{url=>"http://stackoverflow.com/questions/ask"},
'bar'=>{url=>"http://https://github.com/repo/project/issues/new"}
sub bootstrap {
my ($server, $msg, $nick, $address, $target) = #_;
#lowercase of the channel name in case this one will be registered in camelCase ;)
$target = lc $target;
foreach my $channel (#channels) {
if ( $target eq "#".$channel) {
#split the line first peace the command second the rest
my ($cmd,$line) = split / /,$msg,2;
if ($cmd =~ $cmd_help) {
$server->command("MSG ". $nick ." Here are the available commands : !stack");
} elsif ($cmd eq $cmd_newticket) {
my $h = $url_newticket{$channel};
$server->command("MSG $target submit an issue/a ticket $h->{'url'}");
}
}
}
}
#let's add the sub as a signal and let's play
Irssi::signal_add_last('message public', 'bootstrap');
Hope this could help