#!/usr/bin/perl # # reads CommuniGate Pro logs, extracts interesting tidbits, like errors and stats # and emails the results to me. # Intended to be run shortly after midnight by cron (as root user). # # You must set the SMTP log level to "low level" to get the detail that this needs. # # Note: log format changed in CGP 3.5.5 to use cmd: and rsp: instead of inp: and out: # # Started 2002-02-12 by Stonewall Ballard # # To do: # Check outgoing SMTP for errors, esp. blacklisting # Note failed logins # Track "undeliverable" messages from rules and connect them to their original SMTPI # Cope with numbering restart when server restarts # Group and count duplicate spams # # This is free software. Placed in the public domain by Stonewall Ballard. No warranties # expressed or implied. Use at your own risk. # **** set local parameters **** $ReportToAddress = "admin\@dom.ain"; $ReportFromAddress = "CGP_Log_Summary\@dom.ain"; # **** When testing with desktop files, change this **** # 0 for regular, 1 to test with local log file and reporting to STDOUT $testing = 0; # change as needed $testlog = "2002-02-17"; $testlogdir = "/home/usersHomeDirectory"; # **** No local changes needed from here on **** # stat counters $numQueuedMsgs = 0; $numIncomingSMTP = 0; $numOutgoingSMTP = 0; $bytesIncomingSMTP = 0; # CommuniGate directories $logdir = "/var/CommuniGate/SystemLogs/"; $submitdir = "/var/CommuniGate/Submitted/"; $logdir = $testlogdir if $testing; # if there's an arg, it's a day offset (1 == yesterday, the default) $dayoffset = 1; $arg = shift; # distinguishes "0" from "" $dayoffset = $arg if $arg or length $arg == 1; # get the name of yesterday's log $timenow = time(); # subtract 24 hours to make it yesterday $timenow -= 60 * 60 * 24 * $dayoffset; ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime( $timenow ); $logname = sprintf("%4.4d-%2.2d-%2.2d", $year + 1900, $mon + 1, $mday); $logname = $testlog if $testing; # the spew message $spewMsg = "SPEW: Spammer is spewing"; # open the log $logpath = "$logdir$logname.log"; open( IN, "<$logpath" ) || die "Can't open log $logpath"; while () { chomp; # **** gather statistics **** # track queued messages if (/^..:..:..... . ENQUEUER-/) { ++$numQueuedMsgs; } # count and weigh incoming smtp messages elsif (/^..:..:..... . SMTPI-\d+\([^\)]+\) \[\d+\] received, (\d+) bytes/) { $bytesIncomingSMTP += $1; ++$numIncomingSMTP; } # count outgoing messages elsif (/^..:..:..... . SMTP-\d+\([^\)]+\) \[(\d+)\] sent to /) { ++$numOutgoingSMTP; } # group related interesting incoming SMTP if ( /^(..:..:.....) . SMTPI-(\d+)(.+)$/ ) { $timestamp = $1; $key = $2; # get possibly empty group string from hash $groupdesc = $groupSMTPI{$key}; # look for incoming HELO, EHLO, MAIL FROM, RCPT TO lines if ( /\((.+)\) (inp|cmd): (HELO|EHLO)\s+(.+)$/i ) { $groupdesc .= "HELO: $4 $1 $timestamp SMTPI-$key\n"; } elsif ( /(inp|cmd): MAIL FROM:\s*([^ ]+).*$/i ) { $groupdesc .= "FROM: $2\n"; } elsif ( /(inp|cmd): RCPT TO:\s*([^\s]+)$/i ) { $groupdesc .= "TO: $2\n"; } # look for outgoing rejections elsif ( /(out|rsp): (5\d\d)(\s*.+)$/ ) { # rip off extranious verbiage $match = $2 . $3; $match =~ s/Send your questions.+$//; # if this is a 501, look for repeats indicating a # spam spewer (one that ignores responses) if ( $2 == 501 ) { # bump spew count if we're watching a spammer ignore protocol if ( $groupdesc =~ s/ERR: 501[^\n]+\n$/$spewMsg (2)\n/ ) { $spewCount = 3; } elsif ( $groupdesc =~ s/$spewMsg \(\d+\)\n$/$spewMsg ($spewCount)\n/ ) { ++$spewCount; } else { # first 501 - just report it $groupdesc .= "ERR: $match\n"; } } else { $groupdesc .= "ERR: $match\n"; } # note that this group is interesting push @reportSMPTI, $key; } # map in msg id to smtpi IDs for later tracking elsif( /\[(\d+)\] received, \d+ bytes$/ ) { $inMsgToSMTPIMap{ $1 } = $key; } # put group descriptor into hash $groupSMTPI{$key} = $groupdesc; } # look for rejection by rules elsif ( /^..:..:..... . ENQUEUERRULES \[(\d+)\] rule\((.+)\) rejected the message$/ ) { # retrieve SMTPI ID $key = $inMsgToSMTPIMap{ $1 }; next unless $key; # mark this SMTPI group as interesting now push @reportSMPTI, $key; # tack on to description $groupSMTPI{ $key } .= "RULE: Rejected by rule $2\n"; } # to do - track SMTP outputs that are caused by rule rejections } close IN; # produce the report # make unique file name $time = time(); $outFileName = $submitdir . "lp$time-$$"; if ( $testing ) { $outhand = STDOUT; } else { open( OUT, ">$outFileName.tmp" ) || die "Can't create output file"; $outhand = OUT; } # address the message print $outhand "To: <$ReportToAddress>\n"; print $outhand "From: <$ReportFromAddress>\n"; print $outhand "Subject: CGP log summary for $logname\n\n"; print $outhand "Statistics\n\n"; print $outhand "Queued Messages: $numQueuedMsgs\n"; print $outhand "Incoming SMTP: $numIncomingSMTP\n"; print $outhand "Incoming bytes: $bytesIncomingSMTP\n"; print $outhand "Outgoing SMTP: $numOutgoingSMTP\n"; print $outhand "\n--Bounces--\n\n"; # extract the smtp groups in order @reportSMPTI = sort( @reportSMPTI ); # print each group description foreach $smtp ( @reportSMPTI ) { print $outhand $groupSMTPI{ $smtp }, "\n" unless $lastsmtp == $smtp; $lastsmtp = $smtp; } if ( !$testing ) { close $outhand; #submit message rename( $outFileName . ".tmp", $outFileName . ".sub" ); } exit( 0 );