Hi, I have written a perl script called Analyze that will run through sendmail's log files and pull out information regarding Infected mails captured by ClamAV. I wrote this script as we needed greater visibilty of what ClamAV was dropping and I couldn't find anything that would give me the info I required.
By default it will run through the /var/log/maillog and print the full message headers for each infected mail and then print a summary of the Virus detected. It has other options including the ability to: 1. Display Top Email Sender addresses 2. Display Top Relay Servers sending Infected mails 3. Display only Virus Summary 4. Can be pointed at any logfile you desire 5. Can search through logfile for specific Msg ID and show headers of that mail. I have included source code below. Please be gentle as I am relatively new to PERL scripting, but any enhancements or fixes you can recommend will be greatly appreciated. If anyone finds this script useful please let me know ). David Wells ------------------Analyze----------------------------------------------- ------ #!/usr/bin/perl # Analyze by D J Wells # # 16/06/05 # # # This script processes Sendmail log files and prints the full message headers # from infected mails identified by ClamAV in a Human Readable format. It then # attempts to catalogue# each diffrent type of Virus and print out a summary # of viruses encountered. # Mangle the variables above the warning to your liking, but it would be # adviseable not to venture past the warning unless you know a # bit of perl and are comfortable doing so. # # # CHANGELOG # # 17/06/05 0.1.1 Added New Disply functions for Virus Count to display in Decending order # 17/06/05 0.1.2 Added ability to search for specific msgid in any logfile and print headers # 17/06/05 0.1.3 Added help functionality # 17/06/05 0.1.4 Added --viruscount functionality # 17/06/05 0.1.5 Added total to --viruscount functionality # 20/06/05 0.1.6 Added --from functionality (Had to add the Email::Address pkg to pull the email address from the string) # 20/06/05 0.1.7 Added --relay functionality # # use strict; use Email::Address; my $ver = "v0.1.7"; our $logfile = "/var/log/maillog"; my $searchstring = "Infected"; print " Argument 1: $ARGV[0]\n"; print " Argument 2: $ARGV[1]\n"; ######################################################################## # DO NOT MUCK AROUND BELOW THIS POINT UNLESS YOU KNOW WHAT YOU'RE DOING ######################################################################## my $counter = 0 ; my @log; my @infected; my %virus = (); my $infected; our $msgid; our $msgid_set = 0 ; my $infectedinst; my $key; my $viruscount; our $total; our $from_set = 0; our $relay_set = 0; my $addr_spec = $Email::Address::addr_spec; our %email_addresses; our %relay; #print "email_address_regexp: $addr_spec\n"; if( ($ARGV[0] =~ /--logfile=(.*)/i or $ARGV[1] =~ /--logfile=(.*)/i) ) { $logfile = "$1"; print "User Input: Logfile = $logfile \n"; } if( ($ARGV[0] =~ /--msgid=(.*)/i or $ARGV[1] =~ /--msgid=(.*)/i) ) { $msgid = $1; $msgid_set = "1"; print "User Input: msgid = $msgid \n"; } if( ($ARGV[0] =~ /--viruscount/i or $ARGV[1] =~ /--viruscount/i) ) { $viruscount = "1"; } if( ($ARGV[0] =~ /--from/i or $ARGV[1] =~ /--from/i) ) { $from_set = "1"; } if( ($ARGV[0] =~ /--relay/i or $ARGV[1] =~ /--relay/i) ) { $relay_set = "1"; } if( ($ARGV[0] =~ /--help/i or $ARGV[1] =~ /--help/i) ) { print "------Analyze $ver by D Wells------------\n"; print "\tHelp Menu\n"; print "\t--from* #Don't print message headers just print summary of email addresses used to send infected mail\n"; print "\t--relay* #Don't print message headers just print summary of hosts used to send infected mails\n"; print "\t--viruscount* #Don't print message headers just print summary of viruses encountered\n"; print "\t--msgid=<msgid>* #look up specific message headers for certain msgid\n"; print "\t--logfile=<logfile> #point analyze to diffrent logfile Default:/var/log/maillog\n"; print "\t--help #print this help menu\n"; print "\n"; print "\tNOTE: Options with a * are mutually exclusive and cannot be run together on same command line.\n"; exit; } print " Log: $logfile\n"; open ("LOG", "<$logfile") || die ( "$!"); while( <LOG> ) { chomp(); push( @log, $_ ); if($msgid_set == 0) { if( $_ =~ /$searchstring/ ) { push( @infected, $_ ); } #endif } #endif } #endwhile print "Import finished\n"; close ( "LOG" ); if($msgid_set == 1) { print " Infected Message: $msgid\n "; print "----------------------------------------------------------------------- -------------------\n"; foreach( @log ) { chomp(); #print "msgid2 = $msgid"; if( $_ =~ /$msgid/ ) { print "$_\n"; } #endif } #endforeach exit } #endif if( $viruscount == 1 ) { foreach(@infected) { if( /Infected\swith\s(.*)/ ) { $virus{$1}++; } #endif }#endforeach print "\n\n\t ---- Virus Count ---- \n"; $counter = 1; $total = 0; foreach $key (sort hashValueDescendingNum (keys(%virus))) { print "\t$counter:\t$virus{$key} \t\t$key\n"; $total += $virus{$key}; $counter++; }#endforeach print "\tTotal:\t$total \n"; exit }#endif if( $from_set == 1 ) { foreach( @infected ) { #print "infected: $_ \n"; my $infectedinst = $_; if ( $infectedinst =~ /^\w*\s\d*\s\d\d:\d\d:\d\d\s\w*\s\w*\[\d*\]:\s(\w*)/ ) { our $msgid = $1; #print "msgid = $msgid\n"; } #endif $counter++; foreach( @log ) { chomp(); if( $_ =~ /$msgid/ ) { #print "variable = $_\n"; if ( $_ =~ /^\w*\s\d*\s\d\d:\d\d:\d\d\s\w*\s\w*\[\d*\]:\s\w*:\sfrom..($addr_spec)/) { #our $from = $1; #print "from = $from\n"; $email_addresses{$1}++; } #endif } #endif } #endforeach } #endforeach print "\n\n\t ---- Email Addresses Count ---- \n"; $counter = 1; foreach $key (sort hashValueDescendingEmailAddress (keys(%email_addresses))) { print "\t$counter:\t$email_addresses{$key} \t\t$key\n"; $counter++; }#endforeach exit }#endif if( $relay_set == 1 ) { foreach( @infected ) { #print "infected: $_ \n"; my $infectedinst = $_; if ( $infectedinst =~ /^\w*\s\d*\s\d\d:\d\d:\d\d\s\w*\s\w*\[\d*\]:\s(\w*)/ ) { our $msgid = $1; #print "msgid = $msgid\n"; } #endif $counter++; foreach( @log ) { chomp(); if( $_ =~ /$msgid/ ) { #print "variable = $_\n"; if ( $_ =~ /relay=(.*?\s)/) { #our $relay = $1; #print "relay = $relay\n"; $relay{$1}++; } #endif } #endif } #endforeach } #endforeach print "\n\n\t ---- Relay Host Count ---- \n"; $counter = 1; foreach $key (sort hashValueDescendingRelay (keys(%relay))) { print "\t$counter:\t$relay{$key} \t\t$key\n"; $counter++; }#endforeach exit }#endif foreach( @infected ) { #print "infected: $_ \n"; my $infectedinst = $_; if ( $infectedinst =~ /^\w*\s\d*\s\d\d:\d\d:\d\d\s\w*\s\w*\[\d*\]:\s(\w*)/ ) { our $msgid = $1; } #endif $counter++; print " Infected Message No: $counter\n "; print "----------------------------------------------------------------------- -------------------\n"; foreach( @log ) { chomp(); if( $_ =~ /$msgid/ ) { print "$_\n"; } #endif } #endforeach if( $infectedinst =~ /Infected\swith\s(.*)/ ) { $virus{$1}++; } #endif print "\n"; } #endforeach print "\n\n\t ---- Virus Count ---- \n"; $counter = 1; $total = 0; foreach $key (sort hashValueDescendingNum (keys(%virus))) { print "\t$counter:\t$virus{$key} \t\t$key\n"; $total += $virus{$key}; $counter++; }#endforeach print "\tTotal:\t$total \n"; #for my $virus1 ( sort keys %virus ) #{ # $counter++; # print "\t $counter: \t $virus1: \t\t\t\t $virus{$virus1} \n"; #} #endfor #----------------------------------------------------------------------# # FUNCTION: hashValueAscendingNum # # # # PURPOSE: Help sort a hash by the hash 'value', not the 'key'. # # Values are returned in ascending numeric order (lowest # # to highest). # #----------------------------------------------------------------------# sub hashValueAscendingNum { $virus{$a} <=> $virus{$b}; } #----------------------------------------------------------------------# # FUNCTION: hashValueDescendingNum # # # # PURPOSE: Help sort a hash by the hash 'value', not the 'key'. # # Values are returned in descending numeric order # # (highest to lowest). # #----------------------------------------------------------------------# sub hashValueDescendingNum { $virus{$b} <=> $virus{$a}; } #----------------------------------------------------------------------# # FUNCTION: hashValueDescendingEmailAddress # # # # PURPOSE: Help sort a hash by the hash 'value', not the 'key'. # # Values are returned in descending numeric order # # (highest to lowest). # #----------------------------------------------------------------------# sub hashValueDescendingEmailAddress { $email_addresses{$b} <=> $email_addresses{$a}; } #----------------------------------------------------------------------# # FUNCTION: hashValueDescendingRelay # # # # PURPOSE: Help sort a hash by the hash 'value', not the 'key'. # # Values are returned in descending numeric order # # (highest to lowest). # #----------------------------------------------------------------------# sub hashValueDescendingRelay { $relay{$b} <=> $relay{$a}; ______________________________________________________________________ This email has been scanned by the MessageLabs Email Security System. For more information please visit http://www.messagelabs.com/email ______________________________________________________________________ _______________________________________________ http://lurker.clamav.net/list/clamav-users.html