summaryrefslogtreecommitdiffstats
path: root/contrib/check_email_loop.pl
blob: 733406da922fd9a7742a2b18b2fcf5dab4861407 (plain)
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
#!/usr/bin/perl 
#
# (c)2000 Benjamin Schmid, blueshift@gmx.net (emergency use only ;-)
# Copyleft by GNU GPL
#
#
# check_email_loop Nagios Plugin
#
# This script sends a mail with a specific id in the subject via
# an given smtp-server to a given email-adress. When the script
# is run again, it checks for this Email (with its unique id) on
# a given pop3 account and send another mail.
# 
#
# Example: check_email_loop.pl -poph=mypop -popu=user -pa=password
# 	   -smtph=mailer -from=returnadress@yoursite.com
#	   -to=remaileradress@friend.com -pendc=2 -lostc=0
#
# This example will send eacht time this check is executed a new
# mail to remaileradress@friend.com using the SMTP-Host mailer.
# Then it looks for any back-forwarded mails in the POP3 host
# mypop. In this Configuration CRITICAL state will be reached if  
# more than 2 Mails are pending (meaning that they did not came 
# back till now) or if a mails got lost (meaning a mail, that was
# send later came back prior to another mail).
# 

use Net::POP3;
use Net::SMTP;
use strict;
use Getopt::Long;
&Getopt::Long::config('auto_abbrev');

# ----------------------------------------

my $TIMEOUT = 120;
my %ERRORS = ('UNKNOWN' , '-1',
              'OK' , '0',
              'WARNING', '1',
              'CRITICAL', '2');

my $state = "UNKNOWN";
my ($sender,$receiver, $pophost, $popuser, $poppasswd, $smtphost);
my ($poptimeout,$smtptimeout,$pinginterval)=(60,60,5);
my ($lostwarn, $lostcrit,$pendwarn, $pendcrit);

# Internal Vars
my ($pop,$msgcount,@msglines,$statinfo,@messageids,$newestid);
my ($matchcount,$statfile) = (0,"check_email_loop.stat");

# Subs declaration
sub usage;
sub messagematchs;
sub nsexit;

# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
     print ("ERROR: $0 Time-Out $TIMEOUT s \n");
     exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);


# Evaluate Command Line Parameters
my $status = GetOptions(
		        "from=s",\$sender,
			"to=s",\$receiver,
                        "pophost=s",\$pophost,
                        "popuser=s",\$popuser,
			"passwd=s",\$poppasswd,
			"poptimeout=i",\$poptimeout,
			"smtphost=s",\$smtphost,
			"smtptimeout=i",\$smtptimeout,
			"statfile=s",\$statfile,
			"interval=i",\$pinginterval,
			"lostwarr=i",\$lostwarn,
			"lostcrit=i",\$lostcrit,
			"pendwarn=i",\$pendwarn,
			"pendcrit=i",\$pendcrit,
			);
usage() if ($status == 0 || ! ($pophost && $popuser && $poppasswd &&
	$smtphost && $receiver && $sender ));

# Try to read the ids of the last send emails out of statfile
if (open STATF, "$statfile") {
  @messageids = <STATF>;
  chomp @messageids;
  close STATF;
}

# Try to open statfile for writing 
if (!open STATF, ">$statfile") {
  nsexit("Failed to open mail-ID database $statfile for writing",'CRITICAL');
}

# Ok - check if it's time to release another mail

# ...

# creating new serial id
my $serial = time();
$serial = "ID#" . $serial . "#$$";

# sending new ping email
my $smtp = Net::SMTP->new($smtphost,Timeout=>$smtptimeout) 
  || nsexit("SMTP connect timeout ($smtptimeout s)",'CRITICAL');
($smtp->mail($sender) &&
 $smtp->to($receiver) &&
 $smtp->data() &&
 $smtp->datasend("To: $receiver\nSubject: E-Mail Ping [$serial]\n\n".
		 "This is a automatically sended E-Mail.\n".
		 "It ist not intended for human reader.\n\n".
		 "Serial No: $serial\n") &&
 $smtp->dataend() &&
 $smtp->quit
 ) || nsexit("Error delivering message",'CRITICAL');

# no the interessting part: let's if they are receiving ;-)

$pop = Net::POP3->new( $pophost, 
		 Timeout=>$poptimeout) 
       || nsexit("POP3 connect timeout (>$poptimeout s, host: $pophost)",'CRITICAL');

$msgcount=$pop->login($popuser,$poppasswd);

$statinfo="$msgcount mails on POP3";

nsexit("POP3 login failed (user:$popuser)",'CRITICAL') if (!defined($msgcount));

# Count messages, that we are looking 4:
while ($msgcount > 0) {
  @msglines = @{$pop->get($msgcount)};

  for (my $i=0; $i < scalar @messageids; $i++) {
    if (messagematchsid(\@msglines,$messageids[$i])) { 
      $matchcount++;
      # newest received mail than the others, ok remeber id.
      $newestid = $messageids[$i] if ($messageids[$i] > $newestid || !defined $newestid);
      $pop->delete($msgcount);  # remove E-Mail from POP3 server
      splice @messageids, $i, 1;# remove id from List
      last;                     # stop looking in list
    }
  } 

  $msgcount--;
}

$pop->quit();  # necessary for pop3 deletion!

# traverse through the message list and mark the lost mails
# that mean mails that are older than the last received mail.
if (defined $newestid) {
  $newestid =~ /\#(\d+)\#/;
  $newestid = $1;
  for (my $i=0; $i < scalar @messageids; $i++) {
    $messageids[$i] =~ /\#(\d+)\#/;
    my $akid = $1;
    if ($akid < $newestid) {
      $messageids[$i] =~ s/^ID/LI/; # mark lost
    }
  }
}

# Write list to id-Database
foreach my $id (@messageids) {
  print STATF  "$id\n";
}
print STATF "$serial\n";     # remember send mail of this session
close STATF;

# ok - count lost and pending mails;
my @tmp = grep /^ID/, @messageids;
my $pendingm = scalar @tmp;
@tmp = grep /^LI/, @messageids;
my $lostm = scalar @tmp; 

# Evaluate the Warnin/Crit-Levels
if (defined $pendwarn && $pendingm > $pendwarn) { $state = 'WARNING'; }
if (defined $lostwarn && $lostm > $lostwarn) { $state = 'WARNING'; }
if (defined $pendcrit && $pendingm > $pendcrit) { $state = 'CRITICAL'; }
if (defined $lostcrit && $lostm > $lostcrit) { $state = 'CRITICAL'; }

if ((defined $pendwarn || defined $pendcrit || defined $lostwarn 
     || defined $lostcrit) && ($state eq 'UNKNOWN')) {$state='OK';}


# Append Status info
$statinfo = $statinfo . ", $matchcount mail(s) came back,".
            " $pendingm pending, $lostm lost.";

# Exit in a Nagios-compliant way
nsexit($statinfo);

# ----------------------------------------------------------------------

sub usage {
  print "check_email_loop 1.0 Nagios Plugin - Real check of a E-Mail system\n";
  print "=" x 75,"\nERROR: Missing or wrong arguments!\n","=" x 75,"\n";
  print "This script sends a mail with a specific id in the subject via an given\n";
  print "smtp-server to a given email-adress. When the script is run again, it checks\n";
  print "for this Email (with its unique id) on a given pop3 account and sends \n";
  print "another mail.\n";
  print "\nThe following options are available:\n";
  print	"   -from=text         email adress of send (for mail returnr on errors)\n";
  print	"   -to=text           email adress to which the mails should send to\n";
  print "   -pophost=text      IP or name of the POP3-host to be checked\n";
  print "   -popuser=text      Username of the POP3-account\n";
  print	"   -passwd=text       Password for the POP3-user\n";
  print	"   -poptimeout=num    Timeout in seconds for the POP3-server\n";
  print "   -smtphost=text     IP oder name of the SMTP host\n";
  print "   -smtptimeout=num   Timeout in seconds for the SMTP-server\n";
  print "   -statfile=text     File to save ids of messages ($statfile)\n";
#  print "   -interval=num      Time (in minutes) that must pass by before sending\n"
#  print "                      another Ping-mail (gibe a new try);\n"; 
  print "   -lostwarn=num      WARNING-state if more than num lost emails\n";
  print "   -lostcrit=num      CRITICAL \n";
  print "   -pendwarn=num      WARNING-state if more than num pending emails\n";
  print "   -pendcrit=num      CRITICAL \n";
  print " Options may abbreviated!\n";
  print " LOST mails are mails, being sent before the last mail arrived back.\n";
  print " PENDING mails are those, which are not. (supposed to be on the way)\n";
  print "\nExample: \n";
  print " $0 -poph=host -pa=pw -popu=popts -smtph=host -from=root\@me.com\n ";
  print "      -to=remailer\@testxy.com -lostc=0 -pendc=2\n";
  print "\nCopyleft 19.10.2000, Benjamin Schmid\n";
  print "This script comes with ABSOLUTELY NO WARRANTY\n";
  print "This programm is licensed under the terms of the ";
  print "GNU General Public License\n\n";
  exit $ERRORS{"UNKNOWN"};
}

# ---------------------------------------------------------------------

sub nsexit {
  my ($msg,$code) = @_;
  $code=$state if (!defined $code);
  print "$code: $msg\n" if (defined $msg);
  exit $ERRORS{$code};
}

# ---------------------------------------------------------------------

sub messagematchsid {
  my ($mailref,$id) = (@_);
  my (@tmp);
  my $match = 0;
 
  # ID
  $id =~ s/^LI/ID/;    # evtl. remove lost mail mark
  @tmp = grep /Subject: E-Mail Ping \[/, @$mailref;
  chomp @tmp;
  if (($tmp[0] =~ /$id/)) 
    { $match = 1; }

  # Sender:
#  @tmp = grep /^From:\s+/, @$mailref;
#  if (@tmp && $sender ne "") 
#    { $match = $match && ($tmp[0]=~/$sender/); }

  # Receiver:
#  @tmp = grep /^To: /, @$mailref;
#  if (@tmp && $receiver ne "") 
#    { $match = $match && ($tmp[0]=~/$receiver/); }

  return $match;
}

# ---------------------------------------------------------------------