check_email_loop.pl 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. #!/usr/bin/perl
  2. #
  3. # (c)2000 Benjamin Schmid, blueshift@gmx.net (emergency use only ;-)
  4. # Copyleft by GNU GPL
  5. #
  6. #
  7. # check_email_loop Nagios Plugin
  8. #
  9. # This script sends a mail with a specific id in the subject via
  10. # an given smtp-server to a given email-adress. When the script
  11. # is run again, it checks for this Email (with its unique id) on
  12. # a given pop3 account and send another mail.
  13. #
  14. #
  15. # Example: check_email_loop.pl -poph=mypop -popu=user -pa=password
  16. # -smtph=mailer -from=returnadress@yoursite.com
  17. # -to=remaileradress@friend.com -pendc=2 -lostc=0
  18. #
  19. # This example will send eacht time this check is executed a new
  20. # mail to remaileradress@friend.com using the SMTP-Host mailer.
  21. # Then it looks for any back-forwarded mails in the POP3 host
  22. # mypop. In this Configuration CRITICAL state will be reached if
  23. # more than 2 Mails are pending (meaning that they did not came
  24. # back till now) or if a mails got lost (meaning a mail, that was
  25. # send later came back prior to another mail).
  26. #
  27. use Net::POP3;
  28. use Net::SMTP;
  29. use strict;
  30. use Getopt::Long;
  31. &Getopt::Long::config('auto_abbrev');
  32. # ----------------------------------------
  33. my $TIMEOUT = 120;
  34. my %ERRORS = ('UNKNOWN' , '-1',
  35. 'OK' , '0',
  36. 'WARNING', '1',
  37. 'CRITICAL', '2');
  38. my $state = "UNKNOWN";
  39. my ($sender,$receiver, $pophost, $popuser, $poppasswd, $smtphost);
  40. my ($poptimeout,$smtptimeout,$pinginterval)=(60,60,5);
  41. my ($lostwarn, $lostcrit,$pendwarn, $pendcrit);
  42. # Internal Vars
  43. my ($pop,$msgcount,@msglines,$statinfo,@messageids,$newestid);
  44. my ($matchcount,$statfile) = (0,"check_email_loop.stat");
  45. # Subs declaration
  46. sub usage;
  47. sub messagematchs;
  48. sub nsexit;
  49. # Just in case of problems, let's not hang Nagios
  50. $SIG{'ALRM'} = sub {
  51. print ("ERROR: $0 Time-Out $TIMEOUT s \n");
  52. exit $ERRORS{"UNKNOWN"};
  53. };
  54. alarm($TIMEOUT);
  55. # Evaluate Command Line Parameters
  56. my $status = GetOptions(
  57. "from=s",\$sender,
  58. "to=s",\$receiver,
  59. "pophost=s",\$pophost,
  60. "popuser=s",\$popuser,
  61. "passwd=s",\$poppasswd,
  62. "poptimeout=i",\$poptimeout,
  63. "smtphost=s",\$smtphost,
  64. "smtptimeout=i",\$smtptimeout,
  65. "statfile=s",\$statfile,
  66. "interval=i",\$pinginterval,
  67. "lostwarr=i",\$lostwarn,
  68. "lostcrit=i",\$lostcrit,
  69. "pendwarn=i",\$pendwarn,
  70. "pendcrit=i",\$pendcrit,
  71. );
  72. usage() if ($status == 0 || ! ($pophost && $popuser && $poppasswd &&
  73. $smtphost && $receiver && $sender ));
  74. # Try to read the ids of the last send emails out of statfile
  75. if (open STATF, "$statfile") {
  76. @messageids = <STATF>;
  77. chomp @messageids;
  78. close STATF;
  79. }
  80. # Try to open statfile for writing
  81. if (!open STATF, ">$statfile") {
  82. nsexit("Failed to open mail-ID database $statfile for writing",'CRITICAL');
  83. }
  84. # Ok - check if it's time to release another mail
  85. # ...
  86. # creating new serial id
  87. my $serial = time();
  88. $serial = "ID#" . $serial . "#$$";
  89. # sending new ping email
  90. my $smtp = Net::SMTP->new($smtphost,Timeout=>$smtptimeout)
  91. || nsexit("SMTP connect timeout ($smtptimeout s)",'CRITICAL');
  92. ($smtp->mail($sender) &&
  93. $smtp->to($receiver) &&
  94. $smtp->data() &&
  95. $smtp->datasend("To: $receiver\nSubject: E-Mail Ping [$serial]\n\n".
  96. "This is a automatically sended E-Mail.\n".
  97. "It ist not intended for human reader.\n\n".
  98. "Serial No: $serial\n") &&
  99. $smtp->dataend() &&
  100. $smtp->quit
  101. ) || nsexit("Error delivering message",'CRITICAL');
  102. # no the interessting part: let's if they are receiving ;-)
  103. $pop = Net::POP3->new( $pophost,
  104. Timeout=>$poptimeout)
  105. || nsexit("POP3 connect timeout (>$poptimeout s, host: $pophost)",'CRITICAL');
  106. $msgcount=$pop->login($popuser,$poppasswd);
  107. $statinfo="$msgcount mails on POP3";
  108. nsexit("POP3 login failed (user:$popuser)",'CRITICAL') if (!defined($msgcount));
  109. # Count messages, that we are looking 4:
  110. while ($msgcount > 0) {
  111. @msglines = @{$pop->get($msgcount)};
  112. for (my $i=0; $i < scalar @messageids; $i++) {
  113. if (messagematchsid(\@msglines,$messageids[$i])) {
  114. $matchcount++;
  115. # newest received mail than the others, ok remeber id.
  116. $newestid = $messageids[$i] if ($messageids[$i] > $newestid || !defined $newestid);
  117. $pop->delete($msgcount); # remove E-Mail from POP3 server
  118. splice @messageids, $i, 1;# remove id from List
  119. last; # stop looking in list
  120. }
  121. }
  122. $msgcount--;
  123. }
  124. $pop->quit(); # necessary for pop3 deletion!
  125. # traverse through the message list and mark the lost mails
  126. # that mean mails that are older than the last received mail.
  127. if (defined $newestid) {
  128. $newestid =~ /\#(\d+)\#/;
  129. $newestid = $1;
  130. for (my $i=0; $i < scalar @messageids; $i++) {
  131. $messageids[$i] =~ /\#(\d+)\#/;
  132. my $akid = $1;
  133. if ($akid < $newestid) {
  134. $messageids[$i] =~ s/^ID/LI/; # mark lost
  135. }
  136. }
  137. }
  138. # Write list to id-Database
  139. foreach my $id (@messageids) {
  140. print STATF "$id\n";
  141. }
  142. print STATF "$serial\n"; # remember send mail of this session
  143. close STATF;
  144. # ok - count lost and pending mails;
  145. my @tmp = grep /^ID/, @messageids;
  146. my $pendingm = scalar @tmp;
  147. @tmp = grep /^LI/, @messageids;
  148. my $lostm = scalar @tmp;
  149. # Evaluate the Warnin/Crit-Levels
  150. if (defined $pendwarn && $pendingm > $pendwarn) { $state = 'WARNING'; }
  151. if (defined $lostwarn && $lostm > $lostwarn) { $state = 'WARNING'; }
  152. if (defined $pendcrit && $pendingm > $pendcrit) { $state = 'CRITICAL'; }
  153. if (defined $lostcrit && $lostm > $lostcrit) { $state = 'CRITICAL'; }
  154. if ((defined $pendwarn || defined $pendcrit || defined $lostwarn
  155. || defined $lostcrit) && ($state eq 'UNKNOWN')) {$state='OK';}
  156. # Append Status info
  157. $statinfo = $statinfo . ", $matchcount mail(s) came back,".
  158. " $pendingm pending, $lostm lost.";
  159. # Exit in a Nagios-compliant way
  160. nsexit($statinfo);
  161. # ----------------------------------------------------------------------
  162. sub usage {
  163. print "check_email_loop 1.0 Nagios Plugin - Real check of a E-Mail system\n";
  164. print "=" x 75,"\nERROR: Missing or wrong arguments!\n","=" x 75,"\n";
  165. print "This script sends a mail with a specific id in the subject via an given\n";
  166. print "smtp-server to a given email-adress. When the script is run again, it checks\n";
  167. print "for this Email (with its unique id) on a given pop3 account and sends \n";
  168. print "another mail.\n";
  169. print "\nThe following options are available:\n";
  170. print " -from=text email adress of send (for mail returnr on errors)\n";
  171. print " -to=text email adress to which the mails should send to\n";
  172. print " -pophost=text IP or name of the POP3-host to be checked\n";
  173. print " -popuser=text Username of the POP3-account\n";
  174. print " -passwd=text Password for the POP3-user\n";
  175. print " -poptimeout=num Timeout in seconds for the POP3-server\n";
  176. print " -smtphost=text IP oder name of the SMTP host\n";
  177. print " -smtptimeout=num Timeout in seconds for the SMTP-server\n";
  178. print " -statfile=text File to save ids of messages ($statfile)\n";
  179. # print " -interval=num Time (in minutes) that must pass by before sending\n"
  180. # print " another Ping-mail (gibe a new try);\n";
  181. print " -lostwarn=num WARNING-state if more than num lost emails\n";
  182. print " -lostcrit=num CRITICAL \n";
  183. print " -pendwarn=num WARNING-state if more than num pending emails\n";
  184. print " -pendcrit=num CRITICAL \n";
  185. print " Options may abbreviated!\n";
  186. print " LOST mails are mails, being sent before the last mail arrived back.\n";
  187. print " PENDING mails are those, which are not. (supposed to be on the way)\n";
  188. print "\nExample: \n";
  189. print " $0 -poph=host -pa=pw -popu=popts -smtph=host -from=root\@me.com\n ";
  190. print " -to=remailer\@testxy.com -lostc=0 -pendc=2\n";
  191. print "\nCopyleft 19.10.2000, Benjamin Schmid\n";
  192. print "This script comes with ABSOLUTELY NO WARRANTY\n";
  193. print "This programm is licensed under the terms of the ";
  194. print "GNU General Public License\n\n";
  195. exit $ERRORS{"UNKNOWN"};
  196. }
  197. # ---------------------------------------------------------------------
  198. sub nsexit {
  199. my ($msg,$code) = @_;
  200. $code=$state if (!defined $code);
  201. print "$code: $msg\n" if (defined $msg);
  202. exit $ERRORS{$code};
  203. }
  204. # ---------------------------------------------------------------------
  205. sub messagematchsid {
  206. my ($mailref,$id) = (@_);
  207. my (@tmp);
  208. my $match = 0;
  209. # ID
  210. $id =~ s/^LI/ID/; # evtl. remove lost mail mark
  211. @tmp = grep /Subject: E-Mail Ping \[/, @$mailref;
  212. chomp @tmp;
  213. if (($tmp[0] =~ /$id/))
  214. { $match = 1; }
  215. # Sender:
  216. # @tmp = grep /^From:\s+/, @$mailref;
  217. # if (@tmp && $sender ne "")
  218. # { $match = $match && ($tmp[0]=~/$sender/); }
  219. # Receiver:
  220. # @tmp = grep /^To: /, @$mailref;
  221. # if (@tmp && $receiver ne "")
  222. # { $match = $match && ($tmp[0]=~/$receiver/); }
  223. return $match;
  224. }
  225. # ---------------------------------------------------------------------