MTA Exim configuration.
If you want to couple your exim to this RBL then do this:
If you want to couple your exim to this RBL then do this:
#In exim conf activate sender checking (unless you are already checking):
acl_smtp_rcpt = acl_check_recip
#Then add an entry after the line that starts ACL checking (begin_acl):
acl_check_recip:
# ---- here own rules
#And right after them (or in front of them, put the following code:
deny
message = Blocked by rhsbl.rbl.polspam.pl
!authenticated = *
dnslists = rhsbl.rbl.polspam.pl/$sender_address_domain
log_message = Blocked by rhsbl.rbl.polspam.pl(bad domains senders)
deny
message = Blocked by rhsbl-danger.rbl.polspam.pl
!authenticated = *
dnslists = rhsbl-danger.rbl.polspam.pl/$sender_address_domain
log_message = Blocked by rhsbl-danger.rbl.polspam.pl(bad domains senders)
deny
message = Blocked by bl.rbl.polspam.pl
!authenticated = *
dnslists = bl.rbl.polspam.pl
log_message = Blocked by bl.rbl.polspam.pl
defer
message = Blocked by bl-h1.rbl.polspam.pl. We check now your reputation.
!authenticated = *
dnslists = bl-h1.rbl.polspam.pl
log_message = Blocked by bl-h1.rbl.polspam.pl
delay = 30s
defer
message = Blocked by bl-h2.rbl.polspam.pl We check now your reputation.
!authenticated = *
dnslists = bl-h2.rbl.polspam.pl
log_message = Blocked by bl-h2.rbl.polspam.pl
delay = 30s
defer
message = Blocked by bl-h3.rbl.polspam.pl We check now your reputation.
!authenticated = *
dnslists = bl-h3.rbl.polspam.pl
log_message = Blocked by bl-h3.rbl.polspam.pl
delay = 30s
defer
message = Blocked by bl-h4.rbl.polspam.pl
!authenticated = *
dnslists = bl-h4.rbl.polspam.pl
log_message = Blocked by bl-h4.rbl.polspam.pl
Activating the above settings for ACL acl_check_recip, will bounce mail with the code 5xx (for deny) and not to let the mail with the code 4xx (for defer) after polspam RBL polling.
From time to time, there is a need to cut out a nibbler using the domain mail, which, for various reasons, cannot be completely blocked and you want to irritate with a single pest that sends SPAM out of your mind. This situation often applies to domains used by free e-mail providers, such as Google Gmail.
For MTA Exim this can be done using PERL, but to do so it should be compiled in. You can read how to do it here. Next, by completing an existing or writing a new script for Exim, called in exim.conf as follows (during testing, replace deny with defer and observe the action):
#showing exim a perl file
perl_startup = do '/etc/exim/emailbanfilter-polspam-b-emails.pl'
#ACL in which we call the function (sub) perl
acl_smtp_rcpt:
deny message = Private e-mail BlackList in progress ... Bye bye dear spammer :)
!authenticated = *
condition = ${perl{polspam_black_email_rbl_check}}
logwrite = Sender $sender_address_local_part@$sender_address_domain is blacklisted on bl-emails.rbl.polspam.pl
And the little pearl code, called from exim.conf, which queries RBL and takes care of single e-mail addresses (/etc/exim/emailbanfilter-polspam-b-emails.pl) looks like this:
use Socket;
use Net::DNS;
sub polspam_black_email_rbl_check
{
my $usr = Exim::expand_string('$sender_address_local_part');
my $dmn = Exim::expand_string('$sender_address_domain');
my $rbl = 'bl-emails.rbl.polspam.pl';
my $que = "$usr\@$dmn.$rbl";
my $res = Net::DNS::Resolver->new;
my $odp = $res->search($que, "A");
if ($odp)
{
foreach my $rr($odp->answer)
{
next unless $rr->type eq "A";
Exim::log_write("PRV_EMAIL_BL: YES $usr\@$dmn LISTED on RBL: $rbl !!! (" . $rr->address . ")");
return "yes";
}
}
else
{
Exim::log_write("PRV_EMAIL_BL: NO $usr\@$dmn NOT listed.");
return "no"
}
}
return true;
#end
An example of using the log /var/log/exim/rejectlog and showing the cooperation of ipset with iptables to block annoying addresses:
First, we will build an appropriate set of IPv4 addresses, stored using ipset
We create a file named e.g. scan-exim-rejectlog.
#!/bin/bash
####################################################################################################################
export BANTIME=14400 #only later than (CURRENT_UNIX_TIMESTAMP - BANTIME) seconds
export LOGGING="on" #Logging: on - yes, other value - no
export EXIM_REJECTLOG="/var/log/exim/rejectlog" #Exim reject log
export WHEREIS="/usr/bin/whereis"
#!!! Don't change anything below this line !!! [ Unless you know what you are doing :) ]
#Location of the files depends on the operating system
export IPSET=`${WHEREIS} ipset | cut -d ' ' -f 2`
export GREP=`${WHEREIS} grep | cut -d ' ' -f 2`
export ECHO=`${WHEREIS} echo | cut -d ' ' -f 2`
export CUT=`${WHEREIS} cut | cut -d ' ' -f 2`
export MV=`${WHEREIS} mv | cut -d ' ' -f 2`
export RM=`${WHEREIS} rm | cut -d ' ' -f 2`
export SORT=`${WHEREIS} sort | cut -d ' ' -f 2`
export UNIQ=`${WHEREIS} uniq | cut -d ' ' -f 2`
export TMP_4_FILE="/tmp/ip4_block_mail.txt"
export LOGFILE="/var/log/ip4_block_mail.log"
export BAN_BLOCK_NAME="_IP4_BLOCK_MAIL_"
####################################################################################################################
export VER="2021.12.30.11.46"
####################################################################################################################
# Delete old file if exists
if [ -f ${TMP_4_FILE} ]
then
rm -f ${TMP_4_FILE}
fi
# Read data's from exim rejectlog
while IFS= read -r line
do
if [[ $line =~ "535 Incorrect" ]] || \
[[ $line =~ "impersonating" ]] || \
[[ $line =~ "is the local host" ]] || \
[[ $line =~ "MX record points" ]] || \
[[ $line =~ "TLS error" ]] || \
[[ $line =~ "rejected RCPT" ]] || \
[[ $line =~ "rejected EHLO" ]] || \
[[ $line =~ "relay not permitted" ]] || \
[[ $line =~ "too many syntax" ]] || \
[[ $line =~ "HELO should be a FQDN or address literal" ]] || \
[[ $Line =~ "verify a sender in a header" ]]
then
#Date and time
ldt=`${ECHO} $line | ${CUT} -d ' ' -f 1`
lti=`${ECHO} $line | ${CUT} -d ' ' -f 2`
uts=`date -d "$ldt $lti" +"%s"`
cts=`date +"%s"`
ivl=$[ $cts - $uts ]
#IPv4 address
if [[ $line =~ "([" ]] && [[ $line =~ "127.0.0.1" ]]
then
ip=`${ECHO} $line | ${CUT} -d ']' -f 2`
ip=`${ECHO} $ip | ${CUT} -d '[' -f 2`
else
ip=`${ECHO} $line | ${CUT} -d '[' -f 2`
ip=`${ECHO} $ip | ${CUT} -d ']' -f 1`
fi
if [[ $ip != '127.0.0.1' ]] && [[ ! $ip =~ ":" ]]
then
if [ $ivl -lt ${BANTIME} ]
then
${ECHO} $ip >> ${TMP_4_FILE}
fi
fi
fi
done < ${EXIM_REJECTLOG}
####################################################################################################################
# Add IP's ipv4 to ipset data's
#
if [ ! -f ${TMP_4_FILE} ]; then exit; fi
#
#Set ${BAN_BLOCK_NAME} initial operations
chain_exists=`${IPSET} list | grep ${BAN_BLOCK_NAME}`
if [[ $chain_exists != "" ]]
then
chain_exists=`${ECHO} $chain_exists | ${CUT} -d ' ' -f 2`
if [[ "$chain_exists" -eq "${BAN_BLOCK_NAME}" ]]
then
${IPSET} flush ${BAN_BLOCK_NAME} >/dev/null 2>&1
else
${IPSET} create ${BAN_BLOCK_NAME} hash:ip hashsize 4096 maxelem 16777216 family inet >/dev/null 2>&1
fi
else
${IPSET} create ${BAN_BLOCK_NAME} hash:ip hashsize 4096 maxelem 16777216 family inet >/dev/null 2>&1
fi
#
#Prepare data file
${MV} -f ${TMP_4_FILE} ${TMP_4_FILE}.a
${SORT} ${TMP_4_FILE}.a -o ${TMP_4_FILE}
${RM} -f ${TMP_4_FILE}.a
${MV} -f ${TMP_4_FILE} ${TMP_4_FILE}.a
${UNIQ} ${TMP_4_FILE}.a > ${TMP_4_FILE}
${RM} -f ${TMP_4_FILE}.a
#Fill set ${BAN_BLOCK_NAME}
while read ip
do
warn=`${IPSET} test ${BAN_BLOCK_NAME} $ip 2>&1`
exists=${warn:0:4}
if [[ $exists != "Warn" ]]
then
${IPSET} -A ${BAN_BLOCK_NAME} $ip >/dev/null 2>&1
fi
done < ${TMP_4_FILE} | ${SORT}
#
${RM} -f ${TMP_4_FILE}
#
#Save log file
if [ ${LOGGING} = "on" ]
then
entries=`${IPSET} list ${BAN_BLOCK_NAME} | ${GREP} 'Number of entries' | ${CUT} -d ' ' -f 4 2>&1`
stamp=$(date '+%Y-%m-%d %H:%M:%S')
${ECHO} "$stamp SET: ${BAN_BLOCK_NAME} has $entries entries." >> ${LOGFILE}
fi
#
exit 0
###########################################################################################################################
# Rules for your firewall:
# iptables -A INPUT -m tcp -p tcp -m multiport --dports 25,110,143,993,995 -m set --match-set ${BAN_BLOCK_NAME} src -j DROP
# iptables -A INPUT -m udp -p udp -m multiport --dports 25,110,143,993,995 -m set --match-set ${BAN_BLOCK_NAME} src -j DROP
###########################################################################################################################
#end
If necessary, we set the IPSET variable - the location of this file may be different in different versions of the system. We give the file the executable attribute. It should be on a mounted partition with no noexec parameter. It is wise to run this cron file at some chosen time interval (e.g. every 15 minutes). Doing so from cron will scan the exim log and update the pset dataset.
The bash script shown above, updating the ipset data set, can then be used to block connections to the mail ports from the IPv4 addresses collected from the exim log.
iptables -A INPUT -i YOUR_INTERNET_DEVICE -m tcp -p tcp -m multiport --dports 25,110,143,465,587,993,995 \
-m set --set-match _IP4_BLOCK_MAIL_ src -j REJECT --reject-with icmp-port-unreachable
This design will allow you to block annoying IPv4 addresses
Using ipset and cron to update the ipset file will ensure continuous updating of unwanted addressing and will allow iptables to use this file without restarting the firewall.