1 | #!/bin/bash |
---|
2 | # rcptcheck-overlimit v0.3 |
---|
3 | # Digitalmind 2017-08-23 |
---|
4 | # This script limits the number of emails sent by relayclients (authusers or ip with RELAYCLIENT in tcprules) |
---|
5 | # You must define the variable RCPTCHECK=/var/qmail/bin/rcptcheck-overlimit.sh AND RCPTCHECKRELAYCLIENT="1" |
---|
6 | # This script will be called for every accepted rcptto. |
---|
7 | # If RELAYCLIENT is not defined the script terminates with the exit code 112 (ignore/accept). |
---|
8 | # Messages sent to domains in rcpthosts will NOT be accounted for. |
---|
9 | # For every accepted rcptto with RELAYCLIENT defined, a char 'X' will be appended to a file in the directory $OVERLIMITDIR; |
---|
10 | # this file name will be the authuser, if defined, or the client ip address. |
---|
11 | # The script will look for an entry corresponding to the client (authuser or ip) in $LIMITSCONTROLFILE and use the number found |
---|
12 | # as the maximum number of allowed outgoing emails. |
---|
13 | # 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). |
---|
14 | # 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. |
---|
15 | # $LIMITSCONTROLFILEFILE can contain comments, '0' means unlimited, the entry starting with ':' will be considered the default limit. |
---|
16 | # If the default entry can't be found, the default will be set to unlimited. |
---|
17 | # In case more lines match the client name, only the last will be used. |
---|
18 | # A cronjob must be created to periodically cleanup files in $OVERLIMITDIR: to use daily limits, schedule the job once a day. |
---|
19 | # |
---|
20 | # Cronjob example: |
---|
21 | # # find /var/qmail/overlimit/ -type f -exec rm -f "{}" \; |
---|
22 | # |
---|
23 | # $LIMITSCONTROLFILE example: |
---|
24 | # ----- |
---|
25 | #:1000 |
---|
26 | #1.2.3.4:3000 |
---|
27 | #test@example.com:0 |
---|
28 | # ----- |
---|
29 | # Known bugs: |
---|
30 | # - the line 'info@example.com:1000' also matches the client name 'testinfo@example.com'. |
---|
31 | |
---|
32 | EXITIGNORE=112 |
---|
33 | EXITOVERLIMIT=113 |
---|
34 | |
---|
35 | LIMITSCONTROLFILE=/var/qmail/control/relaylimits |
---|
36 | OVERLIMITDIR=/var/qmail/overlimit |
---|
37 | DEBUGLOG=/var/log/overlimit/debug.log |
---|
38 | |
---|
39 | if [ -z "${RELAYCLIENT+x}" ]; then exit $EXITIGNORE; fi |
---|
40 | if [ ! -r "$LIMITSCONTROLFILE" ]; then exit $EXITIGNORE; fi |
---|
41 | if [ ! -w "$OVERLIMITDIR" ]; then exit $EXITIGNORE; fi |
---|
42 | |
---|
43 | # Read config file removing comments, blank lines, spaces and tabs |
---|
44 | PREFILTER="sed -e 's/#.*$//g' -e '/^$/d' -e 's/[ \t]*//g' $LIMITSCONTROLFILE" |
---|
45 | |
---|
46 | # SMTPAUTHUSER should be already validated, but just to be safe leave only alphanum, -.', '_', '-' and '@' |
---|
47 | FILTEREDSMTPAUTHUSER=$(echo "$SMTPAUTHUSER" | tr -cd '[:alnum:].-_@') |
---|
48 | |
---|
49 | if [ -n "${RCPTHOSTS}" ]; then |
---|
50 | logger -t qmail-overlimit -p mail.info "RELAYCLIENT and RCPTHOSTS: mailfrom=$SENDER rcptto=$RECIPIENT authuser=${FILTEREDAUTHUSER} remoteip=${TCPREMOTEIP}" |
---|
51 | exit $EXITIGNORE |
---|
52 | fi |
---|
53 | |
---|
54 | if [ -n "${FILTEREDSMTPAUTHUSER}" ]; then |
---|
55 | value=$(eval ${PREFILTER} | grep -Fi "$FILTEREDSMTPAUTHUSER:" | tail -1); limit="${value##*:}" # specific authuser |
---|
56 | ##if [ -z "${limit}" ]; then value=$(eval ${PREFILTER} | grep -Fi "${FILTEREDSMTPAUTHUSER##*@}:" | tail -1); limit="${value##*:}"; fi # domain part |
---|
57 | client="${FILTEREDSMTPAUTHUSER}" |
---|
58 | else |
---|
59 | value=$(eval ${PREFILTER} | grep -Fi "$TCPREMOTEIP:" | tail -1); limit="${value##*:}" # specific ip address |
---|
60 | client="${TCPREMOTEIP}" |
---|
61 | fi |
---|
62 | if [ -z "${limit}" ]; then value=$(eval ${PREFILTER} | grep "^:" | tail -1); limit="${value##*:}"; fi # default ':value' |
---|
63 | if [ -z "${limit}" ]; then limit=0; fi # if nothing else |
---|
64 | |
---|
65 | currentnum=$(stat -c%s $OVERLIMITDIR/$client 2>/dev/null) |
---|
66 | if [ -z "$currentnum" ]; then currentnum=1; fi |
---|
67 | |
---|
68 | logger -t qmail-overlimit -p mail.info "client=$client limit=$limit current=$currentnum" |
---|
69 | |
---|
70 | if [ "$currentnum" -gt "$limit" ] && [ "$limit" -ne "0" ]; then |
---|
71 | logger -t qmail-overlimit -p mail.info "REJECTED $client " |
---|
72 | exit $EXITOVERLIMIT |
---|
73 | else |
---|
74 | echo -n "X" >> "$OVERLIMITDIR/$client" 2>/dev/null |
---|
75 | fi |
---|
76 | exit $EXITIGNORE |
---|