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
|
#!/usr/bin/perl
# Yet another smtp monitor using IO::Socket with timing and logging
#
# $Id: smtp3.monitor 1.1 Fri, 27 Jul 2001 11:39:59 -0400 trockij $
#
# Copyright (C) 2001, Jon Meek, meekj@ieee.org
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
=head1 NAME
B<smtp3.monitor> - smtp monitor for mon with timing and logging
=head1 DESCRIPTION
A SMTP monitor using IO::Socket with connection response timing and
optional logging. This test is simple, as soon as the greeting banner
is received from the SMTP server the monitor client closes the session
with a QUIT command.
=head1 SYNOPSIS
B<smtp3.monitor> -l log_file_YYYYMM.log -t timeout_seconds -T alarm_time host host1 host2 ...
=head1 OPTIONS
=over 5
=item B<-d> Debug/Test
=item B<-t timeout> Connect timeout in seconds
=item B<-T alarm_timeout> Alarm if connect is successful but took
longer than alarm_timeout seconds
=item B<-l log_file_template> /path/to/logs/smtp_YYYYMM.log
Current year & month are substituted for YYYYMM, that is the only
possible template at this time.
=back
=head1 MON CONFIGURATION EXAMPLE
hostgroup smtp mail1.mymails.org mail2.mymails.org
mail3.mymails.org
watch smtp
service smtp_check
interval 5m
monitor smtp3.monitor -t 70 -T 30 -l /n/na1/logs/wan/smtp_YYYYMM.log
period wd {Sun-Sat}
alert mail.alert meekj@mymails.org
alertevery 1h summary
=head1 LOG FILE FORMAT
A normal log entry has the format:
measurement_time smtp_host_name connect_time
A failed connection log entry contains:
measurement_time smtp_host_name connect_time smtp_code_and_greeting (or connect_error)
Where:
F<measurement_time> - Is the time of the connection attempt in seconds since 1970
F<smtp_host_name> - Is the name of the smtp server that was tested
F<connect_time> - Is the time from the connect request until the SMTP
greeting appeared in seconds with 100 microsecond resolution
F<smtp_code_and_banner> - Should have the SMTP response code integer
followed by the greeting banner
F<connect_error> - If present may indicate "Connect failed" meaning
that the connect attempt failed immediately, possibly due to a DNS
lookup error or because the server is not running any service on port
25. The field may also be "Connect timeout" indicating that the
connect failed after the set timeout period.
=head1 BUGS
A SMTP temporary failure code should cause the monitor to retry the connection.
This initial release has seen less than one day of testing.
=head1 REQUIRED PERL MODULES
IO::Socket
Time::HiRes
If you do not have Time::HiRes you can choose to comment out the lines
that refer to F<gettimeofday> and F<tv_interval> but several features will be lost.
=head1 AUTHOR
Jon Meek, meekj@ieee.org
=cut
use Getopt::Std;
use IO::Socket;
use Time::HiRes qw( gettimeofday tv_interval );
$RCSid = q{$Id: smtp3.monitor 1.1 Fri, 27 Jul 2001 11:39:59 -0400 trockij $};
getopts ("ds:t:T:l:"); # s not used yet, may be optional smtp command
$TimeOut = $opt_t || 30; # Default timeout in seconds
$dt = 0; # Initialize connect time variable
@Failures = ();
$TimeOfDay = time;
print "TimeOfDay: $TimeOfDay\n" if $opt_d;
foreach $host (@ARGV) { # Check each host
print "Check: $host\n" if $opt_d;
push(@HostNames, $host);
$TestTime{$host} = time;
#
# Use eval/alarm to handle timeout
#
eval {
local $SIG{ALRM} = sub { die "timeout\n" }; # Alarm handler
alarm($TimeOut); # Do a SIG_ALRM in $TimeOut seconds
$t1 = [gettimeofday]; # Start connection timer, then connect
$sock = IO::Socket::INET->new(PeerAddr => $host,
PeerPort => 'smtp(25)',
Proto => 'tcp');
if (defined $sock) { # Connection succeded
$in = <$sock>; # Get banner
$t2 = [gettimeofday]; # Stop clock
chomp $in; # Clean up banner EOL
$ResponseBanner{$host} = $in;
print "banner: $in\n" if $opt_d;
# print $sock "NOOP\r\n"; # may want to add optional command later
print $sock "QUIT\r\n"; # Shutdown connection
close $sock;
$dt = tv_interval ($t1, $t2); # Compute connection time
if ($in !~ /^220[-\s]/) { # Consider "220 Service ready" to be only valid
push(@Failures, $host); # Note failure
$FailureDetail{$host} = $in; # Save failure banner
}
$ConnectTime{$host} = sprintf("%0.4f", $dt); # Format to 100us resolution
if ($opt_T) { # Check for slow response
if ($dt > $opt_T) {
push(@Failures, $host); # Call it a failure
$FailureDetail{$host} = "Slow Connect";
}
}
} else { # Connection failed
print "Connect to $host failed\n" if $opt_d;
push(@Failures, $host); # Save failed host
$FailureDetail{$host} = "Connect failed";
$ConnectTime{$host} = -1;
}
};
alarm(0); # Stop alarm countdown
if ($@ =~ /timeout/) { # Detect timeout failures
push(@Failures, $host);
$FailureDetail{$host} = "Connect timeout";
$ConnectTime{$host} = -1;
}
}
if ($opt_d) {
foreach $host (sort @HostNames) {
print "$TestTime{$host} $host $ConnectTime{$host} $ResponseBanner{$host}\n";
}
}
# Write results to logfile, if -l
if ($opt_l) {
# Determine logfile name, usually based on year/month
$LogFile = $opt_l;
($sec,$min,$hour,$mday,$Month,$Year,$wday,$yday,$isdst) =
localtime($TimeOfDay);
$Month++;
$Year += 1900;
$YYYYMM = sprintf('%04d%02d', $Year, $Month);
$LogFile =~ s/YYYYMM/$YYYYMM/; # Fill in current year and month
open(LOG, ">>$LogFile") || warn "$0 Can't open logfile: $LogFile\n";
foreach $host (sort @HostNames) {
print LOG "$TestTime{$host} $host $ConnectTime{$host} $FailureDetail{$host}\n";
}
close LOG;
}
if (@Failures == 0) { # Indicate "all OK" to mon
exit 0;
}
#
# Otherwise we have one or more failures
#
@SortedFailures = sort @Failures;
print "@SortedFailures\n";
foreach $host (@SortedFailures) {
print "$host $ConnectTime{$host} $FailureDetail{$host}\n";
}
print "\n";
exit 1; # Indicate failure to mon
__END__
SMTP Reply Codes From RFC-821 - may use in the future
211 System status, or system help reply
214 Help message
[Information on how to use the receiver or the meaning of a
particular non-standard command; this reply is useful only
to the human user]
220 <domain> Service ready
221 <domain> Service closing transmission channel
250 Requested mail action okay, completed
251 User not local; will forward to <forward-path>
354 Start mail input; end with <CRLF>.<CRLF>
421 <domain> Service not available,
closing transmission channel
[This may be a reply to any command if the service knows it
must shut down]
450 Requested mail action not taken: mailbox unavailable
[E.g., mailbox busy]
451 Requested action aborted: local error in processing
452 Requested action not taken: insufficient system storage
500 Syntax error, command unrecognized
[This may include errors such as command line too long]
501 Syntax error in parameters or arguments
502 Command not implemented
503 Bad sequence of commands
504 Command parameter not implemented
550 Requested action not taken: mailbox unavailable
[E.g., mailbox not found, no access]
551 User not local; please try <forward-path>
552 Requested mail action aborted: exceeded storage allocation
553 Requested action not taken: mailbox name not allowed
[E.g., mailbox syntax incorrect]
554 Transaction failed
|