[Logwatch-Devel] exim

Gary Allen Vollink Gary.Vollink at CorVu.com
Tue May 24 12:39:59 MST 2005


Bjorn L. wrote:

>>/ I modified exim, and saved it in cvs.  It had the date
>/>/ hardcoded (to be the equivalent of 'yesterday') and had
>/>/ some module issues.  So if you use exim, you may want to
>/>/ give it a try; it is very possible it was exiting
>/>/ prematurely in your system before, without printing
>/>/ anything.
>/>/ 
>/>/ Looking through the code it appears that it reads most of
>/>/ the log into memory, and then prints it out without
>/>/ many changes.  I don't use exim, so I don't know if
>/>/ that is too much info, but feel free to submit code
>/>/ to optimize the analysis and reporting if you make
>/>/ improvements.
>/
>P.S.  The specific file for the above is:
>                 scripts/services/exim.
>       And the comments are in Polish, so if anyone
>       wants to add the translation into English, send
>       us a diff file with the added comments.
>
Thank you, Bjorn, for your assistance to make sure I was working with 
the right version...

I use Exim on two servers (and two domains), and have done some 
major-reworking to this file for my use.  I have re-worked it from the 
v6.1 stuff that Bjorn committed.  I have rewritten most of the comments 
(as I couldn't find a pl/en translator that could make sense of the more 
complex comments).  Original pl comments still appear in one section 
near the bottom.

Any critique is more than welcome.

scripts/services/exim (diff) follows:

--- exim    2005-05-09 17:19:26.000000000 -0500
+++ exim.new    2005-05-24 13:05:14.000000000 -0500
@@ -4,23 +4,43 @@
 ##########################################################################
 
 ########################################################
-# This module requires Date::Calc and Tie::IxHash!!
+# Detail Levels:
+#     0: Prints MisFormatted log lines (should never happen)
+#        Prints server Stop/Start
+#        Virus/Malware blocks (if AntiVirus configured)
+#        Prints protocol violations (by category)
+##
+#     5: Prints Queue Run count
+#        Prints Refused Relay count
+##
+#    20: Prints Refused Relay (individual lines)
+##
+#    40: Prints Per Message Tracking (setting high as most
+#          default systems can't run it - see next).
+########################################################
+
+########################################################
+# At Detail >= 40 (Per Message Tracking)
+# This module requires Tie::IxHash
+##
 # To install, run this as root:
 # root> perl -MCPAN -eshell
-# cpan> install Date::Calc
 # cpan> install Tie::IxHash
 ########################################################
 
 ########################################################
-# This was written and is maintained by:
+# This was written by:
 #    Dariusz Nierada <dnierada at kat.supermedia.pl>
+# Edits: Bjorn L <bl_logwatch at mblmail.net>
+#      Gary Vollink <gary.vollink at corvu.com>
 ########################################################
 
 use Logwatch ':dates';
 
 my $Detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
 
-# procedura sortujaca tak jak ja chce (bo tamta sotrowala po ASCII)
+# procedure to compare numbers at the beginning of submitted strings.
+#  .. Which in this case is the message count for a given message ID.
 sub wedlug_liczb {
     ($aa) = ($a =~ /^(\d+).+/);
     ($bb) = ($b =~ /^(\d+).+/);
@@ -34,11 +54,11 @@
 
 while (defined($ThisLine = <STDIN>)) {
    chomp($ThisLine);
-    # pobierz dzisiejsza date z 2002-03-31 22:13:48 ...
+    # Collect this line's date, e.g. 2002-03-31 22:13:48 ...
    do {
       $BadFormat{$ThisLine}++;
       next;
-   } unless ($year1,$month1,$day1) = ($ThisLine =~ 
/^(\d+)\-(\d+)\-(\d+)\s.+/);
+   } unless ($year1,$month1,$day1,$h1,$m1,$s1) = ($ThisLine =~ 
/^(\d+)\-(\d+)\-(\d+)\s(\d+):(\d+):(\d+)\s.+/);
 
    next unless $ThisLine =~ /^$SearchDate /o;
 
@@ -48,15 +68,76 @@
    elsif ( $ThisLine =~ /Start queue run\:/ ) {
       $StartQueue++;
    }
+   elsif ( $ThisLine =~ /message contains malware/ ) {
+      # Exim <= 4.44 with ExiScan-ACL Patch (Running AntiVirus Software)
+      $Virus{$ThisLine}++;
+   }
+   elsif ( $ThisLine =~ /message contains a virus/ ) {
+      # Exim >= 4.50 compiled with WITH_CONTENT_SCAN=yes (Running 
AntiVirus Software)
+      $Virus{$ThisLine}++;
+   }
+    elsif ( $ThisLine =~ /unexpected disconnection while reading SMTP 
command/ )
+    {
+      # Common error from SPAM hosts.
+       $Proto{$ThisLine}++;
+    }
+    elsif ( $ThisLine =~ /SMTP protocol violation\:/ )
+    {
+      # Common error from SPAM hosts.
+       $Proto{$ThisLine}++;
+    }
+    elsif ( $ThisLine =~ /rejected [HE][EH]LO from\s/ )
+    {
+      # Typically due to underscores _ in the HELO line
+      #   (a common protocol violation)
+      # Also can be due to odd escape sequences
+      #   (never seen from a valid MX)
+       $Proto{$ThisLine}++;
+    }
+    elsif ( $ThisLine =~ /no host name found for IP address / )
+    {
+        # This is common, and it's just noise... Ignore this
+         # Could add to Proto - then detail it
+    }
+    elsif ( $ThisLine =~ /no IP address found for host/ )
+    {
+        # This is common, and it's just noise... Ignore this
+         # Could add to Proto - then detail it
+    }
+    elsif ( $ThisLine =~ /SIGHUP received\: re-exec/ )
+    {
+      # I should probably 'push' this, but this seems cleaner.
+        @Restart = (@Restart, "$year1-$month1-$day1 $h1:$m1:$s1 (stop)");
+    }
+    elsif ( $ThisLine =~ /daemon started\:/ )
+    {
+      # I should probably 'push' this, but this seems cleaner.
+        @Restart = (@Restart, "$year1-$month1-$day1 $h1:$m1:$s1 (start)");
+    }
+###
    elsif ( $ThisLine =~ /refused relay/ || $ThisLine =~ /rejected RCPT/ ) {
       $Relay++;
       @RelayH = (@RelayH, $ThisLine);
    }
-   elsif ( $ThisLine =~ 
/^\d+\-\d+\-\d+\s\d+\:\d+\:\d+\s\w+\-\w+\-\w+\s/ ) { # inne wiadomosci 
przesylane przez EXIMA
-    ($mdate,$mtime,$mid,$mrest) = ($ThisLine =~ 
/^(\d+\-\d+\-\d+)\s(\d+\:\d+\:\d+)\s(\w+\-\w+\-\w+)(.+)/);
-    $licze++;         # Dodaje taki licznik aby potem przy wypisaniu 
posortowac po nim, bo wypisywal nie po kolei
-    $mmsg{$mid}{$licze.$mrest} = "$mdate $mtime";
+   elsif ( $ThisLine =~ 
/^\d+\-\d+\-\d+\s\d+\:\d+\:\d+\s\w+\-\w+\-\w+\s/ ) {
+      # Collect Message ID specific notes...
+      if (($Detail >= 40) && (!defined(%mmsg))) {
+         if (eval "require Tie::IxHash") {
+            tie (%mmsg, Tie::IxHash);
+         }
+         else {
+            # Not sure if this is "right", but it works.
+            print STDERR "\nERROR: (logwatch/exim) Tie::IxHash not 
found when Detail Level (>= 40).\n";
+            $Detail = 39;
+         }
+      }
+      if ($Detail >= 40) {
+         ($mdate,$mtime,$mid,$mrest) =
+               ($ThisLine =~ 
/^(\d+\-\d+\-\d+)\s(\d+\:\d+\:\d+)\s(\w+\-\w+\-\w+)(.+)/);
+         $licze++;  # Count of individual Message Lines, used for sort
+         $mmsg{$mid}{$licze.$mrest} = "$mdate $mtime";
 
+      }
    }
    else
    {
@@ -64,6 +145,7 @@
    }
 } #end while
 
+# Print MisFormatted log lines (should never happen)
 if (%BadFormat) {
    print "\n***** BAD FORMAT (Possible data corruption or Exim bug) 
*****\n";
    foreach $ThisOne (keys %BadFormat) {
@@ -71,6 +153,15 @@
    }
 }
 
+# Print server Stops/Starts
+if (@Restart) {
+   print "\n--- Exim Restarted ---\n";
+   foreach $ThisOne (@Restart) {
+      print "  $ThisOne\n";
+   }
+}
+
+
 if ($Detail >= 5) {
    # Start Queue
    $StartQueue and print "\nStart queue run: $StartQueue Time(s)\n";
@@ -80,16 +171,110 @@
    # Relaye!
    if (@RelayH) {
       print "\n--- Refused Relays \n";
-      print "--- \(eg. spam try\): $Relay  Time(s)\n\n";
+      if ( $Detail >= 20 ) {
+         print "--- \(eg. spam try\): $Relay Lines follow:\n\n";
   
-      foreach $ThisOne (@RelayH) {
-         print "$ThisOne\n";
+         foreach $ThisOne (@RelayH) {
+            print "$ThisOne\n";
+         }
       }
+      else {
+         print "--- \(eg. spam try\): $Relay  time(s)\n\n";
+      }
+   }
+}
+
+# Print Blocked Viruses/Malware
+if (%Virus) {
+    my (%vir);
+    print "\n--- VIRUS/MALWARE BLOCKED ---\n";
+   foreach $ThisOne (sort(keys %Virus)) {
+       # Need mid empty...
+       $mid = "";
+       # Virus name holder...
+       $cc = "";
+       # Extract exim date and time string...
+       ($mdate, $mtime) = ($ThisOne =~ 
m/^(\d+-\d+-\d+)\s(\d+\:\d+\:\d+)\s/);
+       # Link date and time (looks cleaner)...
+       $aa = "$mdate $mtime";
+       # Extract the REAL IP address...
+       ($bb) = ($ThisOne =~ m/\s\[(\d+\.\d+\.\d+\.\d+)\]\s/);
+           # Exim >= 4.50 compiled with, WITH_CONTENT_SCAN=yes
+       # Default warning looks like this...
+           # rejected after DATA: This message contains a virus (%s).
+       if ($ThisOne =~ m/virus \((.*?)\)/) {
+           $cc = $1;
+       }
+           # Exim <= 4.44 with ExiScan-ACL patch
+           # rejected after DATA: This message contains malware (%s)
+       elsif ($ThisOne =~ m/malware \((.*?)\)/) {
+           $cc = $1;
+       }
+    # There is probably a more graceful way to do this...
+    if (defined( $vir{$cc} )) {
+        # Assign current value to temporary (mid)
+        $mid = $vir{$cc};
+    }
+    # Set current value to (old value)+new value+','
+    $vir{$cc} = "$mid$aa : IP:$bb,";
+   }
+   # Print the results...
+   foreach $ThisOne (sort(keys %vir)) {
+      print "Virus: [$ThisOne]\n";
+    foreach $aa ( sort( split /,/, $vir{$ThisOne} )) {
+        print "   $aa\n";
+    }
    }
 }
 
+# Print Protocol Violations
+if (%Proto) {
+    my (%spam);
+    # Probable SPAM hosts...
+    print "\n--- MALFUNCTIONING HOSTS ---\n";
+   foreach $ThisOne (sort(keys %Proto)) {
+       # We need this blank.
+       $mid = "";
+       # IP address/current issue holder.
+       $bb = "";
+       # Extract exim date and time string...
+       ($mdate, $mtime) = ($ThisOne =~ 
m/^(\d+-\d+-\d+)\s(\d+\:\d+\:\d+)\s/);
+       # Link date and time (looks cleaner)...
+       $aa = "$mdate $mtime";
+       if ( $ThisOne =~ m/SMTP protocol violation\:\s(.*?\(.*?\))\:/ ) {
+           $cc = $1;
+           ( $bb ) = ($ThisOne =~ m/\[(\d+\.\d+\.\d+\.\d+)\]/);
+       }
+       elsif ( $ThisOne =~ m/unexpected disconnection while reading 
SMTP command/ ) {
+           $cc = "Sudden disconnect while expecting remote input";
+           ( $bb ) = ($ThisOne =~ m/\[(\d+\.\d+\.\d+\.\d+)\]/);
+       }
+       elsif ( $ThisOne =~ m/rejected ([HE][EH])LO from 
\[(\d+\.\d+\.\d+\.\d+)\]\:\s(.*?):\s(.*?)$/ ) {
+           $cc = "rejected HELO/EHLO: $3";
+           $bb = "$2 ($1LO $4)";
+       }
+       else {
+           # If we picked up a malfunction but didn't collect it here,
+           # no need to make the user suffer with superfluous error
+           # messages.
+           next;
+       }
+       if (defined( $spam{$cc} )) {
+           $mid = $spam{$cc};
+       }
+       $spam{$cc} = "$mid$aa : IP:$bb,";
+   }
+   foreach $ThisOne (sort(keys %spam)) {
+      print "Malfunction: [$ThisOne]\n";
+       foreach $aa ( sort( split /,/, $spam{$ThisOne} )) {
+           print "   $aa\n";
+       }
+   }
+}
+
+
 # Messages by ID
-if (keys %mmsg and ($Detail >= 10)) {
+if (keys %mmsg and ($Detail >= 40)) {
    my $tmsgcount=0;
    my $tmsgrcpts=0;
    print "\n--- Messages history ---\n\n";






More information about the Logwatch-Devel mailing list