# HG changeset patch # User Carl Byington # Date 1243275272 25200 # Node ID 5c3e9bf45bb560024e7045997db57bc2edc5862d # Parent 768ce0f23149d54aa4a8018b56f53d0ce2731468 Add whitelisting by regex expression filtering. Add queueid to whitelist extension log message. diff -r 768ce0f23149 -r 5c3e9bf45bb5 ChangeLog --- a/ChangeLog Fri May 08 15:21:40 2009 -0700 +++ b/ChangeLog Mon May 25 11:14:32 2009 -0700 @@ -1,3 +1,7 @@ +6.23 2009-05-25 + Add whitelisting by regex expression filtering. + Add queueid to whitelist extension log message. + 6.22 2009-05-08 Prevent auto whitelisting due to outgoing multipart/report delivery notifications. diff -r 768ce0f23149 -r 5c3e9bf45bb5 NEWS --- a/NEWS Fri May 08 15:21:40 2009 -0700 +++ b/NEWS Mon May 25 11:14:32 2009 -0700 @@ -1,3 +1,4 @@ +6.23 2009-05-25 Add whitelisting by regex expression filtering. 6.22 2009-05-08 Prevent auto whitelisting due to outgoing multipart/report delivery notifications. 6.21 2009-01-03 Fixes to compile on old systems without memrchr or string::clear(). 6.20 2008-12-27 Never whitelist self addressed mail. diff -r 768ce0f23149 -r 5c3e9bf45bb5 configure.in --- a/configure.in Fri May 08 15:21:40 2009 -0700 +++ b/configure.in Mon May 25 11:14:32 2009 -0700 @@ -1,6 +1,6 @@ AC_PREREQ(2.59) -AC_INIT(dnsbl,6.22,carl@five-ten-sg.com) +AC_INIT(dnsbl,6.23,carl@five-ten-sg.com) AC_CONFIG_SRCDIR([config.h.in]) AC_CONFIG_HEADER([config.h]) diff -r 768ce0f23149 -r 5c3e9bf45bb5 dnsbl.conf --- a/dnsbl.conf Fri May 08 15:21:40 2009 -0700 +++ b/dnsbl.conf Mon May 25 11:14:32 2009 -0700 @@ -61,6 +61,8 @@ 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$"; + env_to { # !! replace this with your domain names # child contexts are not allowed to specify recipient addresses outside these domains diff -r 768ce0f23149 -r 5c3e9bf45bb5 dnsbl.spec.in --- a/dnsbl.spec.in Fri May 08 15:21:40 2009 -0700 +++ b/dnsbl.spec.in Mon May 25 11:14:32 2009 -0700 @@ -96,6 +96,9 @@ %changelog +* Mon May 25 2009 Carl Byington - 6.23-1 +- Add whitelisting by regex expression filtering. + * Fri May 08 2009 Carl Byington - 6.22-1 - Prevent auto whitelisting due to outgoing multipart/report delivery notifications. diff -r 768ce0f23149 -r 5c3e9bf45bb5 src/context.cpp --- a/src/context.cpp Fri May 08 15:21:40 2009 -0700 +++ b/src/context.cpp Mon May 25 11:14:32 2009 -0700 @@ -62,6 +62,7 @@ const char *token_uribl; const char *token_verify; const char *token_white; +const char *token_white_regex; const char *token_yes; const char *token_myhostname; @@ -692,6 +693,7 @@ verifier = NULL; generic_regx = NULL; generic_message = NULL; + white_regx = NULL; autowhite_file = NULL; whitelister = NULL; env_from_default = (parent) ? token_inherit : token_unknown; @@ -720,6 +722,7 @@ delete d; } if (generic_regx) regfree(&generic_pattern); + if (white_regx) regfree(&white_pattern); } @@ -738,6 +741,26 @@ } +bool CONTEXT::set_white(const char *regx) +{ + int rc = 0; + if (white_regx) regfree(&white_pattern); + white_regx = regx; + if (white_regx) { + rc = regcomp(&white_pattern, regx, REG_NOSUB | REG_ICASE | REG_EXTENDED); + } + return rc; // true iff bad pattern +} + + +bool CONTEXT::white_match(const char *from) +{ + return (from && + white_regx && + (0 == regexec(&white_pattern, from, 0, NULL, 0))); +} + + bool CONTEXT::set_generic(const char *regx, const char *msg) { int rc = 0; @@ -806,7 +829,7 @@ } -const char *CONTEXT::find_from(const char *from, bool update_white) { +const char *CONTEXT::find_from(const char *from, bool update_white, const char *queueid) { WHITELISTERP w = whitelister; CONTEXTP p = parent; while (!w && p) { @@ -814,12 +837,12 @@ p = p->parent; } if (w && w->is_white(from)) { - if (update_white) { + if (update_white && queueid) { // update senders timestamp to extend the whitelisting period if (debug_syslog > 1) { char buf[maxlen]; char msg[maxlen]; - snprintf(msg, sizeof(msg), "extend whitelist reply from <%s> in context %s", from, get_full_name(buf,maxlen)); + snprintf(msg, sizeof(msg), "%s: extend whitelist reply from <%s> in context %s", queueid, from, get_full_name(buf,maxlen)); my_syslog(msg); } w->sent(strdup(from)); @@ -844,6 +867,10 @@ } } } + if ((rc == token_inherit) || (rc == token_unknown)) { + bool ok = white_match(from); + if (ok) rc = token_white; + } if ((rc == token_inherit) && parent) return parent->find_from(from); return (rc == token_inherit) ? token_unknown : rc; } @@ -1067,6 +1094,10 @@ printf("%s \"%s\"; \n", indent, generic_message); } + if (white_regx) { + printf("%s white_regex \"%s\"; \n", indent, white_regx); + } + if (autowhite_file && whitelister) { printf("%s autowhite %d %s; \n", indent, whitelister->get_days(), autowhite_file); } @@ -1465,6 +1496,20 @@ //////////////////////////////////////////////// // +bool parse_white(TOKEN &tok, CONFIG &dc, CONTEXT &me); +bool parse_white(TOKEN &tok, CONFIG &dc, CONTEXT &me) { + const char *regx = tok.next(); + if (!tsa(tok, token_semi)) return false; + if (me.set_white(regx)) { + tok.token_error("invalid regular expression %s", regx, regx); + return false; + } + return true; +} + + +//////////////////////////////////////////////// +// bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me); bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me) { int days = tok.nextint(); @@ -1607,6 +1652,9 @@ else if (have == token_generic) { if (!parse_generic(tok, dc, *con)) return false; } + else if (have == token_white_regex) { + if (!parse_white(tok, dc, *con)) return false; + } else if (have == token_autowhite) { if (!parse_autowhite(tok, dc, *con)) return false; } @@ -1708,6 +1756,7 @@ token_uribl = register_string("uribl"); token_verify = register_string("verify"); token_white = register_string("white"); + token_white_regex = register_string("white_regex"); token_yes = register_string("yes"); if (gethostname(myhostname, HOST_NAME_MAX+1) != 0) { diff -r 768ce0f23149 -r 5c3e9bf45bb5 src/context.h --- a/src/context.h Fri May 08 15:21:40 2009 -0700 +++ b/src/context.h Mon May 25 11:14:32 2009 -0700 @@ -135,6 +135,8 @@ const char * generic_regx; // pointer to generic regular expression const char * generic_message; // pointer to generic message with one %s regex_t generic_pattern; // compiled regex pattern + const char * white_regx; // pointer to whitelist regular expression + regex_t white_pattern; // compiled regex pattern const char * autowhite_file; // file to use for automatic whitelisting WHITELISTERP whitelister; // pointer to the auto whitelister structure string_map env_from; // map senders to white/black/unknown @@ -193,7 +195,7 @@ void add_from(const char *from, const char *status) {env_from[from] = status;}; void add_from_context(const char *from, CONTEXTP con) {env_from_context[from] = con;}; void set_from_default(const char *status) {env_from_default = status;}; - const char* find_from(const char *from, bool update_white = false); + const char* find_from(const char *from, bool update_white = false, const char *queueid = NULL); CONTEXTP find_context(const char *from); CONTEXTP find_from_context_name(const char *name); @@ -218,6 +220,9 @@ void add_dnsbl(DNSBLP dns) {dnsbl_list.push_back(dns);}; DNSBLP find_dnsbl(const char *name); + bool set_white(const char *regx); + bool white_match(const char *from); + bool set_generic(const char *regx, const char *msg); const char* generic_match(const char *client); @@ -312,6 +317,7 @@ extern const char *token_uribl; extern const char *token_verify; extern const char *token_white; +extern const char *token_white_regex; extern const char *token_yes; extern pthread_mutex_t verifier_mutex; // protect the verifier map diff -r 768ce0f23149 -r 5c3e9bf45bb5 src/dnsbl.cpp --- a/src/dnsbl.cpp Fri May 08 15:21:40 2009 -0700 +++ b/src/dnsbl.cpp Mon May 25 11:14:32 2009 -0700 @@ -1051,7 +1051,7 @@ // priv.mailaddr sending original message to loto CONTEXT &con = *(dc.find_context(loto)->find_context(priv.mailaddr)); VERIFYP ver = con.find_verify(loto); - const char *fromvalue = con.find_from(priv.mailaddr, true); + const char *fromvalue = con.find_from(priv.mailaddr, true, priv.queueid); // tell spam assassin and dccifd about this recipient if (priv.assassin) priv.assassin->mlfi_envrcpt(ctx, loto); if (priv.dccifd) priv.dccifd->mlfi_envrcpt(ctx, loto, con.get_grey() && !priv.authenticated); diff -r 768ce0f23149 -r 5c3e9bf45bb5 xml/dnsbl.in --- a/xml/dnsbl.in Fri May 08 15:21:40 2009 -0700 +++ b/xml/dnsbl.in Mon May 25 11:14:32 2009 -0700 @@ -19,7 +19,7 @@ - 2008-06-08 + 2009-05-25 @@ -364,6 +364,13 @@ parent context. + If the mail has not been accepted or rejected yet, and the filtering + context (or any ancestor context) specifies a non-empty whitelist regular + expression, then we check the envelope from value against that regex. + The mail is accepted if the envelope from value matches the specified regular + expression. + + If the mail has not been accepted or rejected yet, the dns lists specified in the filtering context are checked and the mail is rejected if any list has an A record for the standard dns based lookup scheme @@ -586,7 +593,7 @@ - 2008-06-08 + 2009-05-25 @@ -620,7 +627,7 @@ CONFIG = {CONTEXT ";"}+ CONTEXT = "context" NAME "{" {STATEMENT}+ "}" STATEMENT = (DNSBL | DNSBLLIST | CONTENT | ENV-TO | VERIFY | GENERIC - | AUTOWHITE | CONTEXT | ENV-FROM | RATE-LIMIT) ";" + | W_REGEX | AUTOWHITE | CONTEXT | ENV-FROM | RATE-LIMIT) ";" DNSBL = "dnsbl" NAME DNSPREFIX ERROR-MSG1 @@ -659,6 +666,7 @@ VERIFY = "verify" HOSTNAME ";" GENERIC = "generic" REGULAREXPRESSION ERROR-MSG4 ";" +W-REGEX = "white_regex" REGULAREXPRESSION ";" ERROR-MSG4 = string containing exactly one %s replacement token which is replaced with the client name AUTOWHITE = "autowhite" DAYS FILENAME ";" @@ -741,6 +749,8 @@ 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"; + env_to { # !! replace this with your domain names # child contexts are not allowed to specify recipient addresses outside these domains