diff src/dnsbl.cpp @ 136:f4746d8a12a3

add smtp auth rate limits
author carl
date Tue, 26 Sep 2006 13:59:14 -0700
parents f9917ce924a3
children a6190f7798f4
line wrap: on
line diff
--- a/src/dnsbl.cpp	Wed Aug 02 21:33:34 2006 -0700
+++ b/src/dnsbl.cpp	Tue Sep 26 13:59:14 2006 -0700
@@ -86,6 +86,7 @@
 pthread_mutex_t  syslog_mutex;
 pthread_mutex_t  resolve_mutex;
 pthread_mutex_t  fd_pool_mutex;
+pthread_mutex_t  rate_mutex;
 
 std::set<int>	 fd_pool;
 int    NULL_SOCKET			   = -1;
@@ -95,6 +96,7 @@
 time_t last_error_time;
 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
 
 
 struct ns_map {
@@ -141,6 +143,19 @@
 
 
 ////////////////////////////////////////////////
+// helper to manipulate recipient counts
+//
+int incr_rcpt_count(char *user);
+int incr_rcpt_count(char *user) {
+	pthread_mutex_lock(&rate_mutex);
+		rcpt_rates::iterator i = rcpt_counts.find(user);
+		int c = (i == rcpt_counts.end()) ? 0 : (*i).second;
+		rcpt_counts[user] = c++;
+	pthread_mutex_unlock(&rate_mutex);
+	return c;
+}
+
+////////////////////////////////////////////////
 // helper to discard the strings held by a context_map
 //
 void discard(context_map &cm);
@@ -224,7 +239,7 @@
 	ip					= 0;
 	mailaddr			= NULL;
 	queueid 			= NULL;
-	authenticated		= false;
+	authenticated		= NULL;
 	have_whites 		= false;
 	only_whites 		= true;
 	memory				= NULL;
@@ -247,13 +262,14 @@
 void mlfiPriv::reset(bool final) {
 	if (mailaddr) free(mailaddr);
 	if (queueid)  free(queueid);
+	if (authenticated) free(authenticated);
 	discard(env_to);
 	if (memory)  delete memory;
 	if (scanner) delete scanner;
 	if (!final) {
 		mailaddr			= NULL;
 		queueid 			= NULL;
-		authenticated		= false;
+		authenticated		= NULL;
 		have_whites 		= false;
 		only_whites 		= true;
 		memory				= NULL;
@@ -912,7 +928,8 @@
 {
 	mlfiPriv &priv	   = *MLFIPRIV;
 	priv.mailaddr	   = to_lower_string(from[0]);
-	priv.authenticated = (smfi_getsymval(ctx, "{auth_authen}") != NULL);
+	priv.authenticated = smfi_getsymval(ctx, "{auth_authen}");
+	if (priv.authenticated) priv.authenticated = strdup(priv.authenticated);
 	return SMFIS_CONTINUE;
 }
 
@@ -936,8 +953,22 @@
 	char *fromvalue = con.find_from(priv.mailaddr);
 	status st;
 	if (priv.authenticated) {
+		int c = incr_rcpt_count(priv.authenticated);
+		int l = dc.default_context->find_rate(priv.authenticated);
+		if (c > l) {
+			smfi_setreply(ctx, "550", "5.7.1", "recipient rate limit exceeded");
+			return SMFIS_REJECT;
+		}
+		else {
+			if (debug_syslog > 1) {
+				char buf[maxlen];
+				char msg[maxlen];
+				snprintf(msg, sizeof(msg), "authenticated id %s (%d recipients, %d limit)", priv.authenticated, c, l);
+				my_syslog(&priv, msg);
+			}
 		st = white;
 	}
+	}
 	else if (fromvalue == token_black) {
 		st = black;
 	}
@@ -1127,14 +1158,24 @@
 //	thread to watch the old config files for changes
 //	and reload when needed. we also cleanup old
 //	configs whose reference count has gone to zero.
+//	we also clear the SMTP AUTH recipient counts hourly
 //
 void* config_loader(void *arg);
 void* config_loader(void *arg) {
+	int loop = 0;
 	typedef set<CONFIG *> configp_set;
 	configp_set old_configs;
 	while (loader_run) {
 		sleep(180);  // look for modifications every 3 minutes
 		if (!loader_run) break;
+		loop++;
+		if (loop == 20) {
+			// three minutes thru each loop, 20 loops per hour
+			// clear the recipient counts
+			pthread_mutex_lock(&rate_mutex);
+				rcpt_counts.clear();
+			pthread_mutex_unlock(&rate_mutex);
+		}
 		CONFIG &dc = *config;
 		time_t then = dc.load_time;
 		struct stat st;