Re: [exim] Exim as a relay - ratelimiting by rejections

Top Page
Delete this message
Reply to this message
Author: Lena
Date:  
To: exim-users
Subject: Re: [exim] Exim as a relay - ratelimiting by rejections
Chris Edwards wrote:

> Andrew Hearn wrote:


> > We're an ISP and use exim as a smarthost/relay for our customers.


> > is there a way to ratelimit or deny hosts based on how many messages
> > they've sent that have been rejected/deferred by the recipients MX?


Deferred can be normal (non-selective greylisting - I don't recommend it,
but some recipients' MX do use it). So, I'd count rejections only.

> > Eg, if we've tried to relay messages for a host, and 100 in the past
> > hour have been denied or deferred by the recipients MX, then we can
> > block the sender from sending more. (as well as log it and contact the
> > customer)


I assume that all your customers have static IP-addresses listed in
+relay_from_hosts (in case of dynamic IP-addresses you need to map
$sender_host_address to a customer ID in the first "warn" line; if the mapping
operation is expensive then you can move that line to acl_check_connect).

> We do this. Local senders who trip a limit are added to a list such that
> everything they send is frozen, until a human can investigate.
>
> I'm not aware this can be achieved purely inside Exim.


Not tested:

LIM = 100
PERIOD = 1h
WARNTO = abuse@???
DIR = /var/spool/exim
EXIMBINARY = /usr/local/sbin/exim
SHELL = /bin/sh
...
acl_check_rcpt:
...
 warn set acl_c_customer = $sender_host_address
 warn set acl_c_msg = The customer $acl_c_customer is blocked because \
         has sent mail to more than LIM invalid recipients during PERIOD.


 deny hosts = +relay_from_hosts
      condition = ${if exists{DIR/blocked_customers}}
      condition = ${if eq{${lookup{$acl_c_customer}lsearch\
                     {DIR/blocked_customers}{1}{0}}}{1}}
      message = $acl_c_msg


 warn set acl_m_invrec =
      hosts = +relay_from_hosts
      !verify = recipient/defer_ok/callout=10s,defer_ok,use_sender
      set acl_m_invrec = recipient verification: $recipient_verify_failure \
                         failed: $acl_verify_message


 drop condition = $acl_m_invrec
      ratelimit = LIM / PERIOD / per_rcpt / strict / customer-$acl_c_customer
      continue = ${run{SHELL -c "echo $acl_c_customer \
           >>DIR/blocked_customers; \N{\N echo Subject: customer \
           $acl_c_customer blocked; echo; echo automatic message:; \
           echo $acl_c_msg; \N}\N | EXIMBINARY WARNTO"}}
      message = $acl_c_msg


 deny condition = $acl_m_invrec
      message = $acl_m_invrec


 accept hosts = +relay_from_hosts
        control = submission/domain=
...


After the customer is fined (according to contract), the abuse staff can
manually delete the line with the customer ID from the blocked_customers file.

You can change the two "message = $acl_c_msg" lines to two lines:
      control = freeze
      add_header = X-Customer: $acl_c_customer
and "deny" and "drop" to "accept" in those paragraphs. Then after deleting
the line the abuse staff can either unfreeze or delete accumulated messages
using exipick.