Mini Shell
#!/bin/bash
# outbound-spam-report.sh
# Written by Ryan C <ryan@imhadmin.net> / x 769
#
# This script examines /var/log/exim_mainlog to find outbound messages
# rejected by cpaneleximscanner (SpamAssassin) and sends an STR when it
# finds an address with a number of rejected messages greater than the
# threshold.
#
# ARGV1 to this script can be an integer in order to adjust
# the threshold
HOSTNAME=$(hostname -s)
CONTACT_EMAIL=str@imhadmin.net
EMAIL_SUBJECT="[AUTO STR] Outbound SPAM on ${HOSTNAME}"
# Parse args
for i in $@; do
# Use the offset file?
grep -q 'offset' -- <<<"$i"
if [[ $? -eq 0 ]]; then
OFFSET_FILE="/opt/sharedrads/ops/outbound-spam-offset"
OFFSET=$(grep -E '[0-9]+' $OFFSET_FILE)
[[ -z $OFFSET ]] && OFFSET=0
fi
# Was a threshold specified? We're just looking for some number
# passed as an argument
grep -qE '^[0-9]+$' -- <<<"$i"
if [[ $? -eq 0 ]]; then
SPAM_THRESHOLD=$i
fi
# Send an STR?
grep -q 'send-str' -- <<<"$i"
if [[ $? -eq 0 ]]; then
SEND_STR=1
fi
# help?
grep -qE -- '-h|--help' <<<"$i"
if [[ $? -eq 0 ]]; then
cat <<EOF
${0} [-h|--help] [--offset] [--send-str] [SPAM_THRESHOLD]
-h|--help Print help and exit.
--offset Use offset file. Primarily intended to be used when run from
cron.
--send-str Send STR to ${CONTACT_EMAIL} for addresses which exceed the
threshold.
SPAM_THRESHOLD Default: 30; An integer representing the minumum number of
blocked messages required in order to be included in the
report
Examples:
- Suggested cron invocation:
${0} --offset --send-str
- Specify a specific threshold and print to STDOUT
${0} 10
EOF
exit
fi
done
# Defaults
[[ -z $OFFSET ]] && OFFSET=0
[[ -z $SPAM_THRESHOLD ]] && SPAM_THRESHOLD=30
[[ -z $SEND_STR ]] && SEND_STR=0
# If the offset is greater than the number of lines, start from 0
LOG_LINES=$(wc -l /var/log/exim_mainlog | awk '{print $1}')
[[ $LOG_LINES -lt $OFFSET ]] && OFFSET=0
# Use mawk if it's available
if command mawk 2>/dev/null; then
AWK=mawk
else
AWK=awk
fi
RESULTS=$($AWK -v "OFFSET=$OFFSET" \
-v "OFFSET_FILE=$OFFSET_FILE" \
-v "SPAM_THRESHOLD=$SPAM_THRESHOLD" \
'BEGIN {
ID_TO_EMAIL[0] = ""
SPAM_COUNT[0] = ""
USERS[0] = ""
SPAM_IDS[0] = ""
SPAM_IPS[0] = ""
ACL = "/usr/local/cpanel/etc/exim/acls/ACL_OUTGOING_SMTP_CHECKALL_BLOCK/custom_begin_outgoing_smtp_checkall"
ACL_MAX_SCORE = 0;
while ((getline < ACL) > 0) {
SCORE_MATCH=match($0, /[$]spam_score_int[{}]+[0-9]+[}{]+1/)
if (SCORE_MATCH) {
ACL_MAX_SCORE = substr($0, SCORE_MATCH + 17, RLENGTH - 20)
break
}
}
# spam_score_int should be divided by 10 to get the actual spam score that
# will be used to filter mail
MAX_SCORE = ACL_MAX_SCORE / 10
}
NR > OFFSET {
MSG_ID = $3
if ($0 ~ /cpaneleximscanner detected OUTGOING.*as spam/) {
MSG_ID = $3
SPAM_SCORE = substr($NF, match($NF, /-?[0-9.]+/), RLENGTH)
if (SPAM_SCORE > MAX_SCORE) {
SPAM_IDS[MSG_ID] = ""
}
}
if (MSG_ID in SPAM_IDS) {
ADDR_MATCH = match($0, /F=<[a-zA-Z0-9@-.]+>/)
if (ADDR_MATCH > 0) {
SPAMMER = substr($0, ADDR_MATCH + 3, RLENGTH - 4)
SPAM_COUNT[SPAMMER]++
}
}
}
END {
for (ACCOUNT in SPAM_COUNT) {
if (SPAM_COUNT[ACCOUNT] > SPAM_THRESHOLD) {
printf("%5s %s\n", SPAM_COUNT[ACCOUNT], ACCOUNT)
}
}
print "\n"
if (OFFSET_FILE) {
print NR > OFFSET_FILE
}
}' /var/log/exim_mainlog)
if [[ $(wc -l <<<"$RESULTS" | awk '{print $1}') -gt 1 ]]; then
REPORT=$(echo -n "Outbound SPAM Report"
if [[ ! -z $OFFSET_FILE ]]; then
echo -ne " for lines ${OFFSET}-$(cat $OFFSET_FILE) of /var/log/exim_mainlog.\n"
else
echo -e "Please review mail logs and customer accounts for abuse.\n"
fi
printf "%9s %5s %s\n" User "#" Address
# Time for an ugly BASH loop
while read number address ; do
domain=$(cut -d@ -f2<<<"$address")
user=$(grep -im1 "$domain" /etc/userdomains | cut -d: -f2 )
# Check to see if it was sent by the cPanel user
grep -iq "@${HOSTNAME}" <<<"$address"
if [[ $? -eq 0 ]]; then
user=$(cut -d@ -f1 <<<"$address")
fi
if [[ -z $user ]]; then
printf "%9s %5s %s\n" -- $number $address
else
printf "%9s %5s %s\n" $user $number $address
fi
done <<<"$RESULTS" | sort -nk2)
# Send the report or print it
if [[ $SEND_STR -eq 1 ]]; then
echo "$REPORT" | mail -s "${EMAIL_SUBJECT}" $CONTACT_EMAIL
else
echo "$REPORT"
fi
else
echo "Nothing to report!"
fi
Zerion Mini Shell 1.0