Remove/replace all characters before and after a specific character & Deal with “postfix/smtpd too many errors after UNKNOWN from unknown”

Plenty of logs on an e-mail server like the one below:

Sep  3 05:31:01 web postfix/smtpd[7858]: too many errors after UNKNOWN from unknown[42.119.175.103]
(These logs seem to be caused by botnets trying to send spam, or broken spam bots trying to send spam emails to server, but fail to complete the transaction. )

Needed to extract the IP address from logs. Solution:

Replace all characters before [ with blank space and all after ] with blank space :

sed ‘s/.*\[//’ | sed -e ‘s/\].*//’  The full command:

tail -f /var/log/maillog | grep “too many errors” |  sed ‘s/.*\[//’ | sed -e ‘s/\].*//’ >/var/log/ips.log

Next, needed to count how many times each line (IP) is repeating:

awk ‘NF{a[$NF]++}END{for(i in a)print i,a[i]}’ /var/log/ips.log | sort >/var/log/ips2.log This will produce results as below:

95.82.66.164 8
95.82.74.178 6
95.82.74.221 29

If we want to block incoming tcp connection on port 25 from IPs repeating more than 20 times in the above list, I created a small script:

#!/bin/sh

s1=(`cat /var/log/ips2.log | awk ‘{print $2}’`);  # store in a string the counted repeats
s2=(`cat /var/log/ips2.log | awk ‘{print $1}’`); # store the IPs in a string

for (( i = 0 ; i < ${#s1[@]} ; i++ ))
    do
        if [ ${s1[i]} -gt 20 ]
            then
                   iptables -t raw -A PREROUTING -i eth0 -p tcp –dport 25 -s ${s2[i]} -j DROP;
        fi
done

A different/better approach would be to read the mail logs every 5 min and execute the script below:

 #!/bin/sh
s1=(`cat /usr/local/psa/var/log/maillog  | grep “too many errors” |  sed ‘s/.*\[//’ | sed -e ‘s/\].*//’`);
s2=(`iptables -nL -t raw | grep DROP | awk ‘{ print $4 }’`);  # IPs already blocked in table row

for (( i = 0 ; i < ${#s1[@]} ; i++ ));
        do
            k=0;
            for (( j = 0 ; j < ${#s2[@]} ; j++ ));
                do
                    if [ ${s1[i]} = ${s2[j]} ]
                        then
                           echo “${s1[i]} is already blocked!”;
                           k=1;
                           break;
                    fi
            done
            if [ $k -eq 0 ]
                then
                   iptables -t raw -A PREROUTING -i eth0 -p tcp –dport 25 -s ${s1[i]} -j DROP;
                   echo “${s1[i]} has been blocked!”;
            fi

done

If you have thousands of IPs you may want to consider using ipset.

 

 

 

 

 

 

This entry was posted in Linux and tagged , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *