# HG changeset patch # User Carl Byington # Date 1334019725 25200 # Node ID d6d5c50b927834590f687822d23a370e0eb35bc9 # Parent 720cdc2c303f3910393d81817e5a68a717206f93 Allow dnswl_list and dnsbl_list to be empty, to override lists specified in the ancestor contexts. Add daily recipient limits as a multiple of the hourly limits. diff -r 720cdc2c303f -r d6d5c50b9278 ChangeLog --- a/ChangeLog Sun Apr 08 16:17:53 2012 -0700 +++ b/ChangeLog Mon Apr 09 18:02:05 2012 -0700 @@ -1,3 +1,8 @@ +6.30 2012-04-09 + Allow dnswl_list and dnsbl_list to be empty, to override lists + specified in the ancestor contexts. + Add daily recipient limits as a multiple of the hourly limits. + 6.29 2012-04-08 Add dnswl support. diff -r 720cdc2c303f -r d6d5c50b9278 NEWS --- a/NEWS Sun Apr 08 16:17:53 2012 -0700 +++ b/NEWS Mon Apr 09 18:02:05 2012 -0700 @@ -1,3 +1,4 @@ +6.30 2012-04-09 Allow dnswl_list and dnsbl_list to be empty; add daily recipient limits. 6.29 2012-04-08 Add dnswl support. 6.28 2011-09-30 Add prvs decoding to envelope addresses. 6.27 2011-08-15 const correctness fixes from new gcc diff -r 720cdc2c303f -r d6d5c50b9278 configure.in --- a/configure.in Sun Apr 08 16:17:53 2012 -0700 +++ b/configure.in Mon Apr 09 18:02:05 2012 -0700 @@ -1,6 +1,6 @@ AC_PREREQ(2.59) -AC_INIT(dnsbl,6.29,carl@five-ten-sg.com) +AC_INIT(dnsbl,6.30,carl@five-ten-sg.com) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADER([config.h]) diff -r 720cdc2c303f -r d6d5c50b9278 dnsbl.conf --- a/dnsbl.conf Sun Apr 08 16:17:53 2012 -0700 +++ b/dnsbl.conf Mon Apr 09 18:02:05 2012 -0700 @@ -29,7 +29,9 @@ }; // hourly recipient rate limit by smtp auth client id - rate_limit 30 { // default + // 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; // "" }; @@ -104,6 +106,8 @@ }; context blacklist { + dnsbl_list ; + dnswl_list ; env_to { # dcc_to many { include "/var/dcc/whitecommon"; }; }; diff -r 720cdc2c303f -r d6d5c50b9278 dnsbl.spec.in --- a/dnsbl.spec.in Sun Apr 08 16:17:53 2012 -0700 +++ b/dnsbl.spec.in Mon Apr 09 18:02:05 2012 -0700 @@ -103,7 +103,12 @@ %changelog -* Fri Apr 08 2012 Carl Byington - 6.29-1 +* Mon Apr 09 2012 Carl Byington - 6.30-1 +- Allow dnswl_list and dnsbl_list to be empty, to override lists + specified in the ancestor contexts. +- Add daily recipient limits as a multiple of the hourly limits. + +* Sun Apr 08 2012 Carl Byington - 6.29-1 - Add dnswl support. * Fri Sep 30 2011 Carl Byington - 6.28-1 diff -r 720cdc2c303f -r d6d5c50b9278 src/context.cpp --- a/src/context.cpp Sun Apr 08 16:17:53 2012 -0700 +++ b/src/context.cpp Mon Apr 09 18:02:05 2012 -0700 @@ -727,7 +727,10 @@ require_match = (parent) ? parent->require_match : false; dcc_greylist = (parent) ? parent->dcc_greylist : false; dcc_bulk_threshold = (parent) ? parent->dcc_bulk_threshold : 0; - default_rcpt_rate = INT_MAX; + dnsbl_list_parsed = false; + dnswl_list_parsed = false; + default_rcpt_rate = 36000; // 10 per second + rcpt_daily_multiple = 3; } @@ -991,13 +994,13 @@ dnsblp_list& CONTEXT::get_dnsbl_list() { - if (dnsbl_list.empty() && parent) return parent->get_dnsbl_list(); + if (!dnsbl_list_parsed && parent) return parent->get_dnsbl_list(); return dnsbl_list; } dnswlp_list& CONTEXT::get_dnswl_list() { - if (dnswl_list.empty() && parent) return parent->get_dnswl_list(); + if (!dnswl_list_parsed && parent) return parent->get_dnswl_list(); return dnswl_list; } @@ -1050,25 +1053,23 @@ { dnsblp_list dl = get_dnsbl_list(); - if (!dl.empty()) { printf("%s dnsbl_list", indent); for (dnsblp_list::iterator i=dl.begin(); i!=dl.end(); i++) { DNSBL &d = *(*i); printf(" %s", d.name); } printf("; \n"); - }} + } { dnswlp_list dl = get_dnswl_list(); - if (!dl.empty()) { printf("%s dnswl_list", indent); for (dnswlp_list::iterator i=dl.begin(); i!=dl.end(); i++) { DNSWL &d = *(*i); printf(" %s", d.name); } printf("; \n"); - }} + } if (content_filtering) { printf("%s content on { \n", indent); @@ -1185,7 +1186,7 @@ printf("%s }; \n", indent); if (isdefault) { - printf("%s rate_limit %d { \n", indent, default_rcpt_rate); + printf("%s rate_limit %d %d { \n", indent, default_rcpt_rate, rcpt_daily_multiple); for (rcpt_rates::iterator j=rcpt_per_hour.begin(); j!=rcpt_per_hour.end(); j++) { const char *u = (*j).first; int l = (*j).second; @@ -1305,6 +1306,7 @@ return false; } } + me.set_dnsbll_parsed(); return true; } @@ -1326,6 +1328,7 @@ return false; } } + me.set_dnswll_parsed(); return true; } @@ -1705,6 +1708,11 @@ const char *def = tok.next(); tok.push(def); if (def != token_lbrace) me.set_default_rate(tok.nextint()); + + def = tok.next(); + tok.push(def); + if (def != token_lbrace) me.set_daily_multiple(tok.nextint()); + if (!tsa(tok, token_lbrace)) return false; while (true) { const char *have = tok.next(); diff -r 720cdc2c303f -r d6d5c50b9278 src/context.h --- a/src/context.h Sun Apr 08 16:17:53 2012 -0700 +++ b/src/context.h Mon Apr 09 18:02:05 2012 -0700 @@ -175,9 +175,12 @@ int dcc_bulk_threshold; // off = 0, many = 1000 dnsblp_map dnsbl_names; // name to dnsbl mapping for lists that are available in this context and children dnsblp_list dnsbl_list; // list of dnsbls to be used in this context + bool dnsbl_list_parsed; // true iff we have actually parsed a dnsbl_list dnswlp_map dnswl_names; // name to dnswl mapping for lists that are available in this context and children dnswlp_list dnswl_list; // list of dnswls to be used in this context + bool dnswl_list_parsed; // true iff we have actually parsed a dnswl_list int default_rcpt_rate; // if not specified per user + int rcpt_daily_multiple;// daily multiplier applied to hourly rate rcpt_rates rcpt_per_hour; // per user limits on number of recipients per hour @@ -203,8 +206,10 @@ WHITELISTERP find_autowhite(const char *from, const char *to); void set_default_rate(int limit) {default_rcpt_rate = limit;}; + 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); + int get_daily_multiple() {return rcpt_daily_multiple;}; void add_to(const char *to) {env_to.insert(to);}; void add_from(const char *from, const char *status) {env_from[from] = status;}; @@ -234,10 +239,12 @@ void add_dnsbl(const char *name, DNSBLP dns) {dnsbl_names[name] = dns; }; void add_dnsbl(DNSBLP dns) {dnsbl_list.push_back(dns);}; DNSBLP find_dnsbl(const char *name); + void set_dnsbll_parsed() {dnsbl_list_parsed = true;}; void add_dnswl(const char *name, DNSWLP dns) {dnswl_names[name] = dns; }; void add_dnswl(DNSWLP dns) {dnswl_list.push_back(dns);}; DNSWLP find_dnswl(const char *name); + void set_dnswll_parsed() {dnswl_list_parsed = true;}; bool set_white(const char *regx); bool white_match(const char *from); diff -r 720cdc2c303f -r d6d5c50b9278 src/dnsbl.cpp --- a/src/dnsbl.cpp Sun Apr 08 16:17:53 2012 -0700 +++ b/src/dnsbl.cpp Mon Apr 09 18:02:05 2012 -0700 @@ -114,7 +114,8 @@ time_t last_error_time = 0; int resolver_sock_count = 0; // protected with fd_pool_mutex int resolver_pool_size = 0; // protected with fd_pool_mutex -rcpt_rates rcpt_counts; // protected with rate_mutex +rcpt_rates rcpt_hourly_counts; // protected with rate_mutex +rcpt_rates rcpt_daily_counts; // protected with rate_mutex struct ns_map { @@ -163,20 +164,29 @@ //////////////////////////////////////////////// // helper to manipulate recipient counts // -int incr_rcpt_count(const char *user); -int incr_rcpt_count(const char *user) { +void incr_rcpt_count(const char *user, int &hourly, int &daily); +void incr_rcpt_count(const char *user, int &hourly, int &daily) { pthread_mutex_lock(&rate_mutex); - rcpt_rates::iterator i = rcpt_counts.find(user); - int c = 1; - if (i == rcpt_counts.end()) { + rcpt_rates::iterator i = rcpt_hourly_counts.find(user); + hourly = 1; + if (i == rcpt_hourly_counts.end()) { user = strdup(user); - rcpt_counts[user] = c; + rcpt_hourly_counts[user] = hourly; } else { - c = ++((*i).second); + hourly = ++((*i).second); + } + + rcpt_rates::iterator j = rcpt_daily_counts.find(user); + daily = 1; + if (j == rcpt_daily_counts.end()) { + user = strdup(user); + rcpt_daily_counts[user] = daily; + } + else { + daily = ++((*j).second); } pthread_mutex_unlock(&rate_mutex); - return c; } //////////////////////////////////////////////// @@ -1171,14 +1181,16 @@ return SMFIS_REJECT; } if (priv.authenticated) { - int c = incr_rcpt_count(priv.authenticated); - int l = dc.default_context->find_rate(priv.authenticated); + int hourly, daily; + incr_rcpt_count(priv.authenticated, hourly, daily); + int h_limit = dc.default_context->find_rate(priv.authenticated); + int d_limit = dc.default_context->get_daily_multiple() * h_limit; if (debug_syslog > 1) { char msg[maxlen]; - snprintf(msg, sizeof(msg), "authenticated id %s (%d recipients, %d limit)", priv.authenticated, c, l); + snprintf(msg, sizeof(msg), "authenticated id %s (%d %d recipients, %d %d limits)", priv.authenticated, hourly, daily, h_limit, d_limit); my_syslog(&priv, msg); } - if (c > l) { + if ((hourly > h_limit) || (daily > d_limit)){ smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"recipient rate limit exceeded"); return SMFIS_REJECT; } @@ -1525,20 +1537,32 @@ // extern "C" {void* config_loader(void *arg);} void* config_loader(void *arg) { - int loop = 0; + int loop1 = 0; + int loop2 = 0; while (loader_run) { sleep(180); // look for modifications every 3 minutes if (!loader_run) break; - loop++; - if (loop == 20) { + loop1++; + loop2++; + if (loop1 == 20) { // three minutes thru each loop, 20 loops per hour - // clear the recipient counts + // clear the recipient hourly counts pthread_mutex_lock(&rate_mutex); - for (rcpt_rates::iterator i=rcpt_counts.begin(); i!=rcpt_counts.end(); i++) { + for (rcpt_rates::iterator i=rcpt_hourly_counts.begin(); i!=rcpt_hourly_counts.end(); i++) { (*i).second = 0; } pthread_mutex_unlock(&rate_mutex); - loop = 0; + loop1 = 0; + } + if (loop2 == 480) { + // three minutes thru each loop, 480 loops per day + // clear the recipient daily counts + pthread_mutex_lock(&rate_mutex); + for (rcpt_rates::iterator i=rcpt_daily_counts.begin(); i!=rcpt_daily_counts.end(); i++) { + (*i).second = 0; + } + pthread_mutex_unlock(&rate_mutex); + loop2 = 0; } CONFIG &dc = *config; time_t then = dc.load_time; diff -r 720cdc2c303f -r d6d5c50b9278 xml/dnsbl.in --- a/xml/dnsbl.in Sun Apr 08 16:17:53 2012 -0700 +++ b/xml/dnsbl.in Mon Apr 09 18:02:05 2012 -0700 @@ -661,10 +661,11 @@ | RATE-LIMIT) ";" DNSBL = "dnsbl" NAME DNSPREFIX ERROR-MSG1 -DNSBLLIST = "dnsbl_list" {NAME}+ +DNSBLLIST = "dnsbl_list" {NAME}* -DNSWL = "dnswl" NAME DNSPREFIX INTEGER -DNSWLLIST = "dnswl_list" {NAME}+ +DNSWL = "dnswl" NAME DNSPREFIX LEVEL +DNSWLLIST = "dnswl_list" {NAME}* +LEVEL = INTEGER CONTENT = "content" ("on" | "off") "{" {CONTENT-ST}+ "}" CONTENT-ST = (FILTER | URIBL | IGNORE | TLD | CCTLD | HTML-TAGS | @@ -708,8 +709,11 @@ FROM-ADDR = ADDRESS VALUE [";"] DCC-FROM = "dcc_from" "{" DCCINCLUDEFILE "}" ";" -RATE-LIMIT = "rate_limit" [DEFAULTLIMIT] "{" (RATE)+ "}" +RATE-LIMIT = "rate_limit" [DEFAULT_LIMIT [DAILY_MULTIPLE]] "{" (RATE)+ "}" RATE = USER LIMIT [";"] +LIMIT = INTEGER +DEFAULT_LIMIT = INTEGER +DAILY_MULTIPLE = INTEGER DEFAULT = ("white" | "black" | "unknown" | "inherit" | "") ADDRESS = (USER@ | DOMAIN | USER@DOMAIN) @@ -750,7 +754,9 @@ }; // hourly recipient rate limit by smtp auth client id - rate_limit 30 { // default + // 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; // "" }; @@ -825,6 +831,8 @@ }; context blacklist { + dnsbl_list ; + dnswl_list ; env_to { # dcc_to many { include "/var/dcc/whitecommon"; }; };