#!/usr/bin/perl -w # (C) 2003-2007 Willem Jan Hengeveld # Web: http://www.xs4all.nl/~itsme/ # http://wiki.xda-developers.com/ # # $Id: spamstats 1502 2007-04-15 07:54:20Z itsme $ # use strict; # this script provides statistics on all spams bounced for all users on innocent. use Time::localtime; use File::stat; use POSIX 'getuid'; if (getuid()) { exec "sudo $0 @ARGV"; } my @months=qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); my %months= map { $months[$_]=>$_+1 } (0..$#months); # sudo grep -i bounce /var/log/mail.log | perl -ne 'if (/^(\w+\s+\d+).*to=<(.*?)>/) { $x{$1}{$2}++; } END { for my $d (keys %x) { for my $u (keys %{$x{$d}}) { printf("%4d %s %s\n", $x{$d}{$u}, $d, $u) if ($x{$d}{$u}>5 || $u =~ /itsme/); } } }' # Oct 12 06:53:07 innocent postfix/smtpd[11926]: 982D81CD4DC: client=mxzilla1.xs4all.nl[194.109.6.54] # Oct 12 06:53:07 innocent postfix/cleanup[11927]: 982D81CD4DC: message-id=<3F84FD3E00316DAF@mail02.pds.libertysurf.fr> (added by postmaster@libertysurf.fr) # Oct 12 06:53:07 innocent postfix/qmgr[29277]: 982D81CD4DC: from=, size=2214, nrcpt=1 (queue active) # Oct 12 06:53:39 innocent postfix/pipe[11932]: 982D81CD4DC: to=, relay=filter, delay=32, status=bounced (service unavailable. Command output: Message content rejected ) my %msgs; processlogfile("/var/log/mail.log"); processlogfile("/var/log/mail.log.0"); processlogfile("/var/log/mail.log.1.gz"); processlogfile("/var/log/mail.log.2.gz"); processlogfile("/var/log/mail.log.3.gz"); my %stats_date_usr; my %stats_date_usr_status; my %stats_date_status; my %stats_status; for my $msg (sort { $a->{datetime} cmp $b->{datetime} } grep { defined $_->{datetime} } values %msgs) { next if (!defined $msg->{flags} || $msg->{flags}!=3); (my $date= $msg->{datetime}) =~ s/\s\d.*//; $stats_date_usr{$date}{$msg->{to}}++; $stats_date_usr_status{$date}{$msg->{to}}{$msg->{status}}++; $stats_date_status{$date}{$msg->{status}}++; $stats_status{$msg->{status}}++; #next if ($msg->{to} !~ /itsme/); printf("%-8s %s %6d %-20s %s %s\n", $msg->{status}, $msg->{datetime}, $msg->{size}, $msg->{to}, $msg->{from}, $msg->{msgid} || ""); } print "\n"; print "\n"; print "[date] "; for my $s (sort keys %stats_status) { printf(" %s", $s); } print "\n"; for my $d (sort keys %stats_date_usr) { for my $u (sort keys %{$stats_date_usr{$d}}) { next unless ($stats_date_usr{$d}{$u}>5 || $u =~ /itsme/); next if ($u !~ /nah6/); printf("%s ", $d); for my $s (sort keys %stats_status) { printf(" %3d", $stats_date_usr_status{$d}{$u}{$s} || 0); } printf(" %s", $u); print "\n"; } } exit(0); sub processlogfile { my ($fn)= @_; my ($fileyear, $filemonth, $fileday)= getfileymd($fn); open FH, (($fn =~ /\.gz$/) ? "zcat $fn |" : $fn) or die "$fn: $!\n"; my $curyear= $fileyear; while () { chomp; if (/^(\w+)\s+(\d+)/) { my ($month, $day)= ($months{$1}, $2); if ($month > $filemonth) { $curyear= $fileyear-1; } else { $curyear= $fileyear; } } # \w+ = 'innocent' # qmgr\S+ = qmgr[pid] if (/^(\w+)\s+(\d+)\s+(\S+)\s+\w+\s+postfix\/qmgr\S+:\s+(\w+):\s+from=<(.*?)>,\s+size=(\d+)/) { my ($month, $day, $time, $msgid, $from, $size)= ($1, $2, $3, $4, $5, $6, $7, $8); $msgs{$msgid}{datetime} ||= sprintf("%04d-%02d-%02d %s", $curyear, $months{$month}, $day, $time); $msgs{$msgid}{from} = $from; $msgs{$msgid}{size} = $size; $msgs{$msgid}{flags} |= 1; } elsif (/^(\w+)\s+(\d+)\s+(\S+)\s+\w+\s+postfix\/pipe\S+:\s+(\w+):\s+to=<(.*?)>.*status=(\w+)/) { my ($month, $day, $time, $msgid, $to, $status)= ($1, $2, $3, $4, $5, $6); $msgs{$msgid}{datetime} ||= sprintf("%04d-%02d-%02d %s", $curyear, $months{$month}, $day, $time); $msgs{$msgid}{to} = $to; $msgs{$msgid}{status} = $status; $msgs{$msgid}{flags} |= 2; } elsif (/^(\w+)\s+(\d+)\s+(\S+)\s+\w+\s+postfix\/cleanup\S+:\s+(\w+):\s+message-id=<(.*?)>/) { my ($month, $day, $time, $msgid, $messageid)= ($1, $2, $3, $4, $5); $msgs{$msgid}{datetime} ||= sprintf("%04d-%02d-%02d %s", $curyear, $months{$month}, $day, $time); $msgs{$msgid}{msgid} = $messageid; } } close FH; } sub getfileymd { my ($fn)= @_; my $mtime= localtime(stat($fn)->mtime); return (1900+$mtime->year, 1+$mtime->mon, $mtime->mday) }