Mercurial > dnsbl
diff src/dnsbl.cpp @ 278:368572c57013
add limits on unique ip addresses per hour per authenticated user
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Tue, 17 Dec 2013 15:35:23 -0800 |
parents | a99b6c1f5f67 |
children | 2b77295fb9a7 |
line wrap: on
line diff
--- a/src/dnsbl.cpp Wed Dec 11 22:57:06 2013 -0800 +++ b/src/dnsbl.cpp Tue Dec 17 15:35:23 2013 -0800 @@ -114,8 +114,10 @@ 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_hourly_counts; // protected with rate_mutex -rcpt_rates rcpt_daily_counts; // protected with rate_mutex +rates rcpt_hourly_counts; // protected with rate_mutex +rates rcpt_daily_counts; // protected with rate_mutex +auth_addresses auth_hourly_addresses; // protected with rate_mutex +auth_addresses auth_daily_addresses; // protected with rate_mutex struct ns_map { @@ -167,7 +169,7 @@ 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_hourly_counts.find(user); + rates::iterator i = rcpt_hourly_counts.find(user); hourly = 1; if (i == rcpt_hourly_counts.end()) { user = strdup(user); @@ -177,7 +179,7 @@ hourly = ++((*i).second); } - rcpt_rates::iterator j = rcpt_daily_counts.find(user); + rates::iterator j = rcpt_daily_counts.find(user); daily = 1; if (j == rcpt_daily_counts.end()) { user = strdup(user); @@ -189,6 +191,36 @@ pthread_mutex_unlock(&rate_mutex); } + +void add_auth_address(const char *user, int &hourly, int &daily, int32_t ip); +void add_auth_address(const char *user, int &hourly, int &daily, int32_t ip) { + pthread_mutex_lock(&rate_mutex); + auth_addresses::iterator ii = auth_hourly_addresses.find(user); + if (ii == auth_hourly_addresses.end()) { + auth_hourly_addresses[user] = new int32_t_set; + auth_hourly_addresses[user]->insert(ip); + hourly = 1; + } + else { + int32_t_set::iterator i = ((*ii).second)->find(ip); + if (i == ((*ii).second)->end()) ((*ii).second)->insert(ip); + hourly = ((*ii).second)->size(); + } + + auth_addresses::iterator jj = auth_daily_addresses.find(user); + if (jj == auth_daily_addresses.end()) { + auth_daily_addresses[user] = new int32_t_set; + auth_daily_addresses[user]->insert(ip); + daily = 1; + } + else { + int32_t_set::iterator i = ((*jj).second)->find(ip); + if (i == ((*jj).second)->end()) ((*jj).second)->insert(ip); + daily = ((*jj).second)->size(); + } + pthread_mutex_unlock(&rate_mutex); +} + //////////////////////////////////////////////// // helper to discard the strings held by a context_map // @@ -1135,12 +1167,31 @@ sfsistat mlfi_envfrom(SMFICTX *ctx, char **from) { mlfiPriv &priv = *MLFIPRIV; + CONFIG &dc = *priv.pc; priv.mailaddr = to_lower_string(from[0]); priv.queueid = strdup(smfi_getsymval(ctx, (char*)"i")); priv.authenticated = smfi_getsymval(ctx, (char*)"{auth_authen}"); priv.client_name = smfi_getsymval(ctx, (char*)"_"); if (!priv.helo) priv.helo = strdup("unknown"); if (priv.authenticated) priv.authenticated = strdup(priv.authenticated); + { + const char *uid = (priv.authenticated) ? priv.authenticated : priv.mailaddr; + if (priv.authenticated || dc.default_context->is_unauthenticated_limited(priv.mailaddr)) { + int hourly, daily; + add_auth_address(uid, hourly, daily, priv.ip); + int h_limit = dc.default_context->find_address_limit(uid); + int d_limit = dc.default_context->get_daily_address_multiple() * h_limit; + if (debug_syslog > 1) { + char msg[maxlen]; + snprintf(msg, sizeof(msg), "connect for %s (%d %d addresses, %d %d limits)", uid, 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*)"unique connection address limit exceeded"); + //return SMFIS_REJECT; + } + } + } if (priv.client_name) { priv.client_name = strdup(priv.client_name); const char *p = strstr(priv.client_name, " ["); @@ -1211,8 +1262,8 @@ if (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; + int h_limit = dc.default_context->find_rate_limit(priv.authenticated); + int d_limit = dc.default_context->get_daily_rate_multiple() * h_limit; if (debug_syslog > 1) { char msg[maxlen]; snprintf(msg, sizeof(msg), "authenticated id %s (%d %d recipients, %d %d limits)", priv.authenticated, hourly, daily, h_limit, d_limit); @@ -1295,8 +1346,8 @@ 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; + int h_limit = dc.default_context->find_rate_limit(priv.mailaddr); + int d_limit = dc.default_context->get_daily_rate_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); @@ -1600,9 +1651,12 @@ // three minutes thru each loop, 20 loops per hour // clear the recipient hourly counts pthread_mutex_lock(&rate_mutex); - for (rcpt_rates::iterator i=rcpt_hourly_counts.begin(); i!=rcpt_hourly_counts.end(); i++) { + for (rates::iterator i=rcpt_hourly_counts.begin(); i!=rcpt_hourly_counts.end(); i++) { (*i).second = 0; } + for (auth_addresses::iterator j=auth_hourly_addresses.begin(); j!=auth_hourly_addresses.end(); j++) { + delete (*j).second; + } pthread_mutex_unlock(&rate_mutex); loop1 = 0; } @@ -1610,9 +1664,12 @@ // 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++) { + for (rates::iterator i=rcpt_daily_counts.begin(); i!=rcpt_daily_counts.end(); i++) { (*i).second = 0; } + for (auth_addresses::iterator j=auth_daily_addresses.begin(); j!=auth_daily_addresses.end(); j++) { + delete (*j).second; + } pthread_mutex_unlock(&rate_mutex); loop2 = 0; }