changeset 259:be939802c64e

add recipient rate limits by email from address or domain
author Carl Byington <carl@five-ten-sg.com>
date Sat, 21 Jul 2012 08:34:04 -0700
parents 7a16904fec66
children 7c05043a220e
files dnsbl.conf src/context.cpp src/context.h src/dnsbl.cpp xml/dnsbl.in
diffstat 5 files changed, 55 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/dnsbl.conf	Sun Jul 01 10:34:43 2012 -0700
+++ b/dnsbl.conf	Sat Jul 21 08:34:04 2012 -0700
@@ -7,7 +7,7 @@
     content on {
         filter    sbl-xbl.spamhaus.org        "Mail containing %s rejected - sbl; see http://www.spamhaus.org/query/bl?ip=%s";
         uribl     multi.surbl.org             "Mail containing %s rejected - surbl; see http://www.rulesemporium.com/cgi-bin/uribl.cgi?bl0=1&domain0=%s";
-        #uribl    black.uribl.com             "Mail containing %s rejected - uribl; see http://l.uribl.com/?d=%s";
+        #uribl    multi.uribl.com             "Mail containing %s rejected - uribl; see http://l.uribl.com/?d=%s";
         ignore    { include "hosts-ignore.conf"; };
         tld       { include "tld.conf"; };
         cctld     { include "cctld.conf"; };
@@ -28,12 +28,15 @@
         "<>"    black;
     };
 
-    // hourly recipient rate limit by smtp auth client id
+    // hourly recipient rate limit by smtp auth client id,
+    // or unauthenticated mail from address
     // default hourly limit is 30
     // daily limits are 4 times the hourly limit
     rate_limit 30 4 { // default
         #fred 100;   // override default limits
         #joe  10;    // ""
+        #sam@somedomain.tld  500;
+        #@otherdomain.tld    100;
     };
 };
 
@@ -49,7 +52,7 @@
     content on {
         filter    sbl-xbl.spamhaus.org        "Mail containing %s rejected - sbl; see http://www.spamhaus.org/query/bl?ip=%s";
         uribl     multi.surbl.org             "Mail containing %s rejected - surbl; see http://www.rulesemporium.com/cgi-bin/uribl.cgi?bl0=1&domain0=%s";
-        #uribl    black.uribl.com             "Mail containing %s rejected - uribl; see http://l.uribl.com/?d=%s";
+        #uribl    multi.uribl.com             "Mail containing %s rejected - uribl; see http://l.uribl.com/?d=%s";
         ignore    { include "hosts-ignore.conf"; };
         tld       { include "tld.conf"; };
         cctld     { include "cctld.conf"; };
--- a/src/context.cpp	Sun Jul 01 10:34:43 2012 -0700
+++ b/src/context.cpp	Sat Jul 21 08:34:04 2012 -0700
@@ -843,8 +843,22 @@
 
 int CONTEXT::find_rate(const char *user) {
     if (rcpt_per_hour.empty()) return default_rcpt_rate;
-    rcpt_rates::iterator i = rcpt_per_hour.find(user);
-    return (i == rcpt_per_hour.end()) ? default_rcpt_rate : (*i).second;
+    rcpt_rates::iterator i = rcpt_per_hour.find(user);  // look for authen id, or sender user@email limiting
+    if (i != rcpt_per_hour.end()) return (*i).second;   // found authen id, or user@email limiting
+    const char *f = strchr(user, '@');
+    if (!f) return default_rcpt_rate;
+    i = rcpt_per_hour.find(f);                          // look for @domain limiting
+    if (i != rcpt_per_hour.end()) return (*i).second;   // found @domain limiting
+    return default_rcpt_rate;
+}
+
+
+bool CONTEXT::is_unauthenticated_limited(const char *user) {
+    rcpt_rates::iterator i = rcpt_per_hour.find(user);  // look for sender user@email limiting
+    if (i != rcpt_per_hour.end()) return true;          // found user@email limiting
+    const char *f = strchr(user, '@');
+    i = rcpt_per_hour.find(f);                  // look for sender @domain limiting
+    return (i != rcpt_per_hour.end());          // found @domain limiting
 }
 
 
--- a/src/context.h	Sun Jul 01 10:34:43 2012 -0700
+++ b/src/context.h	Sat Jul 21 08:34:04 2012 -0700
@@ -209,6 +209,7 @@
     void        set_daily_multiple(int multiple)            {rcpt_daily_multiple = multiple;};
     void        add_rate(const char *user, int limit)       {rcpt_per_hour[user] = limit;};
     int         find_rate(const char *user);
+    bool        is_unauthenticated_limited(const char *user);
     int         get_daily_multiple()                        {return rcpt_daily_multiple;};
 
     void        add_to(const char *to)                            {env_to.insert(to);};
--- a/src/dnsbl.cpp	Sun Jul 01 10:34:43 2012 -0700
+++ b/src/dnsbl.cpp	Sat Jul 21 08:34:04 2012 -0700
@@ -1143,9 +1143,9 @@
             uint pp = p - priv.client_name;
             priv.client_dns_name = strdup(priv.client_name);
             priv.client_dns_name[pp] = '\0';
-            char text[500];
-            snprintf(text, sizeof(text), "found simple dns client name %s", priv.client_dns_name);
-            my_syslog(text);
+            //char text[500];
+            //snprintf(text, sizeof(text), "found simple dns client name %s", priv.client_dns_name);
+            //my_syslog(text);
         }
     }
     if (spamc != spamc_empty) {
@@ -1194,6 +1194,21 @@
         smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"recipient can not reply due to blacklisting");
         return SMFIS_REJECT;
     }
+    if (!priv.authenticated && dc.default_context->is_unauthenticated_limited(priv.mailaddr)) {
+        int hourly, daily;
+        incr_rcpt_count(priv.mailaddr, hourly, daily);
+        int h_limit = dc.default_context->find_rate(priv.mailaddr);
+        int d_limit = dc.default_context->get_daily_multiple() * h_limit;
+        if (debug_syslog > 1) {
+            char msg[maxlen];
+            snprintf(msg, sizeof(msg), "unauthenticated address %s (%d %d recipients, %d %d limits)", priv.mailaddr, hourly, daily, h_limit, d_limit);
+            my_syslog(&priv, msg);
+        }
+        if ((hourly > h_limit) || (daily > d_limit)){
+            smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"recipient rate limit exceeded");
+            return SMFIS_REJECT;
+        }
+    }
     if (priv.authenticated) {
         int hourly, daily;
         incr_rcpt_count(priv.authenticated, hourly, daily);
--- a/xml/dnsbl.in	Sun Jul 01 10:34:43 2012 -0700
+++ b/xml/dnsbl.in	Sat Jul 21 08:34:04 2012 -0700
@@ -186,9 +186,13 @@
                 specified limit.
             </para>
             <para>
-                This milter can also impose hourly rate limits on the number of
-                recipients accepted from SMTP AUTH connections, that would otherwise be
-                allowed to relay thru this mail server with no spam filtering.
+                This milter can also impose hourly and daily rate
+                limits on the number of recipients accepted from SMTP
+                AUTH connections, that would otherwise be allowed to
+                relay thru this mail server with no spam filtering. If
+                the connection does not use SMTP AUTH, the rate limits
+                may be specified by the mail from email address or
+                domain.
             </para>
             <para>
                 Consider the case of a message from A to B passing thru this milter.  If
@@ -732,7 +736,7 @@
     content on {
         filter    sbl-xbl.spamhaus.org        "Mail containing %s rejected - sbl; see http://www.spamhaus.org/query/bl?ip=%s";
         uribl     multi.surbl.org             "Mail containing %s rejected - surbl; see http://www.rulesemporium.com/cgi-bin/uribl.cgi?bl0=1&domain0=%s";
-        #uribl    black.uribl.com             "Mail containing %s rejected - uribl; see http://l.uribl.com/?d=%s";
+        #uribl    multi.uribl.com             "Mail containing %s rejected - uribl; see http://l.uribl.com/?d=%s";
         ignore    { include "hosts-ignore.conf"; };
         tld       { include "tld.conf"; };
         cctld     { include "cctld.conf"; };
@@ -753,12 +757,15 @@
         "<>"    black;
     };
 
-    // hourly recipient rate limit by smtp auth client id
+    // hourly recipient rate limit by smtp auth client id,
+    // or unauthenticated mail from address
     // default hourly limit is 30
     // daily limits are 4 times the hourly limit
     rate_limit 30 4 { // default
         #fred 100;   // override default limits
         #joe  10;    // ""
+        #sam@somedomain.tld  500;
+        #@otherdomain.tld    100;
     };
 };
 
@@ -774,7 +781,7 @@
     content on {
         filter    sbl-xbl.spamhaus.org        "Mail containing %s rejected - sbl; see http://www.spamhaus.org/query/bl?ip=%s";
         uribl     multi.surbl.org             "Mail containing %s rejected - surbl; see http://www.rulesemporium.com/cgi-bin/uribl.cgi?bl0=1&domain0=%s";
-        #uribl    black.uribl.com             "Mail containing %s rejected - uribl; see http://l.uribl.com/?d=%s";
+        #uribl    multi.uribl.com             "Mail containing %s rejected - uribl; see http://l.uribl.com/?d=%s";
         ignore    { include "hosts-ignore.conf"; };
         tld       { include "tld.conf"; };
         cctld     { include "cctld.conf"; };
@@ -790,7 +797,7 @@
     generic "^dsl.static.*ttnet.net.tr$|(^|[x.-])(ppp|h|host)?([0-9]{1,3}[x.-](Red-|dynamic[x.-])?){4}"
             "your mail server %s seems to have a generic name";
 
-    white_regex ".*=example.com=user@yourhostingaccount.com";
+    white_regex "=example.com=user@yourhostingaccount.com$";
 
     env_to {
         # !! replace this with your domain names