diff src/dnsbl.cpp @ 192:8f4a9a37d4d9

delay autowhitelisting to avoid out of office reply bots
author carl
date Sun, 11 Nov 2007 12:49:25 -0800
parents 2a67d31099c3
children 3ea79ef741a0
line wrap: on
line diff
--- a/src/dnsbl.cpp	Sat Nov 10 16:20:51 2007 -0800
+++ b/src/dnsbl.cpp	Sun Nov 11 12:49:25 2007 -0800
@@ -257,6 +257,7 @@
 	want_spamassassin	= false;
 	want_dccgrey		= false;
 	want_dccbulk		= false;
+    is_bulk_precedence  = false;
 	content_context 	= NULL;
 	memory				= NULL;
 	scanner 			= NULL;
@@ -285,6 +286,7 @@
 	if (queueid)	   free(queueid);
 	if (authenticated) free(authenticated);
 	if (client_name)   free(client_name);
+    delayer.clear();
 	discard(env_to);
 	if (memory)   delete memory;
 	if (scanner)  delete scanner;
@@ -302,6 +304,7 @@
 		want_spamassassin	= false;
 		want_dccgrey		= false;
 		want_dccbulk		= false;
+        is_bulk_precedence  = false;
 		content_context 	= NULL;
 		memory				= NULL;
 		scanner 			= NULL;
@@ -950,17 +953,22 @@
 // wrapper if the mail client did not, but the current version does not do
 // that.  So the <> wrapper is now optional.  It may have mixed case, just
 // as the mail client sent it.	We dup the string and convert the duplicate
-// to lower case.
+// to lower case. Some clients enclose the entire address in single quotes,
+// so we strip those as well.
 //
 char *to_lower_string(char *email);
 char *to_lower_string(char *email) {
 	int n = strlen(email);
-	if (*email == '<') {
+    if (email[0] == '<') {
 		// assume it also ends with >
 		n -= 2;
 		if (n < 1) return strdup(email);	// return "<>"
 		email++;
 	}
+    if ((email[0] == '\'') && (email[n-1] == '\'') && (n > 2)) {
+        n -= 2;
+        email++;
+    }
 	char *key = strdup(email);
 	key[n] = '\0';
 	for (int i=0; i<n; i++) key[i] = tolower(key[i]);
@@ -1110,14 +1118,15 @@
 	// if needed to ensure we can accept replies
 	loto = to_lower_string(rcptaddr);
 	WHITELISTERP w = con2.find_autowhite(loto, priv.mailaddr);
+    // check if local part is too big
+    const int max_local_size = 30;
+    char *p = strchr(loto, '@');
+    int len = (p) ? p-loto : max_local_size;
+    if (len >= max_local_size) w = NULL;    // too big, pretend we don't have a whitelister
+    // record it if we have a whitelister
 	if (w) {
-		if (debug_syslog > 1) {
-			char buf[maxlen];
-			char msg[maxlen];
-			snprintf(msg, sizeof(msg), "whitelist reply from <%s> in context %s", loto, con2.get_full_name(buf,maxlen));
-			my_syslog(&priv, msg);
-		}
-		w->sent(loto);	// don't free it, the whitelister takes ownership of the string
+        DELAYWHITEP dwp = new DELAYWHITE(loto, w, &con2);
+        priv.delayer.push_back(dwp);
 	}
 	else {
 		free(loto);
@@ -1154,6 +1163,10 @@
 sfsistat mlfi_header(SMFICTX* ctx, char* headerf, char* headerv)
 {
 	mlfiPriv &priv = *MLFIPRIV;
+    // detect precedence:bulk for avoiding autowhitelisting
+    if ((strcasecmp(headerf, "precedence") == 0) &&
+        (strcasecmp(headerv, "bulk") == 0)) priv.is_bulk_precedence = true;
+    // other headers are only needed for content filtering
 	if (priv.authenticated) 	return SMFIS_CONTINUE;
 	if (priv.only_whites)		return SMFIS_CONTINUE;
 	if (priv.want_spamassassin) priv.assassin->mlfi_header(headerf, headerv);
@@ -1164,6 +1177,25 @@
 sfsistat mlfi_eoh(SMFICTX* ctx)
 {
 	mlfiPriv &priv = *MLFIPRIV;
+    // delayed autowhitelisting
+    while (!priv.delayer.empty()) {
+        DELAYWHITEP dwp = priv.delayer.front();
+        if (!priv.is_bulk_precedence) {
+            char         *loto = dwp->get_loto();
+            WHITELISTERP w     = dwp->get_w();
+            CONTEXTP     con2  = dwp->get_con();
+            if (debug_syslog > 1) {
+                char buf[maxlen];
+                char msg[maxlen];
+                snprintf(msg, sizeof(msg), "whitelist reply from <%s> in context %s", loto, con2->get_full_name(buf,maxlen));
+                my_syslog(&priv, msg);
+            }
+            w->sent(loto);  // don't free it, the whitelister takes ownership of the string
+        }
+        delete dwp;
+        priv.delayer.pop_front();
+    }
+    // content filtering
 	if (priv.authenticated) 	return SMFIS_CONTINUE;
 	if (priv.only_whites)		return SMFIS_CONTINUE;
 	if (priv.want_spamassassin) priv.assassin->mlfi_eoh();