Monday, March 04, 2013

Use perl to check spamhaus status in Nagios

We had an issue where something on our internal network was tripping a SMTP spam filter at spamhaus.org.  We thought we fixed it once only to be bitten again a few months later and payslips from our payrol system were bouncing (bad).  As well as actually investigating the root cause, we created a nagios check to check spamhaus programatically.  Creating a custom nagios check is well documented on the nagios website.

#!/usr/bin/perl
#
# Quick perl script to check spamhaus to see if we're blocked again, see https://rt.wilderness.org.au:444/rt/Ticket/Display.html?id=73259
#
# This script returns values consistent with the nagios return code specification at http://nagiosplug.sourceforge.net/developer-guidelines.html#AEN76
# 0     OK          The plugin was able to check the service and it appeared to be functioning properly
# 1     Warning     The plugin was able to check the service, but it appeared to be above some "warning" threshold or did not appear to be working properly
# 2     Critical    The plugin detected that either the service was not running or it was above some "critical" threshold
# 3     Unknown     Invalid command line arguments were supplied to the plugin or low-level failures internal to the plugin 
#                       (such as unable to fork, or open a tcp socket) that prevent it from performing the specified operation. Higher-level errors 
#                       (such as name resolution errors, socket timeouts, etc) are outside of the control of plugins and should generally NOT be reported as UNKNOWN states.

use strict;
my $our_external_ip = "xxx.xxx.xxx.xxx"; 
my $exit_value=3;

# run the wget command and save it's output to the $results variable.
my $results=`/usr/bin/wget --random-wait -U mozilla -O /tmp/spamcheck.dat -o /tmp/spamcheck.log http://www.spamhaus.org/query/ip/$our_external_ip && grep $our_external_ip /tmp/spamcheck.dat`; 
chomp($results); 
#print $results."\n";

# check to see if we score RED ie; we're on a blocklist
if ($results =~ m/red/) {
    print "ALERT: Block found.  Check http://www.spamhaus.org/query/ip/$our_external_ip\n";
    $exit_value=2;
} 

# if we got this far, we saw no RED.  Check to see we at least get one GREEN.
elsif ($results =~ m/green/) {
    print "OK; We got a green and no red.\n";
    $exit_value=0; 
} 

# ALERT: We got no red AND no green; therefore there bust be some issue somewhere!
else {
    print "ALERT: No valid return codes detected; page-load/dns/internet/scripting issue?\n";
    $exit_value=3; 
}

#print "\nPerl hopes it's returning a \$exit_value of $exit_value\n\n";
exit $exit_value;

note that /tmp/spamcheck.* will need to be globally writable.

That then results in a nice web gui telling us all isn't well (again).  Happy with my work i told my boss who said "i don't like it, i want it to say OK", to which i replied, "i can do that ;)", and now you can too.  Happy automation :)




No comments: