File: //ibin/smtpstats
#!/bin/sh
# -------------------------------------------------------------
# Copyright (c) 1991 Regents of the University of Michigan.
# All rights reserved.
#
# Redistribution and use is permitted provided that this notice
# is preserved and that due credit is given to the University of
# Michigan. The name of the University may not be used to endorse
# or promote products derived from this software without specific
# prior written permission. This software is provided "as is"
# without express or implied warranty.
#
# Mail Statistics gatherer
# Author: Bryan Beecher
# Last Modified: 10/17/94
# -------------------------------------------------------------
LOGDIR=/var/log
MAILLOGFILE=maillog
ALIASFILE=/etc/aliases
TEMPFILE=/usr/tmp/.mtool.$$
COUNT=150
FROM=/usr/tmp/from.$$
VIA=/usr/tmp/via.$$
TO=/usr/tmp/to.$$
ERRORS=/usr/tmp/errors.$$
#ERRORSTO=put@your.admin.address.here
ERRORSTO=jack@innovativeinternet.com
TESTMODE=0
# -------------------------------------------------------------
# set things up
# -------------------------------------------------------------
PATH=:/bin:/usr/bin:/usr/ucb
rm -f $TEMPFILE $FROM $VIA $TO $ERRORS
trap "rm -f $TEMPFILE $FROM $VIA $TO $ERRORS ; exit 0" 0 1 2 3 15
# -------------------------------------------------------------
# handle arguments
# -------------------------------------------------------------
# -c count
# Specify the top-N numbers to show in each section of
# the report.
#
# -y
# Do stats for yesterday, not today
#
# -t test mode
# -------------------------------------------------------------
while [ $# != 0 ] ; do
case "$1" in
-c)
COUNT=$2
shift
;;
-t)
TESTMODE=1
;;
esac
shift
done
# -------------------------------------------------------------
# Dice up the lines the way we want
# -------------------------------------------------------------
cd $LOGDIR
if [ ! -s $MAILLOGFILE ] ; then
exit 0
fi
cat $MAILLOGFILE | egrep "sendmail" |
egrep -v "starting daemon|alias database|$ALIASFILE|gethostbyaddr|programs|setsender|return to
sender" |
egrep -v "SYSERR|User unknown|protocol error|timeout waiting|lost input channel|unexpected
close|Unbalanced" |
egrep -v "Address contained invalid control characters|File exists|grew worklist" |
tr A-Z a-z | egrep -v " expn | vrfy " |
awk '
$6 == "finis," { next; }
$7 == "done" { next; }
$7 == "alias" { next; }
$7 == "clone" { next; }
$7 == "forward" { next; }
$6 == "connect" { next; }
$7 == "aliases," && $8 == "longest" { next; }
$7 == "mail" && substr($8, 1, 5) == "from:" { next; }
$8 == "try" { next; }
$(NF-2) == "user" && $(NF-1) == "address" && $NF == "required" { next; }
$6 == "possible" && $7 == "attack" { next; }
$7 ~ /from=.*/ {
#
# Split up the line using the commas
#
n = split($0, part, ",")
#
# Pick off the host that sent this mail
# to be used later.
#
m = split(part[1], from, " ")
host = from[m]
if (substr(from[m], 1, 5) == "from=")
host = substr(from[m], 6)
else {
host = "user@horribly-mangled-address"
}
#
# Increment our bytes handled counter.
#
bytes += substr(part[2], 7)
#
# Increment our recipients handled counter.
#
recipients += substr(part[5], 9)
#
# Record who (directly) sent us this message.
# Look for user@localhost form.
#
if (substr(part[n], 1, 6) == " relay") {
viahost = substr(part[n], 8)
m = split(viahost, relay, " ")
m = split(relay[1], junk, "@")
if (m > 1)
viahost = junk[2]
else if (relay[1] == "[response]")
viahost = localhost
else
viahost = relay[1]
if (viahost == "localhost")
viahost = localhost
print viahost >f4
}
#
# Where is this mail from? Handle the easy cases first, and
# then handle the nasty ones.
#
if (host == "mailer-daemon") {
print localhost >f1
next
}
if (viahost == localhost) {
print localhost >f1
next
}
if ((viahost == "local" || viahost == localhost) && host == "news") {
print localhost >f1
next
}
#
# Can be <blah> or <blah, woof>
# We just want blan.
#
if (substr(host, 1, 1) == "<")
host = substr(host, 2)
if (substr(host, length(host)) == ">")
host = substr(host, 1, length(host) - 1)
#
# Correct for user@domain(First Last) lines
#
i = split(host, tmp, "(")
if (i > 1)
host = tmp[1]
#
# Handle from=<>
#
if (length(host) == 0) {
print "NULL sender" >f1
next
}
i = split(host, bangs, "!")
j = split(host, ats, "@")
k = split(host, pers, "%")
l = split(host, routes, ":")
#
# if it contains quotes and a @-sign
# we sort of bail out here
m = split(host, quotes, "\"");
if ((m > 1) && (j > 1)) {
print ats[j] >f1
next
}
#
# from=foo, but not handled above
#
if (i == 1 && j == 1 && k == 1) {
print viahost >f1
next
}
#
# site!...!SITE!user
#
if (i > 1 && j == 1 && k == 1 && l == 1) {
print bangs[i - 1] >f1
next
}
#
# some-stuff@DOMAIN
#
if (j == 2) {
print ats[2] >f1
next
}
#
# user%DOMAIN...@domain
#
if (i == 1 && j == 2 && k >= 2 && l == 1) {
n = split(ats[1], tmp, "%")
print tmp[2] >f1
next
}
#
# @domain:god-knows-what@DOMAIN
#
if (l == 2 && j >= 3) {
print ats[j] >f1
next
}
#
# site!...!user%DOMAIN
# site!...!%DOMAIN!user
#
if (i >= 2 && j == 1 && k == 2 && l == 1) {
n = split(pers[2], tmp, "!")
if (n == 1)
print pers[2] >f1
else
print tmp[1] >f1
next
}
#
# foo@foo@DOMAIN
#
if (j > 2) {
print ats[j] >f1
next
}
print "from=" host, "line=", $0 >errors
next
}
$7 ~ /to=.*/ {
#
# Only interested in delivered mail.
#
comma_parts = split($0, parts, ",")
m = split(parts[comma_parts], status, " ")
if (status[1] != "stat=sent") {
next
}
count++
#
# Pick off the receiving host for later use.
#
split($7, part, ",")
if (part[1] == "to=<") {
split($8, part, ",")
host = part[1]
}
else
host = substr(part[1], 4)
if (substr(host, 1, 1) == "<")
host = substr(host, 2)
while (substr(host, 1, 1) == " ")
host = substr(host, 2)
if (substr(host, length(host)) == ">")
host = substr(host, 1, length(host) - 1)
#
# Record delay if delivered.
# And count delivered messages.
#
for (i = 1; i <= comma_parts; i++) {
if (substr(parts[i], 1, 5) == " dela") {
time = substr(parts[i], 8)
break
}
}
# time = substr(time, 1, length(time) - 1)
n = split(time, dly, ":")
delay = (dly[1] * 3600) + (dly[2] * 60) + dly[3]
i = split(host, bangs, "!")
j = split(host, ats, "@")
k = split(host, pers, "%")
l = split(host, routes, ":")
#
# if it contains quotes and a @-sign
# we sort of bail out here
m = split(host, quotes, "\"");
if ((m > 1) && (j > 1)) {
print ats[j] >f2
next
}
#
# user [ local mail ]
#
if (i == 1 && j == 1 && k == 1 && l == 1) {
print localhost, delay > f2
next
}
#
# site!...!SITE!user
#
if (i > 1 && j == 1 && k == 1 && l == 1) {
print bangs[i - 1], delay >f2
next
}
#
# foo@foo@foo[@foo...]
#
if (j > 2) {
print ats[j], delay >f2
next
}
#
# stuff@DOMAIN
#
if (j == 2) {
print ats[2], delay >f2
next
}
#
# @domain:user@DOMAIN
#
if (i == 1 && j == 3 && k == 1 && l == 2) {
print ats[3], delay >f2
next
}
#
# @domain:...%DOMAIN@domain
#
if (i >= 1 && j >= 1 && k >= 2 && l == 2) {
n = split(routes[k], tmp, "@")
print tmp[1], delay >f2
next
}
#
# site!...!user%DOMAIN
# site!...!%DOMAIN!user
#
if (i > 2 && j == 2 && k == 1 && l == 1) {
print bangs[i - 2], delay >f2
next
}
#
# site!...!user%DOMAIN
# site!...!%DOMAIN!user
#
if (i >= 2 && j == 1 && k == 2 && l == 1) {
n = split(pers[2], tmp, "!")
if (n == 1)
print pers[2], delay >f2
else
print tmp[1], delay >f2
next
}
print "to=" host, "delay=" delay, "line=" $0 >errors
next
}
{
#
# Did not recognize this
#
print "Did not recognize this =>", $0 >errors
}
END {
if ((count + bytes + recipients) > 0) {
printf("\n")
printf("Total messages handled: %5d\n", count)
printf("Total recipients handled: %5d\n", recipients)
printf("Total bytes handled: ")
if (bytes > 1000000)
printf("%5.2fM\n", bytes / 1000000)
else if (bytes > 1000)
printf("%5.2fK\n", bytes / 1000)
else
printf("%5.2f\n", bytes)
printf("\n")
}
}
' localhost=`hostname` min=100 f1=$FROM f2=$TO f4=$VIA errors=$ERRORS -
if [ ! -s $FROM ] ; then
exit 0
fi
# -------------------------------------------------------------
# Print out info about who sent us mail
# -------------------------------------------------------------
echo " "
echo "--------------------------------------------------------------"
echo Part I -- Mail relayed from:
echo "--------------------------------------------------------------"
sort $VIA | uniq -c | sort -rn | head -$COUNT
# -------------------------------------------------------------
# Print out info about who got the mail
# -------------------------------------------------------------
echo " "
echo "--------------------------------------------------------------"
echo Part II -- Mail sent from:
echo "--------------------------------------------------------------"
sort $FROM | uniq -c | sort -rn | head -$COUNT
# -------------------------------------------------------------
# Print out info about who got mail
# -------------------------------------------------------------
echo " "
echo "--------------------------------------------------------------"
echo "Part III -- Mail sent to: Avg delay Max delay"
echo "--------------------------------------------------------------"
sort $TO | awk ' NR == 1 {
last = $1
delay += $2
max = $2
count = 1
next
}
{
#
# Each line should be of form: <host> <delay>
# Lines are also ordered by host name, and so
# if the previous line began with a different
# name, we know we are on a new host.
#
if ($1 == last) {
if ($2 > max)
max = $2
delay += $2
count++
}
else {
#
# Print results and reset.
#
avg = delay / count
printf("%5d %-30s", count, last)
if (avg >= 3600)
printf(" %5.2f hrs ", avg / 3600)
else if (avg >= 60)
printf(" %5.2f mins", avg / 60)
else
printf(" %5.2f secs", avg)
if (max >= 3600)
printf(" %5.2f hrs ", max / 3600)
else if (max >= 60)
printf(" %5.2f mins", max / 60)
else
printf(" %5.2f secs", max)
printf("\n")
last = $1
count = 1
delay = max = $2
}
}
END {
avg = delay / count
printf("%5d %-30s", count, last)
if (avg >= 3600)
printf(" %5.2f hrs ", avg / 3600)
else if (avg >= 60)
printf(" %5.2f mins", avg / 60)
else
printf(" %5.2f secs", avg)
if (max >= 3600)
printf(" %5.2f hrs ", max / 3600)
else if (max >= 60)
printf(" %5.2f mins", max / 60)
else
printf(" %5.2f secs", max)
printf("\n")
}' | sort -rn | head -$COUNT
# -------------------------------------------------------------
# Mail any errors that were found with this script
# -------------------------------------------------------------
if [ -s $ERRORS ] ; then
if [ $TESTMODE -eq 1 ] ; then
echo "Found these errors"
echo " "
cat $ERRORS
else
Mail -s "smtpstats errors" $ERRORSTO < $ERRORS
fi
fi
# -------------------------------------------------------------
# Tidy up
# -------------------------------------------------------------
rm -f $TO $VIA $FROM $TEMPFILE $ERRORS