Limiting the number of emails sent by a given auth-user/domain/IP

October 8, 2020 by Roberto Puzzanghera 14 comments

If you want to avoid the risk of compromising your server because of accounts who are sending messages indiscriminately to the world, due to the fact that their password have been violated in some way, then you can consider  Luca Franceschini's rcptcheck-overlimit.sh script, which has to be used in conjunction with the rcptcheck patch (a patch derived by Luca himself from an original work of Jay Soffian).

Since in 2016 Luca has decided to merge his combo with my big patch, he is giving his personal contribution to it. He fixed many bugs and added new important patches and functionalities, often writing himself the code. The script shared here is just the last one and it's quite surprising (at least for me) to observe how many things are performed putting together just 20 lines.

How it works

What follows is a cut&paste of the notes that you can read in the header of the script.

This script limits the number of emails sent by relayclients (authusers or ip with RELAYCLIENT in tcprules). You must define the variable RCPTCHECK=/var/qmail/bin/rcptcheck-overlimit.sh and RCPTCHECKRELAYCLIENT="1".

This script will be called for every accepted rcptto. If RELAYCLIENT is not defined the script terminates with the exit code 112 (ignore/accept). Messages sent to domains in rcpthosts will NOT be accounted for.

For every accepted rcptto with RELAYCLIENT defined, a char 'X' will be appended to a file in the directory $OVERLIMITDIR; this file name will be the authuser, if defined, or the client ip address.

The script will look for an entry corresponding to the client (authuser or ip) in $LIMITSCONTROLFILE and use the number found as the maximum number of allowed outgoing emails.

If the OVERLIMITDIR is not writable by the user running qmail-smtpd or the $LIMITSCONTROLFILE cannot be read, the script terminates with 112 (ignore/accept). In case of overlimit, an exit code 113 (reject/overlimit) will be returned to qmail-smtpd and the connection will be dropped with a 421. $LIMITSCONTROLFILE can contain comments, '0' means unlimited, the entry starting with ':' will be considered the default limit.

If the default entry can't be found, the default will be set to unlimited. In case more lines match the client name, only the last will be used.

A cronjob must be created to periodically cleanup files in $OVERLIMITDIR: to use daily limits, schedule the job once a day:

0 3 * * * find /var/qmail/overlimit/ -type f -exec rm -f "{}" \; 1> /dev/null


$LIMITSCONTROLFILE example:

:1000
1.2.3.4:3000
test@example.com:0

Configuration

Download as follows

wget -O /var/qmail/bin/rcptcheck-overlimit.sh https://notes.sagredo.eu/files/qmail/patches/rcptcheck/rcptcheck-overlimit.sh
chmod +x rcptcheck-overlimit.sh

Create the $OVERLIMITDIR directory that will store the informations about the number of messages sent by each IP/auth-user, and assign it full priviledges to the user who runs qmail-smtpd (vpopmail in our case):

mkdir /var/qmail/overlimit
chown -R vpopmail.vchkpw /var/qmail/overlimit
chmod -R 755 /var/qmail/overlimit

create the relaylimits control file and adjust it to your needs according to the instructions above

cat > /var/qmail/control/relaylimits << __EOF__
:1000
__EOF__

Modify your qmail-smtpd/run and qmail-submission/run scripts

export RCPTCHECK=/var/qmail/bin/rcptcheck-overlimit.sh
export RCPTCHECKRELAYCLIENT="1"

Set up a cronjob to periodically cleanup the files in $OVERLIMITDIR, for example:

0 3 * * * find /var/qmail/overlimit/ -type f -exec rm -f "{}" \; 1> /dev/null

And of course remember to restart qmail.

Comments

Allow whole domain

Hi,

Thanks for nice piece of software. How can I limit messages on domain basis?

For example

*.example.com:1000

is it possible?

Thanks

BR

Reply |

Allow whole domain

Hi,

I didn't wrote that code myself, but according to my tests wildcards are not allowed. You can limit a specific domain as follows

sub.domain.tld:1000

but you have to enable the line 56 on rcptcheck-overlimit.sh:

if [ -z "${limit}" ]; then value=$(eval ${PREFILTER} | grep -Fi "${FILTEREDSMTPAUTHUSER##*@}:" | tail -1); li mit="${value##*:}"; fi # domain part

I don't remember why it is commented out

Let me know if it works for you.

Reply |

Allow whole domain

Hi,

Thanks for your reply. I'm testing the configuration and update you the result soon.

Thanks.

BR

Reply |

rcptcheck-relaylimit known bug fix

Hi Roberto,

Regarding to the known bug, I modified line 55 in "rcptcheck-overlimit.sh" as underneath and works well on CentOs 8.2:

-value=$(eval ${PREFILTER} | grep -Fi "$FILTEREDSMTPAUTHUSER:" | tail -1); limit="${value##*:}" # specific authuser
+value=$(eval ${PREFILTER} | grep -i ^"$FILTEREDSMTPAUTHUSER:" | tail -1); limit="${value##*:}" # specific authuser

After that, "info@example.com" does not match "testinfo@example.com". Hope this can help.

Reply |

rcptcheck-relaylimit known bug fix

Tony, I hope you can read this.

The above modification is not distinguishing users belonging to same domain here...

I'm restoring the original version for the time being.

For anyone interested in doing tests this is the modified version and this is the original script by Luca Franceschini

Reply |

rcptcheck-relaylimit known bug fix

Great! Thank you

Reply |

Dash in relaylimits

At the moment, the users listed in /var/qmail/control/relaylimits are without the dash(es) in user and domain part, because the script trims them away:

echo "foo@bar-dings.de" | tr -cd '[:alnum:].-@'
foo@bardings.de

I think the dash-char has to be escaped in the script to keep the dash-char, because the dash-char is used to define character-ranges (http://linuxcommand.org/lc3_man_pages/tr1.html)

echo "foo@bar-dings.de" | tr -cd '[:alnum:].\-@'
foo@bar-dings.de

Reply |

Dash in relaylimits

Corrected. Thanks for the contribution

Reply |

usage report

Hi,

Thanks for your information, I would like to share a tips for usage report.

Add this to crontab:

59 2 * * * /usr/bin/ls -lS /var/qmail/overlimit/ | /usr/bin/grep vpop | /usr/bin/awk '{ print $5" "$9 }' | /usr/bin/column -t | /usr/bin/mail -s "Overlimit Stats" you@youremail.com > /dev/null 2>&1

change the email "you@youremail.com" to your email address, then everynight will send an email report to administrator.

Reply |

usage report

Thank you. I'll check it out.

Reply |

rcptcheck with starttls

Hi there,

Always thankful for this great documentation.

Rencently I found this rcptcheck patch and tried to apply my mail server.

Everything looks fine without any error during patching and compiling.

But once it's applied, starttls doesn't work with this new patch.(I used combined patch, not this patch separately.- the combined patch is also containing this rcptcheck, right?)

qmail-smtpd and qmail-submission (I'm using it as qmail-smtpd-ssl) are actually running.

But if I try to access with starttls it's not accessbie like below.(nothing shows after "CONNECTED").

ryan-PC:~# openssl s_client -starttls smtp -crlf -connect my-server-ip:587
CONNECTED(00000003)

So, I had to rolled back to the old patch...

Do you have any idea?

Thanks in advance.

Reply |

rcptcheck with starttls

How did you configured submission as qmail-smtpd-ssl?

Reply |

rcptcheck with starttls

Hi Roberto,

This is the run file of qmail-smtp-ssl.

#!/bin/sh

QMAILDUID=`id -u vpopmail`
NOFILESGID=`id -g vpopmail`
MAXSMTPD=`cat /var/qmail/control/concurrencyincoming`

# You MUST export this, otherwise you'd get a 30 sec timeout
export SMTPAUTH="!"

# This enables greetdelay for qmail-smtpd.
#export SMTPD_GREETDELAY=5

# This enables chkuser
export CHKUSER_START=ALWAYS

# This enables simscan debug
#export SIMSCAN_DEBUG=2
#export QMAILQUEUE=/var/qmail/bin/qmail-dkim
#export DKIMVERIFY="FGHIKLMNOQRTVWjpu"
# This is to avoid verification of outgoing messages
#export RELAYCLIENT_NODKIMVERIFY=1

exec /usr/local/bin/softlimit -m 100000000 \
/usr/local/bin/tcpserver -v -H -R -l 0 \
-x /home/vpopmail/etc/tcp.submission.cdb -c "$MAXSMTPD" \
-u "$QMAILDUID" -g "$NOFILESGID" 0 587 \
/var/qmail/bin/qmail-smtpd \
/home/vpopmail/bin/vchkpw /usr/bin/true 2>&1

Thanks,

Reply |

rcptcheck with starttls

Honestly I don't know what might be the cause... I also tried to configure qmail-submission as qmail-smtpd-ssl and it works here...

Reply |

Recent comments
See also...
Recent posts

RSS feeds