From: Sven Hoexter Date: Tue, 27 May 2025 15:22:27 +0000 (+0200) Subject: New upstream version 1.1.8 X-Git-Tag: upstream/1.1.8^0 X-Git-Url: https://git.sven.stormbind.net/?a=commitdiff_plain;h=489e374308fecddfae7690878fe4a1be70fec6d6;p=sven%2Fpflogsumm.git New upstream version 1.1.8 --- diff --git a/ChangeLog b/ChangeLog index 656ced2..9d1c594 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,104 @@ ChangeLog for pflogsumm http://jimsun.LinxNet.com/postfix_contrib.html.] +rel-1.1.8 20250525 + + Removed the following deprecated options + + --no_bounce_detail + --no_deferral_detail + --no_reject_detail + --no_smtpd_warnings + + pflogsumm no longer accepts underscores ("_") as part of option + names. (Note: this finally addresses four-year-old Bugzilla bug + 1931403.) + + Code cleanup: Changed some variable constants to true constants. + + Added test for reject type "BDAT" (Thanks to Maxim, + admin-at-modum-dot-by, for the heads up.) + + Fixed unitialized $hostID value bug-reported to OpenSUSE. Thanks to + Sven Uebelacker (uebelhacker) for the bug report. + + I *suspect* that, with an earlier fix I applied, that undefined + value will no longer occur, but this fix certainly won't hurt + anything—just in case. + + Added -srs-mung option. Thanks and a tip o' the hat to Tom Hendrikx + (tom-at-whyscreem-dot-net) for the contribution. + +rel-1.1.7 20250524 + + Added parsing for "Recipient address triggers...," as in DISCARD on + recipient actions. + + Improved "deferred" and "bounce" detail + + Added --use-orig-to switch, which causes the value of the "orig_to" + field to be reported, rather than that of the "to" field, when + "orig_to" is present. (This was long-ago requested by Tony Earnshaw + and was overlooked by me. My apologies, Tony.) + + Added --rej-add-to switch, which adds the target email address to + sender and client reject reports. (This was also long-ago requested + by Tony Earnshaw.) + + For client rejects this could have created an ambiguity: If only + either --rej-add-from or --rej-add-to was specified, you'd have + no way of knowing, after-the-fact, which address was reported. + So "<" and ">" have been added, to indicate "from" and "to," + respectively. If both are specified, you get "from -> to." + + Added --colwidth switch, to allow adjustment of report's output width. + (Default remains at 80 columns.) + + N.B.: --verbose-msg-detail overrides + + Now condenses deferrals in a manner similar to bounces. + + Now condenses warnings in a manner similar to reject reports. + + Made count reporting more consistent. Now each reporting section + shows the item count in parenthesis (e.g.: "(nn)") or, if the + count is limited and less than full count, as "(top nn of nn)". + Suggestion by Michael Rasmussen (michael-at-michaelsnet-dot-us), + tho not done in the way he suggested. + + Fixed policyd-spf-perl log line detection. + + Fixed conversation/lost connection while sending/receiving deferral + detection + + Improved "said:" string trimmer to be a mite less aggressive when it + didn't have to be. + + Improved reject report consolidation. + + In Host/Domain Summary: Message Delivery: Changed "sent cnt" to "msg + cnt" since we're talking about messages delivered, not necessarily + "sent," per se. + + Fixed bug in smtpd "disconnect from" parsing and streamlined. + + Removed superfluous additional "bounced" processing + + Caught another warning message + + Catch "Server configuration error" lines. + + Enhanced FQDN/IP addr/domain name parsing (in gimme_domain()): + + . More exhaustive IPv6 address check + . Handles IPv6-mapped-IPv4 addresses + . Properly handles the newer, longer TLDs + . Treats in-addr.arpa and ip6.arpa FQNS like "unknown"s + . More streamlined + + Added pffrombyto and pftobyfrom command-line utilities to the + distribution. (Actually in 1.1.6.) + rel-1.1.6 20250522 Renamed from "pflogsumm.pl" to "pflogsumm" diff --git a/pffrombyto.1 b/pffrombyto.1 index 3a0e77c..fbe0bad 100644 --- a/pffrombyto.1 +++ b/pffrombyto.1 @@ -55,7 +55,7 @@ .\" ======================================================================== .\" .IX Title "PFFROMBYTO 1" -.TH PFFROMBYTO 1 2025-05-22 1.1.6 "User Contributed Perl Documentation" +.TH PFFROMBYTO 1 2025-05-22 1.1.8 "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l diff --git a/pflogsumm b/pflogsumm index cb3b8a9..42a48e3 100755 --- a/pflogsumm +++ b/pflogsumm @@ -6,18 +6,18 @@ eval 'exec perl -S $0 "$@"' pflogsumm - Produce Postfix MTA logfile summary -Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.6 +Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.8 =head1 SYNOPSIS pflogsumm -[eq] [-d ] [--detail ] - [--bounce-detail ] [--deferral-detail ] + [--bounce-detail ] [--colwidth ] [--deferral-detail ] [-h ] [-i|--ignore-case] [--iso-date-time] [--mailq] - [-m|--uucp-mung] [--no-no-msg-size] [--problems-first] - [--rej-add-from] [--reject-detail ] [--smtp-detail ] - [--smtpd-stats] [--smtpd-warning-detail ] - [--syslog-name=string] [-u ] [--verbose-msg-detail] - [--verp-mung[=]] [--zero-fill] [file1 [filen]] + [-m|--uucp-mung] [--no-no-msg-size] [--problems-first] [--rej-add-from] + [--rej-add-to] [--reject-detail ] [--smtp-detail ] + [--smtpd-stats] [--smtpd-warning-detail ] [--srs-mung] + [--syslog-name=string] [-u ] [--use-orig-to] + [--verbose-msg-detail] [--verp-mung[=] [--zero-fill] [file1 [filen]] pflogsumm -[help|version] @@ -41,6 +41,13 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.6 Limit detailed bounce reports to the top . 0 to suppress entirely. + --colwidth + + Maximum report output width. Default is 80 columns. + 0 = unlimited. + + N.B.: --verbose-msg-detail overrides + -d today generate report for just today -d yesterday generate report for just "yesterday" @@ -114,24 +121,6 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.6 is in $PATH. See "$mailqCmd" variable to path thisi if desired.) - --no_bounce_detail - --no_deferral_detail - --no_reject_detail - - These switches are deprecated in favour of - --bounce-detail, --deferral-detail and - --reject-detail, respectively. - - Suppresses the printing of the following detailed - reports, respectively: - - message bounce detail (by relay) - message deferral detail - message reject detail - - See also: "-u" and "-h" for further report-limiting - options. - --no-no-msg-size Do not emit report on "Messages with no size data". @@ -145,15 +134,6 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.6 normally reported by pflogsumm as "Messages with no size data." - --no-smtpd-warnings - - This switch is deprecated in favour of - smtpd-warning-detail - - On a busy mail server, say at an ISP, SMTPD warnings - can result in a rather sizeable report. This option - turns reporting them off. - --problems-first Emit "problems" reports (bounces, defers, warnings, @@ -170,6 +150,11 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.6 note: headings for warning, fatal, and "master" messages will always be printed. + --rej-add-to + + For sender reject reports: Add the intended recipient + address. + --reject-detail Limit detailed smtpd reject, warn, hold and discard @@ -193,6 +178,23 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.6 Limit detailed smtpd warnings reports to the top . 0 to suppress entirely. + --srs-mung + + Undo SRS address munging. + + If your postfix install has an SRS plugin running, many + addresses in the report will contain the SRS-formatted + email addresses, also for non-local adresses (f.i. + senders). This option will try to undo the "damage". + + Addresses of the form: + + SRS0=A6cv=PT=sender.example.com=support@srs.example.net + + will be reformatted to their original value: + + support@sender.example.com + --syslog-name=name Set syslog-name to look for for Postfix log entries. @@ -211,6 +213,11 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.6 See also: "-h" and "--*-detail" options for further report-limiting options. + --use-orig-to + + Where "orig_to" fields are found, report that in place + of the "to" address. + --verbose-msg-detail For the message deferral, bounce and reject summaries: @@ -284,6 +291,8 @@ Copyright (C) 1998-2025 by James S. Seymour, Release 1.1.6 =head1 SEE ALSO + pffrombyto, pftobyfrom + The pflogsumm FAQ: pflogsumm-faq.txt. =head1 NOTES @@ -402,26 +411,26 @@ eval { require Date::Calc }; my $hasDateCalc = $@ ? 0 : 1; my $mailqCmd = "mailq"; -my $release = "1.1.6"; +my $release = "1.1.8"; # Variables and constants used throughout pflogsumm use vars qw( $progName $usageMsg %opts - $divByOneKAt $divByOneMegAt $oneK $oneMeg @monthNames %monthNums $thisYr $thisMon - $msgCntI $msgSizeI $msgDfrsI $msgDlyAvgI $msgDlyMaxI $isoDateTime ); # Some constants used by display routines. I arbitrarily chose to # display in kilobytes and megabytes at the 512k and 512m boundaries, # respectively. Season to taste. -$divByOneKAt = 524288; # 512k -$divByOneMegAt = 536870912; # 512m -$oneK = 1024; # 1k -$oneMeg = 1048576; # 1m +use constant { + DIV_BY_ONE_K_AT => 524288, # 512k + DIV_BY_ONE_MEG_AT => 536870912, # 512m + ONE_K => 1024, # 1k + ONE_MEG => 1048576, # 1m +}; # Constants used throughout pflogsumm @monthNames = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); @@ -440,15 +449,18 @@ my (%sendgUser, $sendgUserCnt); # Per-domain data my (%recipDom, $recipDomCnt); # recipient domain data my (%sendgDom, $sendgDomCnt); # sending domain data + # Indexes for arrays in above -$msgCntI = 0; # message count -$msgSizeI = 1; # total messages size -$msgDfrsI = 2; # number of defers -$msgDlyAvgI = 3; # total of delays (used for averaging) -$msgDlyMaxI = 4; # max delay +use constant { + MSG_CNT_I => 0, # message count + MSG_SIZE_I => 1, # total messages size + MSG_DFRS_I => 2, # number of defers + MSG_DLY_AVG_I => 3, # total of delays (used for averaging) + MSG_DLY_MAX_I => 4, # max delay +}; my ( - $cmd, $qid, $addr, $size, $relay, $status, $delay, + $cmd, $qid, $addr, $orig_to, $size, $relay, $status, $delay, $dateStr, $dateStrRFC3339, %panics, %fatals, %warnings, %masterMsgs, %msgSizes, @@ -490,22 +502,16 @@ for (0 .. 23) { $usageMsg = "usage: $progName -[eq] [-d ] [--detail ] - [--bounce-detail ] [--deferral-detail ] + [--bounce-detail ] [--colwidth ] [--deferral-detail ] [-h ] [-i|--ignore-case] [--iso-date-time] [--mailq] - [-m|--uucp-mung] [--no-no-msg-size] [--problems-first] - [--rej-add-from] [--reject-detail ] [--smtp-detail ] - [--smtpd-stats] [--smtpd-warning-detail ] - [--syslog-name=string] [-u ] [--verbose-msg-detail] + [-m|--uucp-mung] [--no-no-msg-size] [--problems-first] [--rej-add-from] + [--rej-add-to] [--reject-detail ] [--smtp-detail ] + [--smtpd-stats] [--smtpd-warning-detail ] [--srs-mung] + [--syslog-name=string] [-u ] [--use-orig-to] [--verbose-msg-detail] [--verp-mung[=]] [--zero-fill] [file1 [filen]] $progName --[version|help]"; -# Accept either "_"s or "-"s in --switches -foreach (@ARGV) { - last if($_ eq "--"); - tr/_/-/ if(/^--\w/); -} - # Some pre-inits for convenience $isoDateTime = 0; # Don't use ISO date/time formats GetOptions( @@ -521,20 +527,20 @@ GetOptions( "iso-date-time" => \$isoDateTime, "mailq" => \$opts{'mailq'}, "m" => \$opts{'m'}, - "no-bounce-detail" => \$opts{'noBounceDetail'}, - "no-deferral-detail" => \$opts{'noDeferralDetail'}, "no-no-msg-size" => \$opts{'noNoMsgSize'}, - "no-reject-detail" => \$opts{'noRejectDetail'}, - "no-smtpd-warnings" => \$opts{'noSMTPDWarnings'}, "problems-first" => \$opts{'pf'}, "q" => \$opts{'q'}, "rej-add-from" => \$opts{'rejAddFrom'}, + "rej-add-to" => \$opts{'rejAddTo'}, "reject-detail=i" => \$opts{'rejectDetail'}, + "colwidth=i" => \$opts{'colWidth'}, "smtp-detail=i" => \$opts{'smtpDetail'}, "smtpd-stats" => \$opts{'smtpdStats'}, "smtpd-warning-detail=i" => \$opts{'smtpdWarnDetail'}, + "srs-mung" => \$opts{'srsMung'}, "syslog-name=s" => \$opts{'syslogName'}, "u=i" => \$opts{'u'}, + "use-orig-to" => \$opts{'useOrigTo'}, "uucp-mung" => \$opts{'m'}, "verbose-msg-detail" => \$opts{'verbMsgDetail'}, "verp-mung:i" => \$opts{'verpMung'}, @@ -550,24 +556,8 @@ $opts{'deferralDetail'} = -1 unless(defined($opts{'deferralDetail'})); $opts{'smtpDetail'} = -1 unless(defined($opts{'smtpDetail'})); $opts{'smtpdWarnDetail'} = -1 unless(defined($opts{'smtpdWarnDetail'})); $opts{'rejectDetail'} = -1 unless(defined($opts{'rejectDetail'})); - -# These go away eventually -if(defined($opts{'noBounceDetail'})) { - $opts{'bounceDetail'} = 0; - warn "$progName: \"no_bounce_detail\" is deprecated, use \"bounce-detail=0\" instead\n" -} -if(defined($opts{'noDeferralDetail'})) { - $opts{'deferralDetail'} = 0; - warn "$progName: \"no_deferral_detail\" is deprecated, use \"deferral-detail=0\" instead\n" -} -if(defined($opts{'noRejectDetail'})) { - $opts{'rejectDetail'} = 0; - warn "$progName: \"no_reject_detail\" is deprecated, use \"reject-detail=0\" instead\n" -} -if(defined($opts{'noSMTPDWarnings'})) { - $opts{'smtpdWarnDetail'} = 0; - warn "$progName: \"no_smtpd_warnings\" is deprecated, use \"smtpd-warning-detail=0\" instead\n" -} +$opts{'colWidth'} = 0 if($opts{'verbMsgDetail'}); +$opts{'colWidth'} = -1 unless(defined($opts{'colWidth'})); # If --detail was specified, set anything that's not enumerated to it if(defined($opts{'detail'})) { @@ -671,7 +661,8 @@ while(<>) { /\/cleanup\[\d+\]: .*?\b((?:milter-)?reject|warning|hold|discard): (header|body|END-OF-MESSAGE) (.*)$/) == 3) { $rejRmdr =~ s/( from \S+?)?; from=<.*$// unless($opts{'verbMsgDetail'}); - $rejRmdr = string_trimmer($rejRmdr, 64, $opts{'verbMsgDetail'}); + # FIXME: In retrospect: I've no idea where I came up with the magic numbers I pass to this function. + $rejRmdr = string_trimmer($rejRmdr, 64); if($rejSubTyp eq "reject" or $rejSubTyp eq "milter-reject") { ++$rejects{$cmd}{$rejReas}{$rejRmdr} unless($opts{'rejectDetail'} == 0); ++$msgsRjctd; @@ -689,17 +680,38 @@ while(<>) { ++${$msgsPerDay{$revMsgDateStr}}[4]; } elsif($qid eq 'warning') { (my $warnReas = $logRmdr) =~ s/^.*warning: //; - $warnReas = string_trimmer($warnReas, 66, $opts{'verbMsgDetail'}); - unless($cmd eq "smtpd" && $opts{'noSMTPDWarnings'}) { + unless($opts{'verbMsgDetail'}) { + # Condense smtpd and other warnings + $warnReas =~ s/^(Unable to look up (?:MX|NS) host) for .+(: Host not found(?:,try again)?)/$1$2/ || + $warnReas =~ s/^(hostname ).+ (does not resolve to address) [0-9A-F:\.]+$/$1$2/ || + $warnReas =~ s/^(hostname ).+ (does not resolve to address) .+(: hostname nor servname provided, or not known)$/$1$2$3/ || + $warnReas =~ s/^(Unable to look up (?:MX|NS) host ).+ (for (?:Sender address|Client host|Helo command)) .+(: (?:hostname nor servname provided, or not known|No address associated with hostname))$/$1$2$3/ || + $warnReas =~ s/^(malformed domain name in resource data of MX record) for .*$/$1/ || + $warnReas =~ s/^(numeric domain name in resource data of (?:MX|NS) record) for .*$/$1/ || + $warnReas =~ s/^(numeric hostname): .*$/$1/ || + $warnReas =~ s/^(valid_hostname: invalid character) .*$/$1/ || + $warnReas =~ s/^[0-9A-F:\.]+ (address not listed for hostname) .*$/$1/ || + $warnReas =~ s/^[0-9A-F]+: (queue file size limit exceeded)$/$1/ || + $warnReas =~ s/^[^:]+: (SASL (?:LOGIN|PLAIN|CRAM-MD5) authentication failed(?:: Invalid authentication mechanism)?).*$/$1/ || + $warnReas =~ s/^(Illegal address syntax )from .+ (in (?:MAIL|RCPT) command): .*$/$1$2/ || + $warnReas =~ s/^(non-SMTP command) from .+?(: \S+) .*$/$1$2/ || + $warnReas =~ s/^(Connection concurrency limit exceeded: \d+ )from \S+ (for service .+)$/$1$2/ || + $warnReas =~ s/^[0-9A-F:\.]+ (hostname ).+ (verification failed: No address associated with hostname)$/$1$2/ || + $warnReas =~ s/^[\w\.-]+: (RBL lookup error: Host or domain name not found. Name service error )for name=[\w\.-]+ (type=.+: Host not found, try again)$/$1$2/ || + $warnReas =~ s/^.+((?:postfix-)?policyd-spf-perl: process )id \d+: (command time limit exceeded)$/$1$2/ || + $warnReas =~ s/(process .+) pid \d+ (exit status \d+)/$1 $2/; + } + $warnReas = string_trimmer($warnReas, 66); + unless($cmd eq "smtpd" && $opts{'smtpdWarnDetail'} == 0) { ++$warnings{$cmd}{$warnReas}; } } elsif($qid eq 'fatal') { (my $fatalReas = $logRmdr) =~ s/^.*fatal: //; - $fatalReas = string_trimmer($fatalReas, 66, $opts{'verbMsgDetail'}); + $fatalReas = string_trimmer($fatalReas, 66); ++$fatals{$cmd}{$fatalReas}; } elsif($qid eq 'panic') { (my $panicReas = $logRmdr) =~ s/^.*panic: //; - $panicReas = string_trimmer($panicReas, 66, $opts{'verbMsgDetail'}); + $panicReas = string_trimmer($panicReas, 66); ++$panics{$cmd}{$panicReas}; } elsif($qid eq 'reject') { proc_smtpd_reject($logRmdr, \%rejects, \$msgsRjctd, \$rejPerHr[$msgHr], @@ -752,9 +764,8 @@ while(<>) { @{$connTime{$1}} = ($msgYr, $msgMon + 1, $msgDay, $msgHr, $msgMin, $msgSec); } elsif($logRmdr =~ /: disconnect from /) { - my ($pid, $hostID) = $logRmdr =~ /\/smtpd\[(\d+)\]: disconnect from (.+)$/; - if(exists($connTime{$pid})) { - $hostID = gimme_domain($hostID); + my ($pid, $hostID) = $logRmdr =~ /\/smtpd\[(\d+)\]: disconnect from (.+?)( unknown=\d+\/\d+)?( commands=\d+\/\d+)?$/; + if(exists($connTime{$pid}) && ($hostID = gimme_domain($hostID))) { my($d, $h, $m, $s) = Delta_DHMS(@{$connTime{$pid}}, $msgYr, $msgMon + 1, $msgDay, $msgHr, $msgMin, $msgSec); delete($connTime{$pid}); # dispose of no-longer-needed item @@ -768,17 +779,20 @@ while(<>) { ${$smtpdPerDay{$revMsgDateStr}}[1] = 0; ${$smtpdPerDay{$revMsgDateStr}}[2] = 0; } + ${$smtpdPerDay{$revMsgDateStr}}[1] += $tSecs; ${$smtpdPerDay{$revMsgDateStr}}[2] = $tSecs if($tSecs > ${$smtpdPerDay{$revMsgDateStr}}[2]); - unless(${$smtpdPerDom{$hostID}}[0]++) { - ${$smtpdPerDom{$hostID}}[1] = 0; - ${$smtpdPerDom{$hostID}}[2] = 0; + if($hostID){ + unless(${$smtpdPerDom{$hostID}}[0]++) { + ${$smtpdPerDom{$hostID}}[1] = 0; + ${$smtpdPerDom{$hostID}}[2] = 0; + } + ${$smtpdPerDom{$hostID}}[1] += $tSecs; + ${$smtpdPerDom{$hostID}}[2] = $tSecs + if($tSecs > ${$smtpdPerDom{$hostID}}[2]); } - ${$smtpdPerDom{$hostID}}[1] += $tSecs; - ${$smtpdPerDom{$hostID}}[2] = $tSecs - if($tSecs > ${$smtpdPerDom{$hostID}}[2]); ++$smtpdConnCnt; $smtpdTotTime += $tSecs; @@ -797,6 +811,7 @@ while(<>) { $addr =~ s/(@.+)/\L$1/ unless($opts{'i'}); $addr = lc($addr) if($opts{'i'}); $addr = verp_mung($addr); + $addr = srs_mung($addr); } else { $addr = "from=<>" } @@ -811,19 +826,20 @@ while(<>) { $domAddr = $rcvdMsg{$qid} eq "pickup"? $addr : $rcvdMsg{$qid}; } ++$sendgDomCnt - unless(${$sendgDom{$domAddr}}[$msgCntI]); - ++${$sendgDom{$domAddr}}[$msgCntI]; - ${$sendgDom{$domAddr}}[$msgSizeI] += $size; - ++$sendgUserCnt unless(${$sendgUser{$addr}}[$msgCntI]); - ++${$sendgUser{$addr}}[$msgCntI]; - ${$sendgUser{$addr}}[$msgSizeI] += $size; + unless(${$sendgDom{$domAddr}}[MSG_CNT_I]); + ++${$sendgDom{$domAddr}}[MSG_CNT_I]; + ${$sendgDom{$domAddr}}[MSG_SIZE_I] += $size; + ++$sendgUserCnt unless(${$sendgUser{$addr}}[MSG_CNT_I]); + ++${$sendgUser{$addr}}[MSG_CNT_I]; + ${$sendgUser{$addr}}[MSG_SIZE_I] += $size; $sizeRcvd += $size; delete($rcvdMsg{$qid}); # limit hash size } } - elsif((($addr, $relay, $delay, $status, $toRmdr) = $logRmdr =~ - /to=<([^>]*)>, (?:orig_to=<[^>]*>, )?relay=([^,]+), (?:conn_use=[^,]+, )?delay=([^,]+), (?:delays=[^,]+, )?(?:dsn=[^,]+, )?status=(\S+)(.*)$/) >= 4) + elsif((($addr, $orig_to, $relay, $delay, $status, $toRmdr) = $logRmdr =~ + /to=<([^>]*)>, (?:orig_to=<([^>]*)>, )?relay=([^,]+), (?:conn_use=[^,]+, )?delay=([^,]+), (?:delays=[^,]+, )?(?:dsn=[^,]+, )?status=(\S+)(.*)$/) >= 4) { + $addr = $orig_to if($opts{'useOrigTo'} && $orig_to); if($opts{'m'} && $addr =~ /^(.*!)*([^!]+)!([^!@]+)@([^\.]+)$/) { $addr = "$4!" . ($1? "$1" : "") . $3 . "\@$2"; @@ -839,28 +855,28 @@ while(<>) { ++$msgsFwdd; next; } - ++$recipDomCnt unless(${$recipDom{$domAddr}}[$msgCntI]); - ++${$recipDom{$domAddr}}[$msgCntI]; - ${$recipDom{$domAddr}}[$msgDlyAvgI] += $delay; - if(! ${$recipDom{$domAddr}}[$msgDlyMaxI] || - $delay > ${$recipDom{$domAddr}}[$msgDlyMaxI]) + ++$recipDomCnt unless(${$recipDom{$domAddr}}[MSG_CNT_I]); + ++${$recipDom{$domAddr}}[MSG_CNT_I]; + ${$recipDom{$domAddr}}[MSG_DLY_AVG_I] += $delay; + if(! ${$recipDom{$domAddr}}[MSG_DLY_MAX_I] || + $delay > ${$recipDom{$domAddr}}[MSG_DLY_MAX_I]) { - ${$recipDom{$domAddr}}[$msgDlyMaxI] = $delay + ${$recipDom{$domAddr}}[MSG_DLY_MAX_I] = $delay } - ++$recipUserCnt unless(${$recipUser{$addr}}[$msgCntI]); - ++${$recipUser{$addr}}[$msgCntI]; + ++$recipUserCnt unless(${$recipUser{$addr}}[MSG_CNT_I]); + ++${$recipUser{$addr}}[MSG_CNT_I]; ++$dlvPerHr[$msgHr]; ++${$msgsPerDay{$revMsgDateStr}}[1]; ++$msgsDlvrd; # DEBUG DEBUG DEBUG #print STDERR "Delivered: $qid\n"; if($msgSizes{$qid}) { - ${$recipDom{$domAddr}}[$msgSizeI] += $msgSizes{$qid}; - ${$recipUser{$addr}}[$msgSizeI] += $msgSizes{$qid}; + ${$recipDom{$domAddr}}[MSG_SIZE_I] += $msgSizes{$qid}; + ${$recipUser{$addr}}[MSG_SIZE_I] += $msgSizes{$qid}; $sizeDlvrd += $msgSizes{$qid}; } else { - ${$recipDom{$domAddr}}[$msgSizeI] += 0; - ${$recipUser{$addr}}[$msgSizeI] += 0; + ${$recipDom{$domAddr}}[MSG_SIZE_I] += 0; + ${$recipUser{$addr}}[MSG_SIZE_I] += 0; $noMsgSize{$qid} = $addr unless($opts{'noNoMsgSize'}); push(@{$msgDetail{$qid}}, "(sender not in log)") if($opts{'e'}); # put this back later? mebbe with -v? @@ -870,22 +886,37 @@ while(<>) { } elsif($status eq 'deferred') { unless($opts{'deferralDetail'} == 0) { my ($deferredReas) = $logRmdr =~ /, status=deferred \(([^\)]+)/; - unless(defined($opts{'verbMsgDetail'})) { - $deferredReas = said_string_trimmer($deferredReas, 65); - $deferredReas =~ s/^\d{3} //; - $deferredReas =~ s/^connect to //; + if(!defined($opts{'verbMsgDetail'})) { + my ($host, $reason, $moreReason); # More ugliness :/ + unless((($host, $reason) = ($deferredReas =~ /^host (\S+) (?:said|refused to talk to me): ([^(]+)/)) || + (($host, $reason) = ($deferredReas =~ /^(?:delivery temporarily suspended: )?connect to (.+?(?::\d+)?): ([^)]+)$/)) || + (($host, $reason) = ($deferredReas =~ /^cannot (?:append to file|update mailbox) ([^:.]+)[:.] (.+)$/)) || + (($reason, $host, $moreReason) = ($deferredReas =~ /^.*(Name service error )for (?:domain |name=)?([^: ]+):? (.+)$/)) || + (($reason, $host, $moreReason) = ($deferredReas =~ /^((?:conversation|lost connection) )with (\S+) ((?:timed out )?while (receiving|sending) .+)$/)) || + (($reason, $host, $moreReason) = ($deferredReas =~ /^(delivery temporarily suspended: )connect to ([^:]+): (.+)$/)) + ) + { + $host = "unrecognized deferral reason(s)"; + $reason = $deferredReas; + } + + $reason .= $moreReason if($moreReason); # ick + # Finally... + $reason = said_string_trimmer($reason, 66); + ++$deferred{$cmd}{$host}{$reason}; + } else { + ++$deferred{$cmd}{$deferredReas}; } - ++$deferred{$cmd}{$deferredReas}; } ++$dfrPerHr[$msgHr]; ++${$msgsPerDay{$revMsgDateStr}}[2]; ++$msgsDfrdCnt; ++$msgsDfrd unless($msgDfrdFlgs{$qid}++); - ++${$recipDom{$domAddr}}[$msgDfrsI]; - if(! ${$recipDom{$domAddr}}[$msgDlyMaxI] || - $delay > ${$recipDom{$domAddr}}[$msgDlyMaxI]) + ++${$recipDom{$domAddr}}[MSG_DFRS_I]; + if(! ${$recipDom{$domAddr}}[MSG_DLY_MAX_I] || + $delay > ${$recipDom{$domAddr}}[MSG_DLY_MAX_I]) { - ${$recipDom{$domAddr}}[$msgDlyMaxI] = $delay + ${$recipDom{$domAddr}}[MSG_DLY_MAX_I] = $delay } } elsif($status eq 'bounced') { unless($opts{'bounceDetail'} == 0) { @@ -998,10 +1029,10 @@ if(defined($opts{'smtpdStats'})) { print_domain_smtpd_summary(\%smtpdPerDom, $opts{'h'}); } -print_user_data(\%sendgUser, "Senders by message count", $msgCntI, $opts{'u'}, $opts{'q'}); -print_user_data(\%recipUser, "Recipients by message count", $msgCntI, $opts{'u'}, $opts{'q'}); -print_user_data(\%sendgUser, "Senders by message size", $msgSizeI, $opts{'u'}, $opts{'q'}); -print_user_data(\%recipUser, "Recipients by message size", $msgSizeI, $opts{'u'}, $opts{'q'}); +print_user_data(\%sendgUser, "Senders by message count", MSG_CNT_I, $opts{'u'}, $opts{'q'}); +print_user_data(\%recipUser, "Recipients by message count", MSG_CNT_I, $opts{'u'}, $opts{'q'}); +print_user_data(\%sendgUser, "Senders by message size", MSG_SIZE_I, $opts{'u'}, $opts{'q'}); +print_user_data(\%recipUser, "Recipients by message size", MSG_SIZE_I, $opts{'u'}, $opts{'q'}); print_hash_by_key(\%noMsgSize, "Messages with no size data", 0, 1); @@ -1109,30 +1140,32 @@ sub print_recip_domain_summary { local($hashRef) = $_[0]; my($cnt) = $_[1]; return if($cnt == 0); - my $topCnt = $cnt > 0? "(top $cnt)" : ""; + + my $rptCnt = keys %{$hashRef}; + my $topCnt = "(" . ($cnt > 0 && $rptCnt > $cnt? "top $cnt of " : "") . "$rptCnt)"; my $avgDly; print_subsect_title("Host/Domain Summary: Message Delivery $topCnt"); print <{$_}}[$msgCntI]) { - $avgDly = (${$hashRef->{$_}}[$msgDlyAvgI] / - ${$hashRef->{$_}}[$msgCntI]); + if(${$hashRef->{$_}}[MSG_CNT_I]) { + $avgDly = (${$hashRef->{$_}}[MSG_DLY_AVG_I] / + ${$hashRef->{$_}}[MSG_CNT_I]); } else { $avgDly = 0; } printf " %6d%s %6d%s %6d%s %5.1f %s %5.1f %s %s\n", - adj_int_units(${$hashRef->{$_}}[$msgCntI]), - adj_int_units(${$hashRef->{$_}}[$msgSizeI]), - adj_int_units(${$hashRef->{$_}}[$msgDfrsI]), + adj_int_units(${$hashRef->{$_}}[MSG_CNT_I]), + adj_int_units(${$hashRef->{$_}}[MSG_SIZE_I]), + adj_int_units(${$hashRef->{$_}}[MSG_DFRS_I]), adj_time_units($avgDly), - adj_time_units(${$hashRef->{$_}}[$msgDlyMaxI]), + adj_time_units(${$hashRef->{$_}}[MSG_DLY_MAX_I]), $_; last if --$cnt == 0; } @@ -1145,7 +1178,9 @@ sub print_sending_domain_summary { local($hashRef) = $_[0]; my($cnt) = $_[1]; return if($cnt == 0); - my $topCnt = $cnt > 0? "(top $cnt)" : ""; + + my $rptCnt = keys %{$hashRef}; + my $topCnt = "(" . ($cnt > 0 && $rptCnt > $cnt? "top $cnt of " : "") . "$rptCnt)"; print_subsect_title("Host/Domain Summary: Messages Received $topCnt"); @@ -1156,8 +1191,8 @@ End_Of_Sender_Domain_Heading foreach (reverse sort by_count_then_size keys(%$hashRef)) { printf " %6d%s %6d%s %s\n", - adj_int_units(${$hashRef->{$_}}[$msgCntI]), - adj_int_units(${$hashRef->{$_}}[$msgSizeI]), + adj_int_units(${$hashRef->{$_}}[MSG_CNT_I]), + adj_int_units(${$hashRef->{$_}}[MSG_SIZE_I]), $_; last if --$cnt == 0; } @@ -1169,14 +1204,15 @@ sub print_user_data { my($hashRef, $title, $index, $cnt, $quiet) = @_; my $dottedLine; return if($cnt == 0); - $title = sprintf "%s%s", $cnt > 0? "top $cnt " : "", $title; - unless(%$hashRef) { - return if($quiet); - $dottedLine = ": none"; - } else { - $dottedLine = "\n" . "-" x length($title); - } - printf "\n$title$dottedLine\n"; + + my $rptCnt = keys %{$hashRef}; + $title .= " (" . ($cnt > 0 && $rptCnt > $cnt? "top $cnt of " : "") . "$rptCnt)"; + + return unless($rptCnt || ! $quiet); + + $title .= "\n" . "-" x length($title) if($rptCnt); + printf "\n$title\n"; + foreach (map { $_->[0] } sort { $b->[1] <=> $a->[1] || $a->[2] cmp $b->[2] } map { [ $_, $hashRef->{$_}[$index], normalize_host($_) ] } @@ -1277,7 +1313,9 @@ sub print_domain_smtpd_summary { local($hashRef) = $_[0]; my($cnt) = $_[1]; return if($cnt == 0); - my $topCnt = $cnt > 0? "(top $cnt)" : ""; + + my $rptCnt = keys %{$hashRef}; + my $topCnt = "(" . ($cnt > 0 && $rptCnt > $cnt? "top $cnt of " : "") . "$rptCnt)"; my $avgDly; print_subsect_title("Host/Domain Summary: SMTPD Connections $topCnt"); @@ -1365,10 +1403,12 @@ sub walk_nested_hash { my $hashVal2 = (each(%{$hashRef->{$_}}))[1]; keys(%{$hashRef->{$_}}); # "reset" hash iterator unless(ref($hashVal2) eq 'HASH') { - print " (top $cnt)" if($cnt > 0); + my $rptLines = keys %{$hashRef->{$_}}; my $rptCnt = 0; $rptCnt += $_ foreach (values %{$hashRef->{$_}}); - print " (total: $rptCnt)"; + print " ("; + print "top $cnt of " if($cnt > 0 && $rptLines > $cnt); + print "$rptCnt)"; } print "\n"; walk_nested_hash($hashRef->{$_}, $cnt, $level); @@ -1495,16 +1535,16 @@ sub by_domain_then_user { # structured to do this here - but it's either that or the callers # must run through the hashes twice :-(. sub by_count_then_size { - ${$hashRef->{$a}}[$msgCntI] = 0 unless(${$hashRef->{$a}}[$msgCntI]); - ${$hashRef->{$b}}[$msgCntI] = 0 unless(${$hashRef->{$b}}[$msgCntI]); - if(${$hashRef->{$a}}[$msgCntI] == ${$hashRef->{$b}}[$msgCntI]) { - ${$hashRef->{$a}}[$msgSizeI] = 0 unless(${$hashRef->{$a}}[$msgSizeI]); - ${$hashRef->{$b}}[$msgSizeI] = 0 unless(${$hashRef->{$b}}[$msgSizeI]); - return(${$hashRef->{$a}}[$msgSizeI] <=> - ${$hashRef->{$b}}[$msgSizeI]); + ${$hashRef->{$a}}[MSG_CNT_I] = 0 unless(${$hashRef->{$a}}[MSG_CNT_I]); + ${$hashRef->{$b}}[MSG_CNT_I] = 0 unless(${$hashRef->{$b}}[MSG_CNT_I]); + if(${$hashRef->{$a}}[MSG_CNT_I] == ${$hashRef->{$b}}[MSG_CNT_I]) { + ${$hashRef->{$a}}[MSG_SIZE_I] = 0 unless(${$hashRef->{$a}}[MSG_SIZE_I]); + ${$hashRef->{$b}}[MSG_SIZE_I] = 0 unless(${$hashRef->{$b}}[MSG_SIZE_I]); + return(${$hashRef->{$a}}[MSG_SIZE_I] <=> + ${$hashRef->{$b}}[MSG_SIZE_I]); } else { - return(${$hashRef->{$a}}[$msgCntI] <=> - ${$hashRef->{$b}}[$msgCntI]); + return(${$hashRef->{$a}}[MSG_CNT_I] <=> + ${$hashRef->{$b}}[MSG_CNT_I]); } } @@ -1527,37 +1567,36 @@ sub get_datestrs { } # if there's a real domain: uses that. Otherwise uses the IP addr. +# +# N.B.: in-addr.arpa and ip6.arpa FQDNs return IP addrs +# # Lower-cases returned domain name. # -# Optional bit of code elides the last octet of an IPv4 address. -# (In case one wants to assume an IPv4 addr. is a dialup or other -# dynamic IP address in a /24.) -# Does nothing interesting with IPv6 addresses. -# FIXME: I think the IPv6 address parsing may be weak +# Handles IPv4, IPv6, and IPv6-mapped-IPv4 addrs, current-style +# Postfix bracketed IP addrs, and old-style slash-separated IP addrs +# +# N.B.: IP addr checking is not exhaustive +# sub gimme_domain { $_ = $_[0]; - my($domain, $ipAddr); - - # split domain/ipaddr into separates - # newer versions of Postfix have them "dom.ain[i.p.add.ress]" - # older versions of Postfix have them "dom.ain/i.p.add.ress" - unless((($domain, $ipAddr) = /^([^\[]*)\[((?:\d{1,3}\.){3}\d{1,3})\]/) == 2|| - (($domain, $ipAddr) = /^([^\/]*)\/([0-9a-f.:]+)/i) == 2) { - # more exhaustive method - ($domain, $ipAddr) = /^([^\[\(\/]*)[\[\(\/]([^\]\)]+)[\]\)]:?\d*$/; + my $bracketRegex = '([^\s\[]+)\[((?:\d{1,3}\.){3}\d{1,3}|[\da-fA-F:]+(?:::(?:[\da-fA-F:]+)?)?|[\da-fA-F:]+:(?:\d{1,3}\.){3}\d{1,3})\]'; + my $slashSepRegex = '([^\s\/]+)\/((?:\d{1,3}\.){3}\d{1,3}|[\da-fA-F:]+(?:::(?:[\da-fA-F:]+)?)?|[\da-fA-F:]+:(?:\d{1,3}\.){3}\d{1,3})'; + my ($fqdn, $ipaddr); + + print STDERR "dbg: \$_: \"$_\"\n" if(/unknown=0/); + unless((($fqdn, $ipaddr) = /$bracketRegex/i) == 2) { + ($fqdn, $ipaddr) = /$slashSepRegex/i; } - - # "mach.host.dom"/"mach.host.do.co" to "host.dom"/"host.do.co" - if($domain eq "" || $domain eq 'unknown') { - $domain = $ipAddr; - # For identifying the host part on a Class C network (commonly - # seen with dial-ups) the following is handy. - # $domain =~ s/\.\d+$//; + $fqdn = "unknown" unless($fqdn); + $ipaddr = "unknown" unless($ipaddr); + + my $domain; + if($fqdn eq "unknown" || $fqdn =~ /\.(in-addr|ip6)\.arpa$/) { + $domain = $ipaddr; } else { - $domain =~ - s/^(.*)\.([^\.]+)\.([^\.]{3}|[^\.]{2,3}\.[^\.]{2})$/\L$2.$3/; + ($domain = $fqdn) =~ s/^(.*)\.([^\.]+)\.([^\.]{3,15}|[^\.]{2,3}\.[^\.]{2})$/\L$2.$3/; } - + return $domain; } @@ -1566,11 +1605,11 @@ sub adj_int_units { my $value = $_[0]; my $units = ' '; $value = 0 unless($value); - if($value > $divByOneMegAt) { - $value /= $oneMeg; + if($value > DIV_BY_ONE_MEG_AT) { + $value /= ONE_MEG; $units = 'm' - } elsif($value > $divByOneKAt) { - $value /= $oneK; + } elsif($value > DIV_BY_ONE_K_AT) { + $value /= ONE_K; $units = 'k' } return($value, $units); @@ -1597,10 +1636,11 @@ sub adj_time_units { sub said_string_trimmer { my($trimmedString, $maxLen) = @_; + $trimmedString =~ s/^\d{3}([ -]#?\d\.\d\.\d)? //; while(length($trimmedString) > $maxLen) { - if($trimmedString =~ /^.* said: /) { - $trimmedString =~ s/^.* said: //; - } elsif($trimmedString =~ /^.*: */) { + if($trimmedString =~ /^.* said:( \d{3}([ -]#?\d\.\d\.\d)?)? /) { + $trimmedString =~ s/^.* said:( \d{3}([ -]#?\d\.\d\.\d)?)? //; + } elsif($trimmedString =~ /(delivery error|Requested action not taken|Transaction failed|RCPT TO): */) { $trimmedString =~ s/^.*?: *//; } else { $trimmedString = substr($trimmedString, 0, $maxLen - 3) . "..."; @@ -1613,10 +1653,14 @@ sub said_string_trimmer { # Trim a string, if necessary. Add elipses to show it. sub string_trimmer { - my($trimmedString, $maxLen, $doNotTrim) = @_; + my($trimmedString, $maxLen) = @_; - $trimmedString = substr($trimmedString, 0, $maxLen - 3) . "..." - if(! $doNotTrim && (length($trimmedString) > $maxLen)); + unless($opts{'colWidth'} == 0) { + $maxLen += $opts{'colWidth'} - 80 if($opts{'colWidth'} > 0); + if(length($trimmedString) > $maxLen) { + $trimmedString = substr($trimmedString, 0, $maxLen - 3) . "..."; + } + } return $trimmedString; } @@ -1635,7 +1679,6 @@ sub proc_smtpd_reject { my ($logLine, $rejects, $msgsRjctd, $rejPerHr, $msgsPerDay) = @_; my ($rejTyp, $rejFrom, $rejRmdr, $rejReas); my ($from, $to); - my $rejAddFrom = 0; ++$$msgsRjctd; ++$$rejPerHr; @@ -1655,16 +1698,19 @@ sub proc_smtpd_reject { # Next: get the reject "reason" $rejReas = $rejRmdr; unless(defined($opts{'verbMsgDetail'})) { - if($rejTyp eq "RCPT" || $rejTyp eq "DATA" || $rejTyp eq "CONNECT") { # special treatment :-( + if($rejTyp eq "RCPT" || $rejTyp eq "DATA" || $rejTyp eq "CONNECT" || $rejTyp eq "BDAT") { # special treatment :-( # If there are "<>"s immediately following the reject code, that's # an email address or HELO string. There can be *anything* in # those--incl. stuff that'll screw up subsequent parsing. So just # get rid of it right off. - $rejReas =~ s/^(\d{3} <).*?(>:)/$1$2/; - $rejReas =~ s/^(?:\d{3} \d\.\d\.\d )(Protocol error);.*$/$1/; - $rejReas =~ s/^(?:.*?[:;] )(?:\[[^\]]+\] )?([^;,]+)[;,].*$/$1/; + $rejReas =~ s/^(\d{3} (?:\d\.\d\.\d )?<).*?(>:)/$1$2/; + $rejReas =~ s/^(?:\d{3} \d\.\d\.\d )(Protocol error);.*$/$1/; # from Deb 1.1.15-8 + $rejReas =~ s/^.*?[:;] (?:\[[^\]]+\] )?([^;,]+)[;,].*$/$1/; $rejReas =~ s/^((?:Sender|Recipient) address rejected: [^:]+):.*$/$1/; - $rejReas =~ s/(client|Client host|Sender address) .+? blocked/blocked/; + $rejReas =~ s/(client|Client host|Sender address) .+? blocked/blocked/; # from Deb 1.1.15-8 + $rejReas =~ s/^\d{3} \d\.\d\.\d (Server configuration (?:error|problem));.+$/$1/; + # Condense fqrdns.pcre reports + $rejReas =~ s/^Unverified (Client host rejected: Generic - Please relay via ISP).*$/$1/; } elsif($rejTyp eq "MAIL") { # *more* special treatment :-( grrrr... $rejReas =~ s/^\d{3} (?:<.+>: )?([^;:]+)[;:]?.*$/$1/; } else { @@ -1686,8 +1732,8 @@ sub proc_smtpd_reject { (($from) = $rejRmdr =~ /from=<([^>]+)>/) || ($from = "<>"); if(defined($from)) { - $rejAddFrom = $opts{'rejAddFrom'}; $from = verp_mung($from); + $from = srs_mung($from); $from = lc($from) if($opts{'i'}); } @@ -1695,14 +1741,16 @@ sub proc_smtpd_reject { if($rejReas =~ m/^Sender address rejected:/) { # Sender address rejected: Domain not found # Sender address rejected: need fully-qualified address - ++$rejects->{$rejTyp}{$rejReas}{$from}; + my $rejData = $from; + $rejData .= " ($to)" if($opts{'rejAddTo'} && $to); + ++$rejects->{$rejTyp}{$rejReas}{$rejData}; } elsif($rejReas =~ m/^(Recipient address rejected:|User unknown( |$))/) { # Recipient address rejected: Domain not found # Recipient address rejected: need fully-qualified address # User unknown (in local/relay recipient table) #++$rejects->{$rejTyp}{$rejReas}{$to}; my $rejData = $to; - if($rejAddFrom) { + if($opts{'rejAddFrom'}) { $rejData .= " (" . ($from? $from : gimme_domain($rejFrom)) . ")"; } ++$rejects->{$rejTyp}{$rejReas}{$rejData}; @@ -1712,16 +1760,22 @@ sub proc_smtpd_reject { ++$rejects->{$rejTyp}{$rejReas}{$src}; } elsif($rejReas =~ s/^.*?\d{3} (Message size exceeds fixed limit);.*$/$1/) { my $rejData = gimme_domain($rejFrom); - $rejData .= " ($from)" if($rejAddFrom); + $rejData .= " ($from)" if($opts{'rejAddFrom'}); ++$rejects->{$rejTyp}{$rejReas}{$rejData}; } elsif($rejReas =~ s/^.*?\d{3} (Server configuration (?:error|problem));.*$/(Local) $1/) { my $rejData = gimme_domain($rejFrom); - $rejData .= " ($from)" if($rejAddFrom); + $rejData .= " ($from)" if($opts{'rejAddFrom'}); ++$rejects->{$rejTyp}{$rejReas}{$rejData}; } else { # print STDERR "dbg: unknown reject reason $rejReas !\n\n"; my $rejData = gimme_domain($rejFrom); - $rejData .= " ($from)" if($rejAddFrom); + if($opts{'rejAddFrom'} && $opts{'rejAddTo'} && $to) { + $rejData .= " ($from -> $to)"; + } elsif($opts{'rejAddFrom'}) { + $rejData .= " (< $from)"; + } elsif($opts{'rejAddTo'} && $to) { + $rejData .= " (> $to)"; + } ++$rejects->{$rejTyp}{$rejReas}{$rejData}; } } @@ -1746,6 +1800,16 @@ sub verp_mung { return $addr; } +sub srs_mung { + my $addr = $_[0]; + + if(defined($opts{'srsMung'})) { + $addr =~ s/^SRS(?:[01])(?:[=+-])(?:[^=]+=[\w\.]+==)*(?:[^=]+=[^=]+=)([\w\.]+)=(.+)@[\w\.]+$/$2\@$1/i; + } + + return $addr; +} + ### ### Warning and Error Routines ### diff --git a/pflogsumm.1 b/pflogsumm.1 index c22cf4b..1b8dbef 100644 --- a/pflogsumm.1 +++ b/pflogsumm.1 @@ -55,7 +55,7 @@ .\" ======================================================================== .\" .IX Title "PFLOGSUMM 1" -.TH PFLOGSUMM 1 2025-05-22 1.1.6 "User Contributed Perl Documentation" +.TH PFLOGSUMM 1 2025-05-25 1.1.8 "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l @@ -63,18 +63,18 @@ .SH NAME pflogsumm \- Produce Postfix MTA logfile summary .PP -Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.6 +Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.8 .SH SYNOPSIS .IX Header "SYNOPSIS" .Vb 8 \& pflogsumm \-[eq] [\-d ] [\-\-detail ] -\& [\-\-bounce\-detail ] [\-\-deferral\-detail ] +\& [\-\-bounce\-detail ] [\-\-colwidth ] [\-\-deferral\-detail ] \& [\-h ] [\-i|\-\-ignore\-case] [\-\-iso\-date\-time] [\-\-mailq] -\& [\-m|\-\-uucp\-mung] [\-\-no\-no\-msg\-size] [\-\-problems\-first] -\& [\-\-rej\-add\-from] [\-\-reject\-detail ] [\-\-smtp\-detail ] -\& [\-\-smtpd\-stats] [\-\-smtpd\-warning\-detail ] -\& [\-\-syslog\-name=string] [\-u ] [\-\-verbose\-msg\-detail] -\& [\-\-verp\-mung[=]] [\-\-zero\-fill] [file1 [filen]] +\& [\-m|\-\-uucp\-mung] [\-\-no\-no\-msg\-size] [\-\-problems\-first] [\-\-rej\-add\-from] +\& [\-\-rej\-add\-to] [\-\-reject\-detail ] [\-\-smtp\-detail ] +\& [\-\-smtpd\-stats] [\-\-smtpd\-warning\-detail ] [\-\-srs\-mung] +\& [\-\-syslog\-name=string] [\-u ] [\-\-use\-orig\-to] +\& [\-\-verbose\-msg\-detail] [\-\-verp\-mung[=] [\-\-zero\-fill] [file1 [filen]] \& \& pflogsumm \-[help|version] \& @@ -100,6 +100,13 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.6 \& Limit detailed bounce reports to the top . 0 \& to suppress entirely. \& +\& \-\-colwidth +\& +\& Maximum report output width. Default is 80 columns. +\& 0 = unlimited. +\& +\& N.B.: \-\-verbose\-msg\-detail overrides +\& \& \-d today generate report for just today \& \-d yesterday generate report for just "yesterday" \& @@ -173,24 +180,6 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.6 \& is in $PATH. See "$mailqCmd" variable to path thisi \& if desired.) \& -\& \-\-no_bounce_detail -\& \-\-no_deferral_detail -\& \-\-no_reject_detail -\& -\& These switches are deprecated in favour of -\& \-\-bounce\-detail, \-\-deferral\-detail and -\& \-\-reject\-detail, respectively. -\& -\& Suppresses the printing of the following detailed -\& reports, respectively: -\& -\& message bounce detail (by relay) -\& message deferral detail -\& message reject detail -\& -\& See also: "\-u" and "\-h" for further report\-limiting -\& options. -\& \& \-\-no\-no\-msg\-size \& \& Do not emit report on "Messages with no size data". @@ -204,15 +193,6 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.6 \& normally reported by pflogsumm as "Messages with no \& size data." \& -\& \-\-no\-smtpd\-warnings -\& -\& This switch is deprecated in favour of -\& smtpd\-warning\-detail -\& -\& On a busy mail server, say at an ISP, SMTPD warnings -\& can result in a rather sizeable report. This option -\& turns reporting them off. -\& \& \-\-problems\-first \& \& Emit "problems" reports (bounces, defers, warnings, @@ -229,6 +209,11 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.6 \& note: headings for warning, fatal, and "master" \& messages will always be printed. \& +\& \-\-rej\-add\-to +\& +\& For sender reject reports: Add the intended recipient +\& address. +\& \& \-\-reject\-detail \& \& Limit detailed smtpd reject, warn, hold and discard @@ -252,6 +237,23 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.6 \& Limit detailed smtpd warnings reports to the top . \& 0 to suppress entirely. \& +\& \-\-srs\-mung +\& +\& Undo SRS address munging. +\& +\& If your postfix install has an SRS plugin running, many +\& addresses in the report will contain the SRS\-formatted +\& email addresses, also for non\-local adresses (f.i. +\& senders). This option will try to undo the "damage". +\& +\& Addresses of the form: +\& +\& SRS0=A6cv=PT=sender.example.com=support@srs.example.net +\& +\& will be reformatted to their original value: +\& +\& support@sender.example.com +\& \& \-\-syslog\-name=name \& \& Set syslog\-name to look for for Postfix log entries. @@ -270,6 +272,11 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.6 \& See also: "\-h" and "\-\-*\-detail" options for further \& report\-limiting options. \& +\& \-\-use\-orig\-to +\& +\& Where "orig_to" fields are found, report that in place +\& of the "to" address. +\& \& \-\-verbose\-msg\-detail \& \& For the message deferral, bounce and reject summaries: @@ -347,6 +354,8 @@ Copyright (C) 1998\-2025 by James S. Seymour, Release 1.1.6 .SH "SEE ALSO" .IX Header "SEE ALSO" .Vb 1 +\& pffrombyto, pftobyfrom +\& \& The pflogsumm FAQ: pflogsumm\-faq.txt. .Ve .SH NOTES diff --git a/pftobyfrom.1 b/pftobyfrom.1 index 986515e..b41e649 100644 --- a/pftobyfrom.1 +++ b/pftobyfrom.1 @@ -55,7 +55,7 @@ .\" ======================================================================== .\" .IX Title "PFTOBYFROM 1" -.TH PFTOBYFROM 1 2025-05-22 1.1.6 "User Contributed Perl Documentation" +.TH PFTOBYFROM 1 2025-05-22 1.1.8 "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l