This script can be used if you have mailscanner in mysql database that record results of spamassassin activity and postfix as mta
# postban.sh # Temporary Ban SpamOnly Ip # ------------------------- # # This script create a table for postfix that ban IPs that made high spam results only # # 1) Put this script anywhere and set your parameters # 2) Put in crontab a line like this to run every 15 minutes : # 0/15 * * * * /batch/postban.sh # 3) Modify your main.cf in postfix at this line like here and then postfix reload : # smtpd_client_restrictions = (OTHER YOUR PARAMETERS) check_client_access hash:/etc/postfix/postban_access # Start time start=`date +%s` # Parameters ROOTPWD=YOUR MYSQL PWD VSCORESPAM=9 # Search for IP that have more than VSCORESPAM score VMINSPAM=3600 # In the last VMINSPAM minutes VSCOREHAM=5 # But exclude if the ip sent message that have less than VSCOREHAM VMINHAM=14400 # In the last VMINHAM minutes # In the default config it block ip that sent email that have more than score 9 # for 3600 mins (24 hours) from last event, but exclude if this ip have a mail sent # in the last 10 days (14400 mins) that have a score less than 5 VLOGFILE=/batch/postban.log # Logfile position VACCFILE=/etc/postfix/postban_access # Access file position RJMESSAGE="Il server utilizzato invia troppo spam" # Reject Message CMDPOSTMAP="/usr/sbin/postmap /etc/postfix/postban_access" # Postmap command # Date & Time NOW=$(date +"%m-%d-%Y %r") # Touching log file touch $VLOGFILE # Main selection query, table mailscanner S1="SELECT clientip \ FROM mailscanner.maillog \ WHERE timestamp > DATE_SUB(now(), INTERVAL $VMINSPAM MINUTE) \ AND spamwhitelisted = 0 \ AND clientip NOT LIKE '10.%' \ AND clientip NOT LIKE '192.168.%' \ AND sascore > $VSCORESPAM \ GROUP BY clientip;" echo "# Generated by postban.sh " $start > $VACCFILE f=0;ff=0 res1=($(mysql -N -u root -p${ROOTPWD} -e "${S1}")) cnt=${#res1[@]} for (( i=0 ; i<${cnt} ; i++ )) do #echo "Found line " $i " " ${res1[i]} CLIP=${res1[i]} S2="SELECT clientip \ FROM mailscanner.maillog \ WHERE timestamp > DATE_SUB(now(), INTERVAL $VMINHAM MINUTE) \ AND clientip = '${res1[i]}' \ AND sascore < $VSCOREHAM \ GROUP BY clientip;" #echo $S2 res2=$(mysql -N -u root -p$ROOTPWD -se "$S2") #echo $res2 let "f++" if [[ $res2 == "" ]] ; then let "ff++" #echo "Not found ham so write spam ip " $CLIP echo $CLIP " REJECT " $RJMESSAGE >> $VACCFILE fi done # Postmap (doing postmap is enough to get new ip table without refreshing) eval $CMDPOSTMAP # Logging end=`date +%s` runtime=$((end-start)) echo $NOW " Found" $f "spam ip," $ff "with no ham in the past written in reject table, time elapsed:" $runtime "sec." >> $VLOGFILE # Truncating logfile tail -n 500 $VLOGFILE > $VLOGFILE.tmp mv $VLOGFILE.tmp $VLOGFILE