#!/usr/bin/perl -w # # spamdstats - Gives back rudimentary stats based on spamd logs # # Copyright Clint Byrum, 2003,2004. All Rights Reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # version 0.1 - Initial release # version 0.5 - Suggestion from viz, widening user column for virtual domains # version 0.6 - Adding total messages and spam percentage columns .. ty viz # - Changed name to spamdstats # version 0.7 - Sorting by date # version 0.8 - Sorting by Spam % in user listing # # Month to Digits our %mtd =( 'Jan' => '00' ,'Feb' => '01' ,'Mar' => '02' ,'Apr' => '03' ,'May' => '04' ,'Jun' => '05' ,'Jul' => '06' ,'Aug' => '07' ,'Sep' => '08' ,'Oct' => '09' ,'Nov' => '10' ,'Dec' => '11' ); # Digits to Month our @dtm = ( 'Jan' ,'Feb' ,'Mar' ,'Apr' ,'May' ,'Jun' ,'Jul' ,'Aug' ,'Sep' ,'Oct' ,'Nov' ,'Dec' ); my %cleandates; my %spamdates; my %userspam; my %userclean; my @top5scores; my @top5times; my ($month,$day,$loghost,$daemon); my ($word1,$word2,$scores,$junk,$user,$junk2,$proctime); my $date; my $logtime; my $cleanmsgs=0; my $spams=0; my $linecnt=0; my $timespent=0; my $totalscore=0; my $cleanscore=0; my $spamscore=0; my $maxuserlen=0; while($line=) { ($month,$day,$logtime,$loghost,$daemon,$word1,$word2, $scores,$junk,$user,$junk2,$proctime)=split(' ',$line); # print "DEBUG: m=$month d=$day l=$loghost daemon=$daemon\n"; if($daemon =~ /spamd/) { # yay $date="$month $day"; ($score,$junk)=split('\/',$scores); $score =~ s/^\(//; if($word1 =~ /clean|identified/) { if(length($user) > $maxuserlen) { $maxuserlen = length($user); } $totalscore += $score; $timespent += $proctime; if($word1 =~ /clean/) { $cleanmsgs=$cleanmsgs + 1; $userclean{$user} += 1; $cleandates{&sortabledate($date)} += 1; $cleanscore += $score; } elsif($word1 =~ /identified/) { $spams=$spams + 1; $userspam{$user} += 1; $spamdates{&sortabledate($date)} += 1; $spamscore += $score; } } } $linecnt=$linecnt + 1; } my $totalmsgs=$spams+$cleanmsgs; my $averageptime=$timespent/$totalmsgs; my $averagescore=$totalscore/$totalmsgs; my $avgcleanscore=$cleanscore/$cleanmsgs; my $avgspamscore; if($spams!=0) { $avgspamscore=$spamscore/$spams; } else { $avgspamscore="inf"; } print "Spams Found : $spams"; printf ("\t\tAverage Score: %5.3f\n",$avgspamscore); print "Clean Messages: $cleanmsgs"; printf ("\t\tAverage Score: %5.3f\n",$avgcleanscore); print "Total Messages: $totalmsgs"; printf ("\t\tAverage Score: %5.3f\n",$averagescore); #print "Lines Processed: $linecnt\n"; printf("Time spent: %10.3f\n",$timespent); printf("Average Time: %5.3f\n",$averageptime); print "\n"; #print "------------USERS-------------\n"; # we must adjust maxuserlen down by 2 to reduce the wasted space caused by uids $maxuserlen -= 2; $uheadstr = "%".$maxuserlen."s%10s%10s%10s%9s\n"; $headstr = "%10s%10s%10s%10s%9s\n"; $upfstr = "%".$maxuserlen."s%10d%10d%10d %8.3f\n"; $pfstr = "%10s%10d%10d%10d %8.3f\n"; printf($uheadstr,"User","Spams","Clean","Total","Spam %"); printf($uheadstr,'-'x($maxuserlen-1),'-'x9,'-'x9,'-'x9,'-'x8); # Show users # XXX will only show users who got spam # build spampct hash to be sorted my %userpcts; my $spampct; while(($user,$spams) = each %userspam) { $spams=0 unless defined $spams; $cleanmsgs=$userclean{$user}; $totalmsgs=$spams+$cleanmsgs; if($totalmsgs != 0) { $spampct=($spams/$totalmsgs)*100; } else { $spampct = 'inf'; } $userpcts{$user} = $spampct; } my @sortedusers = sort { $userspam{$b} <=> $userspam{$a} } keys %userspam; foreach $user (@sortedusers) { $spams=$userspam{$user}; $spams=0 unless defined $spams; $cleanmsgs=$userclean{$user}; $cleanmsgs=0 unless defined $cleanmsgs; $spampct=$userpcts{$user}; # Don't do any hash lookups after this next step (strips uid) ($user) = split(/:/,$user); $totalmsgs=$spams+$cleanmsgs; printf($upfstr,$user,$spams,$cleanmsgs,$totalmsgs,$spampct); } print "\n"; #print "------------DATES-------------\n"; printf($headstr,"Date","Spams","Clean","Total","Spam %"); printf($headstr,'-'x9,'-'x9,'-'x9,'-'x9,'-'x8); my @sorteddates = sort { $a cmp $b } keys %spamdates; # XXX Will only show dates that spam was received on #while(($date,$spams) = each %spamdates) { foreach $date (@sorteddates) { $spams=$spamdates{$date}; $cleanmsgs=$cleandates{$date}; #printf "$date\: $spams,$cleanmsgs\n"; $totalmsgs=$spams+$cleanmsgs; if($totalmsgs != 0) { $spampct=($spams/$totalmsgs)*100; } else { $spampct = 'inf'; } printf($pfstr,&dateablesort($date),$spams,$cleanmsgs,$totalmsgs,$spampct); } exit 0; ###### END OF PROGRAM ###### # returns a date suitable for sorting sub sortabledate { my $indate=shift(); my($month,$dom)=split(/ +/,$indate); our %mtd; return $mtd{$month}.sprintf('%02d',$dom); } # reverse the process above sub dateablesort { my $indate=shift(); my $dom=sprintf('%d',substr($indate,2,2)); my $month=sprintf('%d',substr($indate,0,2)); $month=$dtm[$month]; return sprintf('%s %3d',$month,$dom); } sub averagetimes { my @avgarray=@_; my ($total,$counter); foreach $datum (@avgarray) { $total += $datum; $counter++; } return $total / $counter; }