Last week we had a spam issue when a user’s mail credentials were apparently guessed or stolen. (Our mail server doesn’t do two factor yet.) A lot of spam was sent from that useraccount.
To monitor our relay server I wrote a script that checks for unusual amounts of mail being sent. It sends a notification when it spots higher outgoing traffic than usual on a user’s e-mail account.
The script works in conjunction with ASSP’s mail archive plugin.
#!/bin/bash ############################################################# # mailvolumealert.sh - Martin Huijgen, 2017-07-07 # # Published on Vorkbaard.nl # ############################################################# # This script is supposed to work in conjunction with # # ASSP's archive plugin. It bases outgoing mail volume on # # ASSP's mail archive folder. # # # # It counts how many mail a user has sent today. If it is # # significantly more than the last few days, alert the # # admin. # # # # Written for on Ubuntu 17.04. # ############################################################# ############################################################# # Parameters # ############################################################# ARCHIVEDIR="/var/assp/archive/outgoing" # Where the mail archive is stored AVGDAYS=10 # How many working days to use for average (Saturdays and Sundays are excluded) ALWAYS_ALLOW=100 # Allow this many mails to be sent without notification PERC_ALLOWED=150 # Percentage of mail the user is allowed to send relative to the average UPPER_LIMIT=200 # Always notify if a user sent more mail than this ADMIN_EMAIL=your@email.here # Where to send alerts FROM_ADDR=$ADMIN_EMAIL # Which address should we say is the mail from? # File to remember which users have already been reported today. Only change this # if you really need it. PREV_REPORT_FILE=mailnotified.$(date -d "1 day ago" +%A) CUR_REPORT_FILE=mailnotified.$(date +%A) # Remember to check your 'mailx' or 'xmail' settings on the last # few lines of this script. ############################################################# # End of parameters # ############################################################# # A bit of preparation # Check if the archive folder exists if [ ! -d $ARCHIVEDIR ] ; then echo "$ARCHIVEDIR does not exist, please correct the ARCHIVEDIR variable." exit fi # Check if there is any mail to count TODAYS_MAIL_FLD=$ARCHIVEDIR/$(date +%Y)/$(date +%m)/$(date +%d) # If noone has send any mail today then don't bother. if [ ! -d $TODAYS_MAIL_FLD ] ; then exit; fi CUR_FLD=$(ls -d $TODAYS_MAIL_FLD) SENDERS=$CUR_FLD/* SENDERNR=0 SEND_ALERTMAIL=false ALERTMAIL="The following users are sending an unusual amount of mail or have breached the upper notification limit ($UPPER_LIMIT mails).\n" # Delete yesterday's report file and create the new one if it doesn't exist if [ -e $PREV_REPORT_FILE ] ; then rm $PREV_REPORT_FILE ; fi touch $CUR_REPORT_FILE # Here we go! # Go to mail archive folder; enumerate users for SENDER in $SENDERS; do SENDER=$(echo $SENDER | rev | cut -d'/' -f1 | rev) # If we were already notified about this sender, skip them if ! ( grep -iq "$SENDER" $CUR_REPORT_FILE ) ; then # Calculate average amount of mail based on last ten working days DATE_FORMAT="+%Y%m%d" PREVDAYS=1 WEEKDAYS=0 while [ $WEEKDAYS -lt $AVGDAYS ] ; do DAYAGO=$(date "$DATE_FORMAT" -d "$PREVDAYS day ago") # Substract $PREVDAYS days from today DAYNUMBER=$(date -d "$DAYAGO" +%u) # Get day number; 1 is Monday NR_OF_DAYS=0 TOT_MAIL=0 if [ "$DAYNUMBER" -lt "6" ] ; then # Get number of mails for this user on this day CURDIR=$ARCHIVEDIR/${DAYAGO:0:4}/${DAYAGO:4:2}/${DAYAGO:6:2} # Check if the folder exists if [ -d "$CURDIR/$SENDER" ] ; then FLD_CNT[$WEEKDAYS]=$(ls $CURDIR/$SENDER/* | wc -l) fi NR_OF_DAYS=${#FLD_CNT[@]} TOT_MAIL=0 for i in ${FLD_CNT[@]}; do let TOT_MAIL+=$i; done # Calculate total number of mails WEEKDAYS=$(( $WEEKDAYS + 1 )) fi PREVDAYS=$(( $PREVDAYS + 1 )) done #WEEKDAYS -lt 11 # If the counting yielded any results, use them ALLOWEDMAIL=0 if [ "$NR_OF_DAYS" -gt "0" ] ; then let AVG_MAIL=$TOT_MAIL/$NR_OF_DAYS # echo "$SENDER Average number of mails per day over the last $AVGDAYS workdays: $AVG_MAIL" let ALLOWEDMAIL=($AVG_MAIL*$PERC_ALLOWED)/100 # The amount of mail allowed to be sent if [ "$ALLOWEDMAIL" -lt "$ALWAYS_ALLOW" ] ; then ALLOWEDMAIL=$ALWAYS_ALLOW; fi # Maintain the lower threshold else # Perhaps this is a new user. Set their average to the lower threshold. ALLOWEDMAIL=$ALWAYS_ALLOW fi # Find how many mails this user has sent today TODAYSMAIL=$(ls $ARCHIVEDIR/$(date +%Y)/$(date +%m)/$(date +%d)/$SENDER/* | wc -l) # This is for troubleshooting # echo "$SENDER - avg: $AVG_MAIL; allowed: $ALLOWEDMAIL" # If the user sent more mail than allowed, send a notification if [ "$TODAYSMAIL" -gt "$ALLOWEDMAIL" ] || [ "$TODAYSMAIL" -gt "$UPPER_LIMIT" ] ; then SEND_ALERTMAIL=true ALERTMAIL="$ALERTMAIL\n$SENDER - 10 day average is $AVG_MAIL, today's amount $TODAYSMAIL." # Remind next script run to not scan this user again echo "$SENDER" >> $CUR_REPORT_FILE fi fi # grep sender in cur_report_file done #SENDER IN SENDERS # Send the alertmail if necessary if ($SEND_ALERTMAIL); then echo -e $ALERTMAIL | mailx -a "From: Mail relay server <$FROM_ADDR>" -s "Mail warning" $ADMIN_EMAIL fi