Nagios plugin check_logfiles postscript option cannot execute a postscript - perl

I'm working with a Nagios plugin called check_logfiles. a pretty powerful script. I have it working on Unix/Linux and Windows. well, all but 1 feature. the ability to execute a post or pre script hook.
I just can't get a postscript to execute from the check_logfiles.cfg.
I get from check_logfiles protocol file
WARNING Errors in postscript (tag postscript)
cannot execute custom_mail_alert.pl
I tried running it with the -d trace option - no success gettng debug output. ?
I've tried several different implementations seen in config file below. Any help with understanding why a postscript cannot execute in check_logfies I really appreciate it much, thank you.
note: the script check_logfiles executes successfully even if postscript fails - this is OK and Good.
thank you for your help, I'm pulling my hair out :) I can't seem to figure it out.
check_logfiles works
custom_mail_alert.pl works on command line, but not as called from check_logfiles ?
The check_logfiles.cfg:
$scriptpath = 'C:\Program Files (x86)\Nagios\NCPA\contrib';
$protocolsdir = 'C:\Program Files (x86)\Nagios\NCPA\protocols';
$seekfilesdir = 'C:\Program Files (x86)\Nagios\NCPA\seek';
$MACROS = {
LOGS_DIR => 'C:\APMConnect\Logs',
PP_INGESTION_EP => 'C:\APMConnect\AutoDataLoader\Scandir\ManageAPM',
SRC_DIR => '\\win.alphper031.corporate.com\APM_Data_Storage\Zip File Archive',
CL_CMAIL_SMTP_HOST => 'mail.ad.com',
CL_CMAIL_TO => 'gary.l.mills#corp.com',
CL_CMAIL_FROM => 'ALPCTS000000881#alpcts000000881.corp.com',
CL_CMAIL_SUBJECT => 'APM Loader - Upload Failure Notification'
};
#$postscript = 'C:\Program Files (x86)\Nagios\NCPA\contrib\custom_mail_alert.pl';
#$postscript = 'perl custom_mail_alert.pl';
$postscript = 'custom_mail_alert.pl';
$postscriptparams = '-Host $CL_CMAIL_SMTP_HOST$ -To $CL_CMAIL_TO$ -From $CL_CMAIL_FROM$ -Subject "$CL_CMAIL_SUBJECT$" -Body "The APM Loader Upload Failed.\n Please see attached." -Attachment "C:\Program Files (x86)\Nagios\NCPA\seek\check_logfiles.C__APMConnect_Logs_AutoLoader.log.504 Gateway Time-Out" -Send_if_rc_gt $CL_SERVICESTATEID$';
#$postscriptstdin = '$CL_HOSTNAME$\t$CL_SERVICEDESC$\t$CL_SERVICESTATEID$\t$CL_SERVICEOUTPUT$\n';
#searches = (
{
tag => '504 Gateway Time-Out',
logfile => '$LOGS_DIR$\AutoLoader.log',
rotation => 'AutoLoader.log.\d{1,2}',
type => 'rotating',
criticalpatterns => [
'^java.lang.Exception:Method failed: HTTP/1.1 504 Gateway Time-out Please check configuration details and replace or update the file :.*'],
options => 'protocol,perfdata,script,supersmartscript',
script => sub {
use File::Copy;
my $cmd = 'net use E: /delete /y';
my $other_cmd = 'net use E: \\\\win.alphper031.corporate.com\\APM_Data_Storage /USER:logon.ds.com\\lg4274sv xnEDs7UMh3gT /PERSISTENT:YES';
my $other_status = system($other_cmd);
my $_source_dir = $ENV{CHECK_LOGFILES_SRC_DIR};
my $_target_dir = $ENV{CHECK_LOGFILES_PP_INGESTION_EP};
my $sout = $ENV{CHECK_LOGFILES_SERVICEOUTPUT};
my $result = rindex($sout, 'FaultData');
my $_file_name = substr($sout, $result, length($sout));
opendir (dir, $_source_dir);
if( -f "$_source_dir/$_file_name" ) {
copy ("$_source_dir\\$_file_name", "$_target_dir\\$_file_name");
if ( $? ) {
printf 'OK - File Copy Successful!';
printf " Copied File to Refeed APM: $_source_dir\\$_file_name";
return 0;
} else {
printf 'CRITICAL - File Copy Failed!';
printf " - Source dir: $_source_dir\\$_file_name";
return 2;
}
} else {
printf 'CRITICAL - File Copy Failed, File CANNOT be located! Resource may not be Mounted!';
printf " - Source dir: $_source_dir\\$_file_name";
return 2;
}
closedir($dir);
}});
The custom_mail_alert.pl script:
! C:\strawberry\perl\bin\perl -w
use strict;
use warnings;
use Getopt::Long;
my $Host;
my $To;
my $From;
my $Subject;
my $Body;
my $Attachment;
my $Send_if_rc_gt;
GetOptions(
"Host=s" => \$Host,
"To=s" => \$To,
"From=s" => \$From,
"Subject=s" => \$Subject,
"Body=s" => \$Body,
"Attachment=s" => \$Attachment,
"Send_if_rc_gt=i" => \$Send_if_rc_gt
);
printf "host:$Host\n";
printf "to:$To\n";
printf "from:$From\n";
printf "subject:$Subject\n";
printf "body:$Body\n";
printf "attachment:$Attachment\n";
printf "send_if_rc_gt:$Send_if_rc_gt\n";
my #cmd = ('C:\Program Files (x86)\Nagios\NCPA\contrib\cmail.exe');
push #cmd, "-host:$Host";
push #cmd, "-to:$To";
push #cmd, "-from:$From";
push #cmd, "-subject:$Subject";
push #cmd, "-body:$Body";
push #cmd, "-a:$Attachment";
printf "#cmd\n";
if (!defined $Host||!defined $To||!defined $From||!defined $Subject ||!defined $Body){
print "Usage: $0 -Host <host> -To <to> -From <from> -Subject <subject> -Body <mail body=""> -Attachment [--send-if-rc-gt <1-9> ]\n";
exit (-1);
}
require $Attachment;</mail></subject></from></to></host>
if ((defined $state->{'servicestateid'} && defined $Send_if_rc_gt) && ($state->{'servicestateid'} > $Send_if_rc_gt)){
print "$state->{'servicestateid'} was lower than $send_if_rc_gt\n";
exit 0;
}
if ($state->{'serviceoutput'}){
system(#cmd);
}

Related

[ Undefined subroutine]: Net::Frame::Dump::Online: Must be EUID 0

I am new using Perl language, and I am following a book to begin with some advanced scanning network (as that's why I am learning Perl for)
so the program looks like that:
#!/usr/bin/perl -w
use strict;
use Net::Pcap qw( :functions );
use Net::Frame::Device;
use Net::Netmask;
use Net::Frame::Dump::Online;
use Net::ARP;
use Net::Frame::Simple;
my $err = "";
my $dev = pcap_lookupdev(\$err); # from Net::Pcap
my $devProp = Net::Frame::Device->new(dev => $dev);
my $ip = $devProp->ip;
my $gateway = $devProp->gatewayIp;
my $netmask = new Net::Netmask($devProp->subnet);
my $mac = $devProp->mac;
my $netblock = $ip . ":" . $netmask->mask();
my $filterStr = "arp and dst host ".$ip;
my $pcap = Net::Frame::Dump::Online->new(
dev => $dev,
filter => $filterStr,
promisc => 0,
unlinkOnStop => 1,
timeoutOnNext => 10 # waiting for ARP responses
);
$pcap->start;
print "Gateway IP: ",$gateway,"\n","Starting scan\n";
for my $ipts ($netmask->enumerate){
Net::ARP::send_packet(
$dev,
$ip,
$ipts,
$mac,
"ff:ff:ff:ff:ff:ff", # broadcast
"request");
}
until ($pcap->timeout){
if (my $next = $pcap->next){ # frame according to $filterStr
my $fref = Net::Frame::Simple->newFromDump($next);
# we don’t have to worry about the operation codes 1, or 2
# because of the $filterStr
print $fref->ref->{ARP}->srcIp," is alive\n";
}
}
END{ print "Exiting\n"; $pcap->stop; }
However, when I run ./script.pl I am getting this error:
Undefined subroutine &main::pcap_lookupdev called at ./scan_ARP.pl line 13.
Exiting
Can't call method "stop" on an undefined value at ./scan_ARP.pl line 48.
END failed--call queue aborted.
and as mentionned in the book, I can replace my $dev = pcap_lookupdev(\$err); directly with my $dev = "wlp0s20f3" (wlp0s20f3; is the name of my network interface), but when I do that, I get:
[-]: Net::Frame::Dump::Online: Must be EUID 0 (or equivalent) to open a device for live capture
Exiting
Can't kill a non-numeric process ID at /usr/share/perl5/Net/Frame/Dump/Online.pm line 363.
END failed--call queue aborted.
So I found out that to solve the problem, I have to run the script as a root.

using Net::LDAPs with Net::LDAP::Control::Paged

I'm trying to use Net::LDAPs with Net::LDAP::CONTROL::PAGED to return many records via a privlidged bind, but so far I have failed, miserably. I've used this Net::LDAPs extensively in the past, but I've never been able to find any documentation suggesting that it is compatible with Net::LDAP:Control::Paged. Everything I find is related to Net::LDAP.
The error message I get is: Undefined subroutine &main::process_entry called at /usr/local/share/perl/5.20.2/Net/LDAP/Search.pm line 55, line 755
Here is my code:
sub Ldap636{
my ($filter) = $_[0];
my $USERNAME = 'username';
my $PASSWORD = 'password';
my $LDAP_SERVER = 'directory.domain.edu';
my $LDAP_SSL_PORT = '636';
my $LDAP_BASE = 'ou=people,dc=domain,dc=edu';
my $userDN = "uid=$USERNAME,ou=identities,ou=special,dc=domain,dc=edu";
my $ldap = Net::LDAPS->new($LDAP_SERVER, port => $LDAP_SSL_PORT) or die "Could not create LDAP object because:\n$!";
my $ldapMsg = $ldap->bind($userDN, password => $PASSWORD);
die $ldapMsg->error if $ldapMsg->is_error;
my $page = Net::LDAP::Control::Paged->new( size => 100 );
#args = (base => "$LDAP_BASE",
callback => \&process_entry,
filter => $filter,
control => [ $page ],
);
my $cookie;
while (1) {
my $result = $ldap->search(#args);
"LDAP error: server says ",$result->error,"\n" if $result->code;
foreach my $entry ($result->entries ) {
my $cn = $entry->get_value('cn');
my $desc = $entry->get_value('description');
print "$cn - $desc\n";
}
# Get cookie from paged control
my($resp) = $result->control( LDAP_CONTROL_PAGED ) or last;
$cookie = $resp->cookie or last;
$page->cookie($cookie);
}
$ldap->unbind;
}
The error message I get is: Undefined subroutine &main::process_entry
called at /usr/local/share/perl/5.20.2/Net/LDAP/Search.pm line 55,
line 755
You have written process_entry as a callback but you didn't write that subroutine. That's why you are getting the above error.

Perl: Unable to check validity of hostname for Net::Appliance::Session

When I tried to pass an invalid hostname, the code will get into an infinite loop.
my $s = Net::Appliance::Session->new({
personality => 'ios',
transport => 'SSH',
host => $ip
});
Is there a way to overcome this bug?
EDIT:
Here's my full code:
I use the subroutine to download the config file of my network device. When I pass in an invalid IP address in download_config, it will get into an infinite loop.
sub download_config
{
my ($ip) = #_;
my $s = Net::Appliance::Session->new({
personality => 'ios',
transport => 'SSH',
host => $ip,
Timeout => 1
});
$s->set_global_log_at('debug'); # maximum debugging
eval {
$s->connect({ username => $username, password => $password });
$s->begin_privileged({ password => $enable_password });
#get hostname to set the file name
$hostname_result = $s->cmd('sh run | inc hostname');
$hostname_result =~ m/hostname (.*)/;
$hostname = $1;
#download the file
my #running_config = $s->cmd('sh run');
#running_config = #running_config[ 2 .. (#running_config -1)];#remove header and footer of the file
open(FH, "> temp/".$hostname.".txt") or die("Cannot open config file : $!");
print FH #running_config;
close FH;
$s->end_privileged;
};
if ($#) {
#when the login details are wrong
print redirect('../../na/unauthorised.html');
}
$s->close;
}
The developer has fixed the bug.
Are you sure?
Are you tried this example code with your host name?
http://cpansearch.perl.org/src/OLIVER/Net-Appliance-Session-3.120560/examples/example-1.pl
If yes, you could create an RT ticket or you could try to contact the author.
I have chacked the code, and did not found anything (too) nasty.
Regards,

Perl SSH connection to execute telnet

I tried the following to access a router via a central admin server as "ssh hop" server
#!/usr/bin/perl -X
use strict;
use Net::OpenSSH;
use Net::Telnet;
my $lhost = "linuxserver";
my $luser = "linuxuser";
my $lpass = "linuxpassword";
my $chost = "routername";
my $cpass = "Routerpassword";
my $prompt = '/(?:Password: |[>])/m';
my #commands = ("show users\r");
my $ssh = Net::OpenSSH->new($lhost,
'user' => $luser,
'password' => $lpass,
'master_opts' => [ '-t' ],
#'async' => 1 # if enabled then password cannot be set here
);
my ($pty, $err, $pid) = $ssh->open2pty("telnet $chost");
my $t = new Net::Telnet(
-telnetmode => 0,
-fhopen => $pty,
-prompt => $prompt,
-cmd_remove_mode => 1,
-output_record_separator => "\r",
#-dump_log => "debug.log",
);
my $end = 0;
while (!$end) {
my ($pre, $post) = $t->waitfor($prompt);
if ($post =~ /Password: /m) {
# send password
$t->print("$cpass");
}
elsif ($post =~ /[>#]/ && #commands) {
my $cmd = shift(#commands);
if ($cmd !~ /[\r\n]/) {
$t->print($cmd);
}
else {
print $t->cmd($cmd);
}
}
else {
$end = 1;
$t->cmd("exit");
}
}
#close $pty;
$t->close();
Unfortunately I always get the following error:
read error: Input/output error at test.pl line 71
Can somebody help me please or is there a better solution only to test if a telnet connection via the "hop" server is possible or not?
The connection looks like:
workstation --ssh-> server --telnet-> router
Thanks in advance.
I think best option is to make an SSH-tunnel to your admin server and use it for telnetting to the router.
Getting Net::Telnet to work over Net::OpenSSH sometimes is not as easy as it should be and it requires some experimentation to get to the right combination of flags and calls that make it work.
For instance, instead of telneting to the target host, use netcat to open a raw connection (or Net::OpenSSH support for TCP forwarding if tunnels are allowed on the proxy).
Expect + Net::OpenSSH may be a better option.

How to post non-latin1 data to non-UTF8 site using perl?

I want to post russian text on a CP1251 site using LWP::UserAgent and get following results:
# $text="Русский текст"; obtained from command line
FIELD_NAME => $text # result: Г?в г'В?г'В?г'В?г?вєг?вёг?в? Г'В'Г?вчг?вєг'В?г'В'
$text=Encode::decode_utf8($text);
FIELD_NAME => $text # result: Р с?с?с?рєрёр? С'Рчрєс?с'
FIELD_NAME => Encode::encode("cp1251", $text) # result: Г?гіг+г+гЄгёгЏ ГІгҐгЄг+гІ
FIELD_NAME => URI::Escape::uri_escape_utf8($text) # result: D0%a0%d1%83%d1%81%d1%81%d0%ba%d0%b8%d0%b9%20%d1%82%d0%b5%d0%ba%d1%81%d1%82
How can I do this? Content-Type must be x-www-form-urlencoded. You can find similar form here, but there you can just escape any non-latin character using &#...; form, trying to escape it in FIELD_NAME results in 10561091108910891 10901077108210891 (every &, # and ; stripped out of the string) or 1056;усский текст (punctuation characters at the beginning of the string are stripped out) depending on what the FIELD_NAME actually is.
UPDATE: Anybody knows how to convert the following code so that it will use LWP::UserAgent::post function?
my $url=shift;
my $fields=shift;
my $request=HTTP::Request->new(POST => absURL($url));
$request->content_type('application/x-www-form-urlencoded');
$request->content_encoding("UTF-8");
$ua->prepare_request($request);
my $content="";
for my $k (keys %$fields) {
$content.="&" if($content ne "");
my $c=$fields->{$k};
eval {$c=Encode::decode_utf8($c)};
$c=Encode::encode("cp1251", $c, Encode::FB_HTMLCREF);
$content.="$k=".URI::Escape::uri_escape($c);
}
$request->content($content);
my $response=$ua->simple_request($request);
This code actually solves the problem, but I do not want to add the third request wrapper function (alongside with get and post).
One way around it appears to be (far from the best, I think) to use recode system command if you have it avialable. From http://const.deribin.com/files/SignChanger.pl.txt
my $boardEncoding="cp1251"; # encoding used by the board
$vals{'Post'} = `fortune $forunePath | recode utf8..$boardEncoding`;
$res = $ua->post($formURL,\%vals);
Another approach seems to be in http://mail2lj.nichego.net/lj.txt
my $formdata = $1 ;
my $hr = ljcomment_string2form($formdata) ;
my $req = new HTTP::Request('POST' => $ljcomment_action)
or die "new HTTP::Request(): $!\n" ;
$hr->{usertype} = 'user' ;
$hr->{encoding} = $mh->mime_attr('content-type.charset') ||
"cp1251" ;
$hr->{subject} = decode_mimewords($mh->get('Subject'));
$hr->{body} = $me->bodyhandle->as_string() ;
$req->content_type('application/x-www-form-urlencoded');
$req->content(href2string($hr)) ;
my $ljres = submit_request($req, "comment") ;
if ($ljres->{'success'} eq "OK") {
print STDERR "journal updated successfully\n" ;
} else {
print STDERR "error updating journal: $ljres->{errmsg}\n" ;
send_bounce($ljres->{errmsg}, $me, $mh->mime_attr("content-type.charset")) ;
}
Use WWW::Mechanize, it takes care of encoding (both character encoding and form encoding) automatically and does the right thing if a form element's accept-charset attribute is set appropriately. If it's missing, the form defaults to UTF-8 and thus needs correction. You seem to be in this situation. By the way, your example site's encoding is KOI8-R, not Windows-1251. Working example:
use utf8;
use WWW::Mechanize qw();
my $message = 'Русский текст';
my $mech = WWW::Mechanize->new(
cookie_jar => {},
agent => 'Mozilla/5.0 (X11; U; Linux x86_64; en-US) AppleWebKit/533.9 SUSE/6.0.401.0-2.1 (KHTML, like Gecko)',
);
$mech->get('http://zhurnal.lib.ru/cgi-bin/comment?COMMENT=/z/zyx/index_4-1');
$mech->current_form->accept_charset(scalar $mech->response->content_type_charset);
$mech->submit_form(with_fields => { TEXT => $message });
HTTP dump (essential parts only):
POST /cgi-bin/comment HTTP/1.1
Content-Length: 115
Content-Type: application/x-www-form-urlencoded
FILE=%2Fz%2Fzyx%2Findex_4-1&MSGID=&OPERATION=store_new&NAME=&EMAIL=&URL=&TEXT=%F2%D5%D3%D3%CB%C9%CA+%D4%C5%CB%D3%D
These functions solve the issue (first for posting application/x-www-form-urlencoded data and second for multipart/form-data):
#{{{2 postue
sub postue($$;$) {
my $url=shift;
my $fields=shift;
my $referer=shift;
if(defined $referer and $referer eq "" and defined $fields->{"DIR"}) {
$referer=absURL($url."?DIR=".$fields->{"DIR"}); }
else {
$referer=absURL($referer); }
my $request=HTTP::Request->new(POST => absURL($url));
$request->content_type('application/x-www-form-urlencoded');
$request->content_encoding("UTF-8");
$ua->prepare_request($request);
my $content="";
for my $k (keys %$fields) {
$content.="&" if($content ne "");
my $c=$fields->{$k};
if(not ref $c) {
$c=Encode::decode_utf8($c) unless Encode::is_utf8($c);
$c=Encode::encode("cp1251", $c, Encode::FB_HTMLCREF);
$c=URI::Escape::uri_escape($c);
}
elsif(ref $c eq "URI::URL") {
$c=$c->canonical();
$c=URI::Escape::uri_escape($c);
}
$content.="$k=$c";
}
$request->content($content);
$request->referer($referer) if(defined $referer);
my $i=0;
print STDERR "Doing POST request to url $url".
(($::o_verbose>2)?(" with fields:\n".
::YAML::dump($fields)):("\n"))
if($::o_verbose>1);
REQUEST:
my $response=$ua->simple_request($request);
$i++;
my $code=$response->code;
if($i<=$o_maxtries and 500<=$code and $code<600) {
print STDERR "Failed to request $url with code $code... retrying\n"
if($::o_verbose>2);
sleep $o_retryafter;
goto REQUEST;
}
return $response;
}
#{{{2 postfd
sub postfd($$;$) {
my $url=absURL(shift);
my $content=shift;
my $referer=shift;
$referer=absURL($referer) if(defined $referer);
my $i=0;
print STDERR "Doing POST request (form-data) to url $url".
(($::o_verbose>2)?(" with fields:\n".
::YAML::dump($content)):("\n"))
if($::o_verbose>1);
my $newcontent=[];
while(my ($f, $c)=splice #$content, 0, 2) {
if(not ref $c) {
$c=Encode::decode_utf8($c) unless Encode::is_utf8($c);
$c=Encode::encode("cp1251", $c, Encode::FB_HTMLCREF);
}
push #$newcontent, $f, $c;
}
POST:
my $response=$ua->post($url, $newcontent,
Content_type => "form-data",
((defined $referer)?(referer => $referer):()));
$i++;
my $code=$response->code;
if($i<=$o_maxtries and 500<=$code and $code<600) {
print STDERR "Failed to download $url with code $code... retrying\n"
if($::o_verbose>2);
sleep $o_retryafter;
goto POST;
}
return $response;
}