/usr/bin/sa-check_spamd is in spamassassin 3.4.1-3.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 | #!/usr/bin/perl -T -w
eval 'exec /usr/bin/perl -T -w -S $0 ${1+"$@"}'
if 0; # not running under some shell
#
# Inform the Nagios embedded perl interpreter that this script is
# incompatible. http://bugs.debian.org/598573
# nagios: -epn
#
########################################################################
#
# <@LICENSE>
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to you under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at:
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# </@LICENSE>
#
########################################################################
# Written by Daryl C. W. O'Shea, DOS Technologies <spamassassin@dostech.ca>
# See perldoc sa-check_spamd for program info.
use strict;
use warnings;
use re 'taint';
my $PREFIX = '/usr'; # substituted at 'make' time
my $DEF_RULES_DIR = '/usr/share/spamassassin'; # substituted at 'make' time
my $LOCAL_RULES_DIR = '/etc/spamassassin'; # substituted at 'make' time
my $LOCAL_STATE_DIR = '/var/lib/spamassassin'; # substituted at 'make' time
use lib '/usr/share/perl5'; # substituted at 'make' time
use Errno qw(EBADF);
use File::Spec;
use Config;
BEGIN { # see comments in "spamassassin.raw" for doco
my @bin = File::Spec->splitpath($0);
my $bin = ($bin[0] ? File::Spec->catpath(@bin[0..1]) : $bin[1])
|| File::Spec->curdir;
if (-e $bin.'/lib/Mail/SpamAssassin.pm'
|| !-e '/usr/share/perl5/Mail/SpamAssassin.pm' )
{
my $searchrelative;
if ($searchrelative && $bin eq '../' && -e '../blib/lib/Mail/SpamAssassin.pm')
{
unshift ( @INC, '../blib/lib' );
} else {
foreach ( qw(lib ../lib/site_perl
../lib/spamassassin ../share/spamassassin/lib))
{
my $dir = File::Spec->catdir( $bin, split ( '/', $_ ) );
if ( -f File::Spec->catfile( $dir, "Mail", "SpamAssassin.pm" ) )
{ unshift ( @INC, $dir ); last; }
}
}
}
}
use Getopt::Long;
use constant HAS_TIME_HIRES => eval { require Time::HiRes; };
use constant HAS_MSA_CLIENT => eval { require Mail::SpamAssassin::Client; };
use constant HAS_MSA_TIMEOUT => eval { require Mail::SpamAssassin::Timeout; };
use Mail::SpamAssassin::Util;
### nagios plugin return codes: 0 OK / 1 Warning / 2 Critical / 3 Unknown ###
use constant EX_OK => 0;
use constant EX_WARNING => 1;
use constant EX_CRITICAL => 2;
use constant EX_UNKNOWN => 3;
my $VERSION = $Mail::SpamAssassin::VERSION;
my %opt = (
'critical' => undef,
'hostname' => undef,
'port' => undef,
'socketpath' => undef,
'timeout' => 45,
'verbose' => undef,
'warning' => undef,
);
# Parse the command line
Getopt::Long::Configure("bundling");
GetOptions(
'critical|c=s' => \$opt{'critical'},
'help|h|?' => sub { print_usage_and_exit(); },
'hostname|H=s' => \$opt{'hostname'},
'port|p=s' => \$opt{'port'},
'socketpath=s' => \$opt{'socketpath'},
'timeout|t=s' => \$opt{'timeout'},
'verbose|v' => \$opt{'verbose'},
'version|V' => sub { print "sa-check_spamd version $VERSION\n"; exit EX_UNKNOWN; },
'warning|w=s' => \$opt{'warning'},
) or print_usage_and_exit();
if (defined $opt{'critical'}) {
if ($opt{'critical'} =~ /^(\d+(?:\.\d*)?)$/) {
$opt{'critical'} = $1;
} else {
print "SPAMD UNKNOWN: invalid critical config value provided\n";
exit EX_UNKNOWN;
}
}
if (defined $opt{'hostname'}) {
if ($opt{'hostname'} =~ /^([A-Za-z0-9_.:-]+)$/) {
$opt{'hostname'} = $1;
} else {
print "SPAMD UNKNOWN: invalid hostname config value provided\n";
exit EX_UNKNOWN;
}
}
if (defined $opt{'port'}) {
if ($opt{'port'} =~ /^(\d+)$/) {
$opt{'port'} = $1;
} else {
print "SPAMD UNKNOWN: invalid port config value provided\n";
exit EX_UNKNOWN;
}
}
# TODO: --socketpath isn't checked, suboptimal
if ($opt{'timeout'} =~ /^(\d+(?:\.\d*)?)$/ && $opt{'timeout'} >= 1) {
$opt{'timeout'} = $1;
} else {
print "SPAMD UNKNOWN: invalid timeout config value provided\n";
exit EX_UNKNOWN;
}
if (defined $opt{'warning'}) {
if ($opt{'warning'} =~ /^(\d+(?:\.\d*)?)$/) {
$opt{'warning'} = $1;
} else {
print "SPAMD UNKNOWN: invalid warning config value provided\n";
exit EX_UNKNOWN;
}
}
# logic checking
if (defined $opt{'critical'} && defined $opt{'warning'} &&
$opt{'critical'} < $opt{'warning'}) {
print "SPAMD UNKNOWN: critical value is less than warning value, config not valid\n";
exit EX_UNKNOWN;
}
if (defined $opt{'critical'} && defined $opt{'timeout'} &&
$opt{'critical'} > $opt{'timeout'}) {
print "SPAMD UNKNOWN: critical value is greater than timeout value, config not valid\n";
exit EX_UNKNOWN;
}
if (defined $opt{'warning'} && defined $opt{'timeout'} &&
$opt{'warning'} > $opt{'timeout'}) {
print "SPAMD UNKNOWN: warning value is greater than timeout value, config not valid\n";
exit EX_UNKNOWN;
}
# check to make sure that both TCP and UNIX domain socket info wasn't provided
if ((defined $opt{'hostname'} || defined $opt{'port'}) && defined $opt{'socketpath'}) {
print "SPAMD UNKNOWN: both TCP and UNIX domain socket info provided, only one can be used\n";
exit EX_UNKNOWN;
}
# if not provided with a spamd service to connect to set some defaults
unless (defined $opt{'socketpath'}) {
$opt{'hostname'} ||= 'localhost';
$opt{'port'} ||= 783;
}
if ($opt{'verbose'}) {
print ((HAS_MSA_CLIENT ? "loaded" : "failed to load") ." Mail::SpamAssassin::Client\n");
print ((HAS_MSA_TIMEOUT ? "loaded" : "failed to load") ." Mail::SpamAssassin::Timeout\n");
}
# If there's no client available, there's no way to check the service...
unless (HAS_MSA_CLIENT && HAS_MSA_TIMEOUT) {
# Nagios will only display the first line printed.
print "SPAMD UNKNOWN: could not load M:SA::Client\n" unless HAS_MSA_CLIENT;
print "SPAMD UNKNOWN: could not load M:SA::Timeout\n" unless HAS_MSA_TIMEOUT;
print "cannot continue\n" if $opt{'verbose'};
exit EX_UNKNOWN;
}
# untaint the command-line args; since the root user supplied these, and
# we're not a setuid script, we trust them. This needs to be called explicitly
foreach my $optkey (keys %opt) {
next if ref $opt{$optkey};
Mail::SpamAssassin::Util::untaint_var(\$opt{$optkey});
}
# If the client connection fails it'll spit out it's own error message which
# is probably more appropriate than anything we can provide to Nagios ourself.
# We'll still spit out something later, but Nagios will ignore it since it
# only uses the first line of output.
my $client;
if (defined $opt{'port'}) {
$client = new Mail::SpamAssassin::Client({port => $opt{'port'},
host => $opt{'hostname'}});
} else {
$client = new Mail::SpamAssassin::Client({socketpath => $opt{'socketpath'}});
}
# this'd be weird, but totally dependent on the client
unless (defined $client) {
print "SPAMD UNKNOWN: could not create M::SA::Client instance\n";
print "failed to create Mail::SpamAssassin::Client instance\n" if $opt{'verbose'};
exit EX_UNKNOWN;
}
# until we try a ping, the ping response status is unknown
my $response = -1;
print "connecting to spamd for ping\n" if $opt{'verbose'};
my $timer = Mail::SpamAssassin::Timeout->new({ secs => $opt{'timeout'}});
my $t0 = (HAS_TIME_HIRES ? Time::HiRes::time() : time());
my $err = $timer->run(sub {
if ($client->ping()) {
$response = 1;
} else {
$response = 0;
}
});
my $elapsed = (HAS_TIME_HIRES ? Time::HiRes::time() : time()) - $t0;
# a ping response should be most common, we'll handle it first
if ($response == 1) {
# it's possible that we may timeout right after setting the response status to 1
# since the timeout value > the critical value, this is a critical state
if ((defined $opt{'critical'} && $elapsed > $opt{'critical'}) || $timer->timed_out()) {
printf("SPAMD CRITICAL: %.3f second ping response time\n", $elapsed);
exit EX_CRITICAL;
}
# warning state will never timeout since that'd be critical (above)
if (defined $opt{'warning'} && ($elapsed > $opt{'warning'})) {
printf("SPAMD WARNING: %.3f second ping response time\n", $elapsed);
exit EX_WARNING;
}
# otherwise we got a timely ping response
printf("SPAMD OK: %.3f second ping repsonse time\n", $elapsed);
exit EX_OK;
}
# any way we get a failed ping response is a critical state
if ($response == 0) {
printf("SPAMD CRITICAL: ping failed in %.3f seconds\n", $elapsed);
exit EX_CRITICAL;
}
if ($response == -1) {
# this is the common timeout scenario
if ($timer->timed_out()) {
printf("SPAMD CRITICAL: ping timed out in %.3f seconds\n", $elapsed);
exit EX_CRITICAL;
}
# dos: I'll buy lunch for the first person that gets a page about this while
# they're sleeping if they come to Midland, ON to get it
printf("SPAMD UNKNOWN: assertion! unknown ping response status without timeout after %.3f seconds\n", $elapsed);
exit EX_UNKNOWN;
}
# and some apple pie too
exit EX_UNKNOWN;
#############################################################################
sub print_usage_and_exit {
print <<EOF;
sa-check_spamd version $VERSION
For more details, use "perldoc sa-check_spamd".
Usage:
sa-check_spamd [options]
Options:
-c secs, --critical=secs Critical ping response threshold
-h, -?, --help Print usage message
-H hostname, --hostname=hostname Hostname of spamd service to ping
-p port, --port=port Port of spamd service to ping
--socketpath=path Connect to given UNIX domain socket
-t secs, --timeout=secs Max time to wait for a ping response
-v, --verbose Verbose debug output
-V, --version Output version info
-w secs, --warning=secs Warning ping response threshold
EOF
exit EX_UNKNOWN;
}
# Don't use a __DATA__ here, it screws up embedded Perl Nagios (ePN)
=head1 NAME
sa-check_spamd - spamd monitoring script for use with Nagios, etc.
=head1 SYNOPSIS
sa-check_spamd [options]
Options:
-c secs, --critical=secs Critical ping response threshold
-h, -?, --help Print usage message
-H hostname, --hostname=hostname Hostname of spamd service to ping
-p port, --port=port Port of spamd service to ping
--socketpath=path Connect to given UNIX domain socket
-t secs, --timeout=secs Max time to wait for a ping response
-v, --verbose Verbose debug output
-V, --version Output version info
-w secs, --warning=secs Warning ping response threshold
=head1 DESCRIPTION
The purpose of this program is to provide a tool to monitor the status of
C<spamd> server processes. spamd is the daemonized version of the
spamassassin executable, both provided in the SpamAssassin distribution.
This program is designed for use, as a plugin, with the Nagios service
monitoring software available from http://nagios.org. It might be compatible
with other service monitoring packages. It is also useful as a command line
utility or as a component of a custom shell script.
=head1 OPTIONS
Options of the long form can be shortened as long as the remain
unambiguous (i.e. B<--host> can be used instead of B<--hostname>).
=over 4
=item B<-c> I<secs>, B<--critical>=I<secs>
Critical ping response threshold in seconds. If a spamd ping response takes
longer than the value specified (in seconds) the program will exit with a
value of 2 to indicate the critical status.
This value must be at least as long as the value specified for B<warning> and
less than the value specified for B<timeout>.
=item B<-h>, B<-?>, B<--help>
Prints this usage message and exits.
=item B<-H> I<hostname>, B<--hostname>=I<hostname>
The hostname, or IP address, of the spamd service to ping. By default the
hostname B<localhost> is used. If B<--socketpath> is set this value will be
ignored.
=item B<-p> I<port>, B<--port>=I<port>
The port of the spamd service to ping. By default port B<783> (the spamd
default port number) is used. If B<--socketpath> is set this value will be
ignored.
=item B<--socketpath>=I<path>
Connect to given UNIX domain socket. Use instead of a hostname and TCP port.
When set, any hostname and TCP port specified will be ignored.
=item B<-t> I<secs>, B<--timeout>=I<secs>
The maximum time to wait for a ping response. Once exceeded the program will
exit with a value of 2 to indicate the critical status. The default timeout
value is 45 seconds. The timeout must be no less than 1 second.
This value must be greater than the values specified for both the B<critical>
and B<warning> values.
=item B<-v>, B<--verbose>
Display verbose debug output on STDOUT.
=item B<-V>, B<--version>
Display version info on STDOUT.
=item B<-w> I<secs>, B<--warning>=I<secs>
Warning ping response threshold in seconds. If a spamd ping response takes
longer than the value specified (in seconds), and does not exceed the
B<critical> threshold value, the program will exit with a value of 1 to
indicate the warning staus.
This value must be no longer than the value specified for B<critical> and
less than the value specified for B<timeout>.
=back
=head1 EXIT CODES
The program will indicate the status of the spamd process being monitored by
exiting with one of these values:
=over 4
=item C<0>
OK: A spamd ping response was received within all threshold times.
=item C<1>
WARNING: A spamd ping response exceeded the warning threshold but not the
critical threshold.
=item C<2>
CRITICAL: A spamd ping response exceeded either the critical threshold or the
timeout value.
=item C<3>
UNKNOWN: An error, probably caused by a missing dependency or an invalid
configuration parameter being supplied, occurred in the sa-check_spamd program.
=back
=head1 SEE ALSO
spamc(1)
spamd(1)
spamassassin(1)
=head1 PREREQUISITES
C<Mail::SpamAssassin> version 3.1.1 or higher (3.1.6 or higher recommended)
=head1 AUTHOR
Daryl C. W. O'Shea, DOS Technologies <spamassassin@dostech.ca>
=head1 LICENSE
sa-check_spamd is distributed under the Apache License, Version 2.0, as
described in the file C<LICENSE> included with the Apache SpamAssassin
distribution and available at http://www.apache.org/licenses/LICENSE-2.0
=cut
|