#!/usr/bin/perl #============================================================================== # # SCRIPT: BMS - Bad Mail Stats # # AUTHOR: Peter Sundstrom (c)2002-2004. # # SOURCE: http://www.ginini.com/software/bms/ # #============================================================================== use strict; use Getopt::Long; # For processing options my $VERSION='1.1.1'; my $log='/var/log/mail.log'; # Default mail log my $top=10; # Default number of entries for the summaries my $interval=1000; # Verbose output every interval lines my $gzip='/bin/gzip'; # Location of gzip binary # # Process arguments # Getopt::Long::config("bundling"); my %opt; GetOptions( \%opt, 'd', 'detail', 'h', 'html', 'i=s', 'ignore=s', 'l=s', 'log=s', 'm=s', 'match=s', 'o=s', 'output=s', 't=i', 'top=i', 'v', 'verbose', 'w=i', 'width=i', ) or Usage(); my $logfile = $log; if ($opt{l} or $opt{log}) { $log = $opt{l} if $opt{l}; $log = $opt{log} if $opt{log}; if ($log eq '-') { $logfile = "-"; } else { die "$log does not exist\n" unless -f $log; if ($log =~ /\.gz$/) { $logfile = "$gzip -dc $log|"; } else { $logfile = $log; } } } # # Redirect STDOUT to output file (if specified) # my $output; $output=$opt{o} if $opt{o}; $output=$opt{output} if $opt{output}; open(STDOUT,">$output") or die "Can not open $output $!\n" if $output; my ($detail,$detail_lines); $detail=1 if ($opt{d} or $opt{detail}); my $html; $html=1 if ($opt{h} or $opt{html}); my $ignore; $ignore=$opt{i} if $opt{i}; $ignore=$opt{ignore} if $opt{ignore}; my $match; $match=$opt{m} if $opt{m}; $match=$opt{match} if $opt{match}; $top=$opt{t} if $opt{t}; $top=$opt{top} if $opt{top}; my $width; $width=$opt{w} if $opt{w}; $width=$opt{width} if $opt{width}; my $verbose; $verbose=1 if ($opt{v} or $opt{verbose}); # # Initialise counters # my $entries = 0; my $lines = 0; my $matches=0; my $ignores=0; my (%relays,%errcodes,%hosts,%ips,%messages); my ($startdate,$enddate); open LOG,$logfile or die "Can not open $logfile $!\n"; while () { $lines++; if ($verbose) { print STDERR "Processed $lines lines. Matched $entries entries\n" if ($lines % $interval == 0); } next unless (/sendmail|-mta/ and /reject=/i); # # Ignore entries # if ($ignore) { if (/$ignore/) { $ignores++; next; } } # # Match entries # if ($match) { unless (/$match/) { $matches++; next; } } chomp; my ($date,$relay,$errcode,$message) = /^(.*\d+:\d+\d+) .*relay=(.*), reject=(\d+) \S+ (.*)/; # # Relay entries can have the hostname if it is resolvable # my ($host,$ip); if ($relay =~ /[a-z]/ and $relay !~ /@/) { ($host,$ip) = $relay =~ /(\S+) \[(\S+)\]/; } else { $host='unresolved'; ($ip) = $relay =~ /\[(\S+)\]/; } # # Set size of message if specified # $message = substr($message,0,$width) if $width; # # Encode characters HTML characters # if ($html) { $message =~ s/$date$errcode$relay$message\n); } else { print "$date\t$errcode\t $relay\t$message\n"; } } } if ($html) { HTMLheader(); } else { Header(); } Summarize("SMTP Error Codes", \%errcodes,"SMTP Code"); Summarize("Relay Hosts",\%relays,"Server"); Summarize("Relay Hosts by Hostname",\%hosts,"Server"); Summarize("Relay Hosts by IP Address",\%ips,"Server"); Summarize("Reject Messages",\%messages,"Message"); # # Print footer # if ($html) { print qq(

Bad Mail Stats

Version: $VERSION
\n); print qq(\n); } else { print "\n\nbms (version: $VERSION)\n"; } #------------------------------------------------------------------------------ sub Header { my $date = localtime(); print < BMS
BMS - Bad Mail Stats

Date run:$date
Date range:$startdate - $enddate
Lines processed:$lines
Entries matched:$entries

EOF if ($detail) { print qq(\n); print qq(\n); print $detail_lines; print qq(
DateCodeRelay HostMessage
\n); } } #------------------------------------------------------------------------------ sub Summarize { my ($title,$href,$description) = @_; if ($html) { print qq(

$title

\n); print qq(\n); print qq(\n); } else { print "\n$title\n"; print '=' x length($title) . "\n"; } my $count=1; # # Sort in descending order on number of matches # foreach my $entry (sort { $href->{$b} <=> $href->{$a} } keys %$href) { last if ($count > $top); if ($html) { print qq(\n); } else { printf("%4d - %s\n", $href->{$entry},$entry); } $count++; } print "
Count$description
$href->{$entry}$entry
\n" if $html; } #------------------------------------------------------------------------------ sub Usage { print <] [-l ] [-m ] [-o ] [-t ] [-w ] -d --detail Show details of each entry -h --html Produce HTML output -i --ignore Ignore entries matching specified regex -l --log Read from specified log (Default: $log) -m --match Include entries matching specified regex -o --output Output to specified file -t --top Number of entries in the summary (Default: $top) -v --verbose Verbose output -w --width Maximum width of message EOF exit 1; }