#!/usr/bin/perl ## # smreject.pl - processes check_* rejections from sendmail logfile ## # # Ver 2.1 by Ted George (ted@kcnet.com) # Oct 10, 2001 # # smreject.pl reports rejected messages based on the database version # of the check_* rulesets at # http://www.informatik.uni-kiel.de/~ca/email/chk-newmap.html. # # usage: smreject.pl [ -d ] [ -l logfile ] [ -t n ] # # -d print detail # -l full path name to logfile (default /var/log/maillog) # -t print top n addresses (default 10) # require 'getopts.pl'; &Getopts('dl:t:'); # location of the html output file here $output = '/home/www/usmil/html/sendmail/reject.html'; # location of date command $date = '/bin/date'; $printdetail = $opt_d || 0; $top = $opt_t || 10; $logfile = $opt_l || '/var/log/maillog'; $report_date = `$date`; &main(); sub main { &read_logfile(); open(OUTPUT, "> $output") or die "Can't open $output: $!\n"; &print_header(); &summary(); &other_failed(); if ($printdetail) { $title = "Top $top \"Access denied\" rejections"; &pr_detail($title, "Relay_IP/Address", $reason{"Access denied"}, \%deny); $title = "Top $top \"Access denied\" rejections summarized by domain"; &pr_detail($title, "Domain", $reason{"Access denied"}, \%denydomain); $title = "Top $top \"Domain does not resolve/exist\" rejections"; &pr_detail($title, "Domain", $reason{"Domain of sender address does not resolve"} + $reason{"Domain of sender address does not exist"}, \%domainofsender); $title = "Top $top \"Relaying denied\" rejections by email address"; &pr_detail($title, "Address", $reason{"Relaying denied"} + $reason{"Relaying denied. IP name lookup failed"} + $reason{"Relaying denied. IP name possibly forged"} + $reason{"Relaying temporarily denied. Cannot resolve PTR record"}, \%relay); $title = "Top $top \"Relaying denied\" rejections by ip address"; &pr_detail($title, "Relay_IP", $reason{"Relaying denied"} + $reason{"Relaying denied. IP name lookup failed"} + $reason{"Relaying denied. IP name possibly forged"} + $reason{"Relaying temporarily denied. Cannot resolve PTR record"}, \%relayip); } print OUTPUT ""; close(OUTPUT); } sub print_header { print OUTPUT "\n"; print OUTPUT "Sendmail Logfile Rejections\n"; print OUTPUT "\n"; print OUTPUT "
\n"; print OUTPUT "\n"; } sub read_logfile { open(INPUT, "$logfile") or die "Can't open $logfile: $!\n"; while () { $entries++; $datestr = substr($_, 0, 15); $date_from = $datestr unless $date_from; &proc_reject($_) if /, reject=\d+/; $unknown++ if /\.\.\. User unknown$/; $cnt_quota++ if /dsn=5.0.0, stat=Can't create output/; # site specific, probably don't need this if (/, mailer=local, .*, stat=User unknown/) { $to_unknown++ unless /: to=bounce,/; } } close(INPUT); } sub proc_reject { local($_) = shift(); local($reason, $relay); $cnt_check_mail++ if /: ruleset=check_mail, /; $cnt_check_rcpt++ if /: ruleset=check_rcpt, /; $cnt_check_relay++ if /: ruleset=check_relay, /; $reason = $1 if /reject=\d+ \d\.\d\.\d (.*)$/; $relay = $1 if /, relay=.*\[([^\]]+)/; &classify_reason($reason, $relay) if $reason; } sub classify_reason { local($_) = shift(); local($relay) = shift(); local($addr, $domain); if (/Access denied$/) { $reason{"Access denied"}++; $addr = $1 if /^(\<[^\>]+\>)/; $deny{$addr}++ if $addr; $deny{$relay}++ if /: ruleset=check_relay, / and $relay; $domain = $1 if $addr =~ /\@([^\>]+)/; $denydomain{$domain}++ if $domain; } elsif (/^Domain name required/) { $reason{"Domain name required"}++; } elsif (/does not resolve$/) { $reason{"Domain of sender address does not resolve"}++; $addr = $1 if /Domain of sender address (\S+)/; $domain = $1 if $addr =~ /\@([^\>]+)/; $domainofsender{$domain}++ if $domain; } elsif (/does not exist$/) { $reason{"Domain of sender address does not exist"}++; $addr = $1 if /Domain of sender address (\S+)/; $domain = $1 if $addr =~ /\@([^\>]+)/; $domainofsender{$domain}++ if $domain; } elsif (/Relaying denied$/) { $reason{"Relaying denied"}++; $addr = $1 if /^(\<[^\>]+\>)/; $relay{$addr}++ if $addr; $relayip{$relay}++ if $relay; } elsif (/IP name lookup failed/) { $reason{"Relaying denied. IP name lookup failed"}++; $addr = $1 if /^(\<[^\>]+\>)/; $relay{$addr}++ if $addr; $relayip{$relay}++ if $relay; } elsif (/IP name possibly forged/) { $reason{"Relaying denied. IP name possibly forged"}++; $addr = $1 if /^(\<[^\>]+\>)/; $relay{$addr}++ if $addr; $relayip{$relay}++ if $relay; } elsif (/Cannot resolve PTR record/) { $reason{"Relaying temporarily denied. Cannot resolve PTR record"}++; $addr = $1 if /^(\<[^\>]+\>)/; $relay{$addr}++ if $addr; $relayip{$relay}++ if $relay; } elsif (/Mailbox disabled for this recipient/) { $reason{"Mailbox disabled for this recipient"}++; } else { $reason{"Other"}++; # print "$_\n"; } } sub summary { local(@_); print OUTPUT "\n"; } sub other_failed { local(@_); print OUTPUT "\n"; } sub pr_detail { local($title) = shift(); local($heading) = shift(); local($count) = shift(); local($hashref) = @_[$[]; local(@table); print OUTPUT "\n"; } sub commas { local($_) = shift() || 0; 1 while s/(.*\d)(\d\d\d)/$1,$2/; $_; } sub fixhtml { local($_) = shift(); s/ /_/g; s/\n"; foreach (@_) { @row = split(); print OUTPUT "\n"; for ($i = 0; $i < $cols; $i++) { @row[$i] =~ s/_/ /g; print OUTPUT "@row[$i]" if substr($align, $i, 1) eq 'l'; print OUTPUT " align=\"right\">@row[$i]" if substr($align, $i, 1) eq 'r'; print OUTPUT " align=\"center\">@row[$i]" if substr($align, $i, 1) eq 'c'; print OUTPUT "" if $firstrow and $headings; print OUTPUT "" unless $firstrow and $headings; } $firstrow = 0; print OUTPUT "\n"; } print OUTPUT "

Sendmail Rejected Messages
"; print OUTPUT "for $date_from - $datestr

"; print OUTPUT "

Report generated by smreject.pl on $report_date"; print OUTPUT "


check_* rejections by reason for rejection

"; $_ = &commas($entries); push(@_, "Total_logfile_entries_processed $_"); sub reason_values { $reason{$b} <=> $reason{$a}; } foreach $key (sort reason_values (keys(%reason))) { $_ = &commas($reason{$key}); $key =~ s/ /_/g; push(@_, "$key $_"); } $_ = &commas($cnt_check_mail); push(@_, "Total_check_mail_rejections $_"); $_ = &commas($cnt_check_rcpt); push(@_, "Total_check_rcpt_rejections $_"); $_ = &commas($cnt_check_relay); push(@_, "Total_check_relay_rejections $_"); print_table(1, 80, 0, 2, 'lr', @_); print OUTPUT "

Other failed deliveries

"; $_ = &commas($unknown); push(@_, "Attempts_to_unknown_users_(not_denied) $_") if $unknown; $_ = &commas($to_unknown); push(@_, "Procmail_filter_rejections $_") if $to_unknown; $_ = &commas($cnt_quota); push(@_, "Can't_create_output_(message_exceeded_quota) $_") if $cnt_quota; print_table(1, 80, 0, 2, 'lr', @_); print OUTPUT "

$title

"; push(@table, "$heading Count %Total"); sub hashvalues { $hashref->{$b} <=> $hashref->{$a}; } $i = 0; foreach $key (sort hashvalues (keys(%$hashref))) { $i++; $percent = sprintf("%6.2f%s", $hashref->{$key} / $count * 100, "%"); $skey = fixhtml($key); $_ = &commas($hashref->{$key}); push(@table, "$skey $_ $percent"); last if $i >= $top; } print_table(1, 80, 1, 3, 'lrr', @table); print OUTPUT "

\n"; }