# HG changeset patch # User carl # Date 1191563121 25200 # Node ID d6531c702be378b44558e758a8d222c1d245dfea # Parent a4d313c2460b141e54add6c0334766ca0e13bc17 embedded dcc filtering diff -r a4d313c2460b -r d6531c702be3 ChangeLog --- a/ChangeLog Sun Sep 30 10:27:14 2007 -0700 +++ b/ChangeLog Thu Oct 04 22:45:21 2007 -0700 @@ -1,7 +1,11 @@ $Id$ -6.11 2007-09-30 - Add DCC filtering via dccifd. +6.11 2007-10-04 + Add DCC filtering via dccifd. Drop to 60 seconds the time we will + keep idle smtp verify sockets around. This needs to be about half + the value of confTO_COMMAND configured on the verify targets. + Fix potential race condition or buffer overflow caused by static + buffer referenced by multiple threads. 6.10 2007-09-23 Don't whitelist addresses with embedded blanks, or the empty diff -r a4d313c2460b -r d6531c702be3 Makefile.am --- a/Makefile.am Sun Sep 30 10:27:14 2007 -0700 +++ b/Makefile.am Thu Oct 04 22:45:21 2007 -0700 @@ -13,9 +13,9 @@ chkconfig: dnsbl /usr/bin/getent passwd dnsbl >/dev/null || /usr/sbin/useradd -r -d $(sysconfdir)/dnsbl -M -c "dnsbl pseudo-user" -s /sbin/nologin dnsbl >/dev/null mv -f $(sysconfdir)/dnsbl/dnsbl /etc/rc.d/init.d - mkdir $(sysconfdir)/dnsbl/autowhite + mkdir -p $(sysconfdir)/dnsbl/autowhite chown dnsbl:root $(sysconfdir)/dnsbl/autowhite - mkdir $(sysconfdir)/dnsbl/.spamassassin + mkdir -p $(sysconfdir)/dnsbl/.spamassassin chown dnsbl:root $(sysconfdir)/dnsbl/.spamassassin /sbin/chkconfig --del dnsbl /sbin/chkconfig --add dnsbl diff -r a4d313c2460b -r d6531c702be3 NEWS --- a/NEWS Sun Sep 30 10:27:14 2007 -0700 +++ b/NEWS Thu Oct 04 22:45:21 2007 -0700 @@ -1,6 +1,6 @@ $Id$ -6.11 2007-09-30 Add DCC filtering via dccifd. +6.11 2007-10-04 Add DCC filtering via dccifd. Fix static buffer referenced by multiple threads. 6.10 2007-09-23 Don't whitelist addresses with embedded blanks, or the empty path. 6.09 2007-09-06 Fix memory leak. Update timestamps when receiving from auto-whitelisted sender. 6.08 2007-08-30 Don't do generic reverse dns filtering on authenticated connections. diff -r a4d313c2460b -r d6531c702be3 dnsbl.conf --- a/dnsbl.conf Sun Sep 30 10:27:14 2007 -0700 +++ b/dnsbl.conf Thu Oct 04 22:45:21 2007 -0700 @@ -17,6 +17,9 @@ host_limit on 20 "Mail containing excessive host names rejected"; host_limit soft 20; spamassassin 4; + require_match yes; + dcc_greylist yes; + dcc_bulk_threshold 50; }; // backscatter prevention - don't send bounces for mail that we accepted but could not forward @@ -50,6 +53,9 @@ html_limit off; host_limit soft 20; spamassassin 5; + require_match yes; + dcc_greylist yes; + dcc_bulk_threshold 20; }; generic "(^|[.-])(ppp|h|host)?([0-9]{1,3}[.-](Red-|dynamic[.-])?){4}" @@ -83,8 +89,10 @@ context minimal { dnsbl_list sbl; - content on {}; + content on { spamassassin 10; + dcc_bulk_threshold many; + }; generic "^$ " " "; # regex cannot match, to disable generic rdns rejects env_to { }; diff -r a4d313c2460b -r d6531c702be3 dnsbl.rc.in --- a/dnsbl.rc.in Sun Sep 30 10:27:14 2007 -0700 +++ b/dnsbl.rc.in Thu Oct 04 22:45:21 2007 -0700 @@ -22,7 +22,9 @@ echo -n "Starting dnsbl-milter: " if [ ! -f /var/lock/subsys/dnsbl ]; then cd SYSCONFDIR/dnsbl # conf file is here - SBINDIR/dnsbl -d 10 -r /var/run/dnsbl/dnsbl.resolver.sock -p local:/var/run/dnsbl/dnsbl.sock + DCCIFD= + [ -S /var/dcc/dccifd ] && DCCIFD='-b /var/dcc/dccifd' + SBINDIR/dnsbl -d 10 $DCCIFD -r /var/run/dnsbl/dnsbl.resolver.sock -p local:/var/run/dnsbl/dnsbl.sock RETVAL=$? pid=`pidof -s SBINDIR/dnsbl` if [ $pid ] diff -r a4d313c2460b -r d6531c702be3 sendmail.st Binary file sendmail.st has changed diff -r a4d313c2460b -r d6531c702be3 src/Makefile.am --- a/src/Makefile.am Sun Sep 30 10:27:14 2007 -0700 +++ b/src/Makefile.am Thu Oct 04 22:45:21 2007 -0700 @@ -1,5 +1,5 @@ sbin_PROGRAMS = dnsbl -dnsbl_SOURCES = dnsbl.cpp dnsbl.h spamass.cpp spamass.h context.cpp context.h tokenizer.cpp tokenizer.h scanner.cpp scanner.h includes.h +dnsbl_SOURCES = dnsbl.cpp dnsbl.h dccifd.cpp dccifd.h spamass.cpp spamass.h context.cpp context.h tokenizer.cpp tokenizer.h scanner.cpp scanner.h includes.h EXTRA_DIST = test.cpp # set the include path found by configure diff -r a4d313c2460b -r d6531c702be3 src/context.cpp --- a/src/context.cpp Sun Sep 30 10:27:14 2007 -0700 +++ b/src/context.cpp Thu Oct 04 22:45:21 2007 -0700 @@ -23,9 +23,12 @@ char *token_autowhite; char *token_black; +char *token_cctld; char *token_content; char *token_context; +char *token_dccbulk; char *token_dccfrom; +char *token_dccgrey; char *token_dccto; char *token_default; char *token_dnsbl; @@ -43,22 +46,24 @@ char *token_lbrace; char *token_mailhost; char *token_many; +char *token_no; char *token_off; +char *token_ok; char *token_ok2; -char *token_ok; char *token_on; char *token_rate; char *token_rbrace; +char *token_require; char *token_semi; char *token_soft; char *token_spamassassin; char *token_substitute; char *token_tld; -char *token_cctld; char *token_unknown; char *token_uribl; char *token_verify; char *token_white; +char *token_yes; char *token_myhostname; #ifndef HOST_NAME_MAX @@ -74,7 +79,7 @@ string_set all_strings; // owns all the strings, only modified by the config loader thread const int maxlen = 1000; // used for snprintf buffers -const int maxsmtp_age = 120;// smtp verify sockets older than this are ancient +const int maxsmtp_age = 60;// smtp verify sockets older than this are ancient const int maxauto_age = 600;// auto whitelister delay before flushing to file extern int NULL_SOCKET; const time_t ERROR_SMTP_SOCKET_TIME = 600; // number of seconds between attempts to open a socket to an smtp server @@ -697,6 +702,9 @@ tag_limit = (parent) ? parent->tag_limit : 0; tag_limit_message = NULL; spamassassin_limit = (parent) ? parent->spamassassin_limit : 0; + 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; } @@ -917,13 +925,19 @@ } -bool CONTEXT::acceptable_content(recorder &memory, int score, string& msg) { +bool CONTEXT::acceptable_content(recorder &memory, int score, int bulk, string& msg) { if (spamassassin_limit && (score > spamassassin_limit)) { char buf[maxlen]; snprintf(buf, sizeof(buf), "Mail rejected - spam assassin score %d", score); msg = string(buf); return false; } + if (dcc_bulk_threshold && (bulk > dcc_bulk_threshold)) { + char buf[maxlen]; + snprintf(buf, sizeof(buf), "Mail rejected - dcc score %d", bulk); + msg = string(buf); + return false; + } if (memory.excessive_bad_tags(tag_limit)) { msg = string(tag_limit_message); return false; @@ -1016,6 +1030,11 @@ printf("%s html_limit off; \n", indent); } printf("%s spamassassin %d; \n", indent, spamassassin_limit); + printf("%s require_match %s; \n", indent, (require_match) ? "yes" : "no"); + printf("%s dcc_greylist %s; \n", indent, (dcc_greylist) ? "yes" : "no"); + if (dcc_bulk_threshold == 0) printf("%s dcc_bulk_threshold off; \n", indent); + else if (dcc_bulk_threshold == 1000) printf("%s dcc_bulk_threshold many; \n", indent); + else printf("%s dcc_bulk_threshold %d; \n", indent, dcc_bulk_threshold); printf("%s }; \n", indent); spamass |= (spamassassin_limit != 0); } @@ -1214,16 +1233,6 @@ } if (!tsa(tok, token_semi)) return false; } - else if (have == token_cctld) { - if (!tsa(tok, token_lbrace)) return false; - while (true) { - char *have = tok.next(); - if (!have) break; - if (have == token_rbrace) break; // done - me.add_cctld(have); - } - if (!tsa(tok, token_semi)) return false; - } else if (have == token_tld) { if (!tsa(tok, token_lbrace)) return false; while (true) { @@ -1234,19 +1243,13 @@ } if (!tsa(tok, token_semi)) return false; } - else if (have == token_html_limit) { - have = tok.next(); - if (have == token_on) { - me.set_tag_limit(tok.nextint()); - me.set_tag_message(tok.next()); - } - else if (have == token_off) { - me.set_tag_limit(0); - me.set_tag_message(NULL); - } - else { - tok.token_error("on/off", have); - return false; + else if (have == token_cctld) { + if (!tsa(tok, token_lbrace)) return false; + while (true) { + char *have = tok.next(); + if (!have) break; + if (have == token_rbrace) break; // done + me.add_cctld(have); } if (!tsa(tok, token_semi)) return false; } @@ -1269,6 +1272,22 @@ } if (!tsa(tok, token_semi)) return false; } + else if (have == token_html_limit) { + have = tok.next(); + if (have == token_on) { + me.set_tag_limit(tok.nextint()); + me.set_tag_message(tok.next()); + } + else if (have == token_off) { + me.set_tag_limit(0); + me.set_tag_message(NULL); + } + else { + tok.token_error("on/off", have); + return false; + } + if (!tsa(tok, token_semi)) return false; + } else if (have == token_host_limit) { have = tok.next(); if (have == token_on) { @@ -1296,6 +1315,41 @@ me.set_spamassassin_limit(tok.nextint()); if (!tsa(tok, token_semi)) return false; } + else if (have == token_require) { + have = tok.next(); + if (have == token_yes) me.set_require(true); + else if (have == token_no) me.set_require(false); + else { + tok.token_error("yes/no", have); + return false; + } + if (!tsa(tok, token_semi)) return false; + } + else if (have == token_dccgrey) { + have = tok.next(); + if (have == token_yes) me.set_grey(true); + else if (have == token_no) me.set_grey(false); + else { + tok.token_error("yes/no", have); + return false; + } + if (!tsa(tok, token_semi)) return false; + } + else if (have == token_dccbulk) { + have = tok.next(); + if (have == token_off) me.set_bulk(0); + else if (have == token_many) me.set_bulk(1000); + else { + char *e; + long i = strtol(have, &e, 10); + if (*e != '\0') { + tok.token_error("integer", have); + return false; + } + me.set_bulk((int)i); + } + if (!tsa(tok, token_semi)) return false; + } else if (have == token_rbrace) { break; // done } @@ -1607,7 +1661,9 @@ token_cctld = register_string("cctld"); token_content = register_string("content"); token_context = register_string("context"); + token_dccbulk = register_string("dcc_bulk_threshold"); token_dccfrom = register_string("dcc_from"); + token_dccgrey = register_string("dcc_greylist"); token_dccto = register_string("dcc_to"); token_default = register_string("default"); token_dnsbl = register_string("dnsbl"); @@ -1625,12 +1681,14 @@ token_lbrace = register_string("{"); token_mailhost = register_string("mail_host"); token_many = register_string("many"); + token_no = register_string("no"); token_off = register_string("off"); token_ok = register_string("ok"); token_ok2 = register_string("ok2"); token_on = register_string("on"); token_rate = register_string("rate_limit"); token_rbrace = register_string("}"); + token_require = register_string("require_match"); token_semi = register_string(";"); token_soft = register_string("soft"); token_spamassassin = register_string("spamassassin"); @@ -1640,6 +1698,7 @@ token_uribl = register_string("uribl"); token_verify = register_string("verify"); token_white = register_string("white"); + token_yes = register_string("yes"); if (gethostname(myhostname, HOST_NAME_MAX+1) != 0) { strncpy(myhostname, "localhost", HOST_NAME_MAX+1); diff -r a4d313c2460b -r d6531c702be3 src/context.h --- a/src/context.h Sun Sep 30 10:27:14 2007 -0700 +++ b/src/context.h Thu Oct 04 22:45:21 2007 -0700 @@ -147,6 +147,9 @@ int tag_limit; // limit on bad html tags char * tag_limit_message; // error message for excessive bad html tags int spamassassin_limit; // max score from spamassassin + bool require_match; // require matching context filtering context + bool dcc_greylist; // should we do dcc greylisting? + 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 int default_rcpt_rate; // if not specified per user @@ -210,7 +213,14 @@ bool set_generic(char *regx, char *msg); char* generic_match(char *client); + void set_require(bool r) {require_match = r; }; + void set_grey(bool g) {dcc_greylist = g; }; + void set_bulk(int b) {dcc_bulk_threshold = b; }; + bool get_content_filtering() {return content_filtering; }; + bool get_require() {return require_match; }; + bool get_grey() {return dcc_greylist; }; + int get_bulk() {return dcc_bulk_threshold;}; int get_host_limit() {return host_limit; }; bool get_host_random() {return host_random; }; int get_spamassassin_limit() {return (content_filtering) ? spamassassin_limit : 0;}; @@ -224,7 +234,7 @@ string_set& get_html_tags(); dnsblp_list& get_dnsbl_list(); - bool acceptable_content(recorder &memory, int score, string& msg); + bool acceptable_content(recorder &memory, int score, int bulk, string& msg); bool ignore_host(char *host); void dump(bool isdefault, bool &spamass, int level = 0); @@ -260,7 +270,9 @@ extern char *token_cctld; extern char *token_content; extern char *token_context; +extern char *token_dccbulk; extern char *token_dccfrom; +extern char *token_dccgrey; extern char *token_dccto; extern char *token_default; extern char *token_dnsbl; @@ -278,12 +290,14 @@ extern char *token_lbrace; extern char *token_mailhost; extern char *token_many; +extern char *token_no; extern char *token_off; +extern char *token_ok; extern char *token_ok2; -extern char *token_ok; extern char *token_on; extern char *token_rate; extern char *token_rbrace; +extern char *token_require; extern char *token_semi; extern char *token_soft; extern char *token_spamassassin; @@ -291,7 +305,9 @@ extern char *token_tld; extern char *token_unknown; extern char *token_uribl; +extern char *token_verify; extern char *token_white; +extern char *token_yes; extern pthread_mutex_t verifier_mutex; // protect the verifier map extern pthread_mutex_t whitelister_mutex; // protect the diff -r a4d313c2460b -r d6531c702be3 src/dnsbl.cpp --- a/src/dnsbl.cpp Sun Sep 30 10:27:14 2007 -0700 +++ b/src/dnsbl.cpp Thu Oct 04 22:45:21 2007 -0700 @@ -255,14 +255,18 @@ have_whites = false; only_whites = true; want_spamassassin = false; + want_dccgrey = false; + want_dccbulk = false; + content_context = NULL; memory = NULL; scanner = NULL; - assassin = NULL; content_suffix = NULL; content_message = NULL; uribl_suffix = NULL; uribl_message = NULL; content_host_ignore = NULL; + assassin = NULL; + dccifd = NULL; } mlfiPriv::~mlfiPriv() { @@ -285,6 +289,7 @@ if (memory) delete memory; if (scanner) delete scanner; if (assassin) delete assassin; + if (dccifd) delete dccifd; if (!final) { mailaddr = NULL; queueid = NULL; @@ -293,14 +298,18 @@ have_whites = false; only_whites = true; want_spamassassin = false; + want_dccgrey = false; + want_dccbulk = false; + content_context = NULL; memory = NULL; scanner = NULL; - assassin = NULL; content_suffix = NULL; content_message = NULL; uribl_suffix = NULL; uribl_message = NULL; content_host_ignore = NULL; + assassin = NULL; + dccifd = NULL; } } @@ -404,8 +413,8 @@ void mlfiPriv::need_content_filter(char *rcpt, CONTEXT &con) { register_string(env_to, rcpt, &con); if (!memory) { - // first recipient that needs content filtering sets all - // the content filtering parameters + // first recipient that needs content filtering sets + // some of the content filtering parameters memory = new recorder(this, con.get_html_tags(), con.get_content_tlds(), con.get_content_cctlds()); scanner = new url_scanner(memory); content_suffix = con.get_content_suffix(); @@ -718,11 +727,12 @@ // lookup the domain name part of a hostname on the uribl // // if we find part of the hostname on the uribl, return -// true and point found to the part of the hostname that we found. +// true and point found to the part of the hostname that we found +// as a string registered in hosts. // otherwise, return false and preserve the value of found. // -bool uriblookup(mlfiPriv &priv ,char *hostname, char *top, char *&found) ; -bool uriblookup(mlfiPriv &priv, char *hostname, char *top, char *&found) { +bool uriblookup(mlfiPriv &priv, string_set &hosts, char *hostname, char *top, char *&found) ; +bool uriblookup(mlfiPriv &priv, string_set &hosts, char *hostname, char *top, char *&found) { // top is pointer to '.' char at end of base domain, or null for ip address form // so for hostname of www.fred.mydomain.co.uk // top points to-----------------------^ @@ -742,7 +752,7 @@ snprintf(tmp, sizeof(tmp), "found %s on %s", hostname, priv.uribl_suffix); my_syslog(tmp); } - found = hostname; + found = register_string(hosts, hostname); return true; } return false; @@ -757,11 +767,12 @@ // Else, look up three level domain. // // if we find part of the hostname on the uribl, return -// true and point found to the part of the hostname that we found. +// true and point found to the part of the hostname that we found +// as a string registered in hosts. // otherwise, return false and preserve the value of found. // -bool check_uribl(mlfiPriv &priv, char *hostname, char *&found) ; -bool check_uribl(mlfiPriv &priv, char *hostname, char *&found) { +bool check_uribl(mlfiPriv &priv, string_set &hosts, char *hostname, char *&found) ; +bool check_uribl(mlfiPriv &priv, string_set &hosts, char *hostname, char *&found) { in_addr ip; if (inet_aton(hostname, &ip)) { const u_char *src = (const u_char *)&ip.s_addr; @@ -769,9 +780,9 @@ if (src[0] == 10) return false; // don't do dns lookups on rfc1918 space if ((src[0] == 192) && (src[1] == 168)) return false; if ((src[0] == 172) && (16 <= src[1]) && (src[1] <= 31)) return false; - static char adr[sizeof "255.255.255.255"]; + char adr[sizeof "255.255.255.255 "]; snprintf(adr, sizeof(adr), "%u.%u.%u.%u", src[3], src[2], src[1], src[0]); - return (uriblookup(priv, adr, NULL, found)); + return (uriblookup(priv, hosts, adr, NULL, found)); } char *top, *top2, *top3; @@ -785,18 +796,18 @@ string_set::iterator i = priv.memory->get_cctlds()->find(top2+1); string_set::iterator x = priv.memory->get_cctlds()->end(); // if we have a 2-level-cctld, just look at top three levels of the name - if (i != x) return uriblookup(priv, hostname, top2, found); + if (i != x) return uriblookup(priv, hosts, hostname, top2, found); *top2 = '\0'; top3 = strrchr(hostname, '.'); *top2 = '.'; // if we have more than 3 levels in the name, look at the top three levels of the name - if (top3 && uriblookup(priv, hostname, top2, found)) return true; + if (top3 && uriblookup(priv, hosts, hostname, top2, found)) return true; // if that was not found, fall thru to looking at the top two levels } // look at the top two levels of the name - return uriblookup(priv, hostname, top, found); + return uriblookup(priv, hosts, hostname, top, found); } return false; } @@ -863,7 +874,7 @@ return true; } // Check uribl & surbl style list - if (priv.uribl_suffix && check_uribl(priv, host, found)) { + if (priv.uribl_suffix && check_uribl(priv, hosts, host, found)) { msg = priv.uribl_message; return true; } @@ -976,6 +987,9 @@ if (spamc != spamc_empty) { priv.assassin = new SpamAssassin(&priv, priv.ip, priv.helo, priv.mailaddr, priv.queueid); } + if (dccifd_port) { + priv.dccifd = new DccInterface(dccifd_port, &priv, priv.ip, priv.helo, priv.mailaddr, priv.queueid); + } return SMFIS_CONTINUE; } @@ -994,6 +1008,7 @@ } if (priv.assassin) priv.assassin->mlfi_envrcpt(ctx, loto); + if (priv.dccifd) priv.dccifd->mlfi_envrcpt(loto); // priv.mailaddr sending original message to loto CONTEXT &con = *(dc.find_context(loto)->find_context(priv.mailaddr)); VERIFYP ver = con.find_verify(loto); @@ -1089,6 +1104,14 @@ else { free(loto); } + // remember first content filtering context + if (con.get_content_filtering()) { + if (!priv.content_context) priv.content_context = &con; + else if (con.get_require() && (priv.content_context != &con)) { + smfi_setreply(ctx, "452", "4.2.1", "incompatible filtering contexts"); + return SMFIS_TEMPFAIL; + } + } // accept the recipient if (!con.get_content_filtering()) st = white; if (st == oksofar) { @@ -1097,6 +1120,10 @@ priv.only_whites = false; priv.want_spamassassin |= (priv.assassin) && // have spam assassin available and (con.get_spamassassin_limit() != 0); // want to use it with a non-zero score + priv.want_dccgrey |= (priv.dccifd) && // have dcc interface and + (con.get_grey()); // want to use it for greylisting + priv.want_dccbulk |= (priv.dccifd) && // have dcc interface and + (con.get_bulk() != 0); // want to use it for bulk detection } if (st == white) { priv.have_whites = true; @@ -1110,6 +1137,7 @@ if (priv.authenticated) return SMFIS_CONTINUE; if (priv.only_whites) return SMFIS_CONTINUE; if (priv.want_spamassassin) priv.assassin->mlfi_header(headerf, headerv); + if (priv.want_dccgrey || priv.want_dccbulk) priv.dccifd->mlfi_header(ctx, headerf, headerv); return SMFIS_CONTINUE; } @@ -1119,6 +1147,7 @@ if (priv.authenticated) return SMFIS_CONTINUE; if (priv.only_whites) return SMFIS_CONTINUE; if (priv.want_spamassassin) priv.assassin->mlfi_eoh(); + if (priv.want_dccgrey || priv.want_dccbulk) priv.dccifd->mlfi_eoh(); return SMFIS_CONTINUE; } @@ -1128,6 +1157,7 @@ if (priv.authenticated) return SMFIS_CONTINUE; if (priv.only_whites) return SMFIS_CONTINUE; if (priv.want_spamassassin) priv.assassin->mlfi_body(data, len); + if (priv.want_dccgrey || priv.want_dccbulk) priv.dccifd->mlfi_body(data, len); priv.scanner->scan(data, len); return SMFIS_CONTINUE; } @@ -1143,8 +1173,18 @@ // process end of message if (priv.authenticated || priv.only_whites) rc = SMFIS_CONTINUE; else { + // assert env_to not empty, it contains the + // non-whitelisted folks that want content filtering int score = (priv.want_spamassassin) ? priv.assassin->mlfi_eom() : 0; - // assert env_to not empty + bool greylist = false; + int dccbulk = 0; + if (priv.want_dccgrey || priv.want_dccbulk) priv.dccifd->mlfi_eom(greylist, dccbulk); + + if (priv.want_dccgrey && greylist) { + smfi_setreply(ctx, "452", "4.2.1", "temporary greylist embargoed"); + rc = SMFIS_TEMPFAIL; + } + else { char buf[maxlen]; string msg; string_set alive; @@ -1153,8 +1193,9 @@ for (context_map::iterator i=priv.env_to.begin(); i!=priv.env_to.end(); i++) { char *rcpt = (*i).first; CONTEXT &con = *((*i).second); - if (!con.acceptable_content(*priv.memory, score, msg)) { - // bad html tags or excessive hosts or high spam assassin score + if (!con.acceptable_content(*priv.memory, score, dccbulk, msg)) { + // bad html tags or excessive hosts or + // high spam assassin score or dcc bulk threshold exceedeed smfi_delrcpt(ctx, rcpt); } else { @@ -1200,6 +1241,7 @@ rc = SMFIS_CONTINUE; } } + } // reset for a new message on the same connection mlfi_abort(ctx); return rc; diff -r a4d313c2460b -r d6531c702be3 src/dnsbl.h --- a/src/dnsbl.h Sun Sep 30 10:27:14 2007 -0700 +++ b/src/dnsbl.h Thu Oct 04 22:45:21 2007 -0700 @@ -11,6 +11,7 @@ #include "context.h" #include "spamass.h" +#include "dccifd.h" extern int debug_syslog; @@ -36,7 +37,10 @@ char *client_name; // fully qualified host name of the smtp client bool have_whites; // have at least one whitelisted recipient? need to accept content and remove all non-whitelisted recipients if it fails bool only_whites; // every recipient is whitelisted? - bool want_spamassassin; // at least one non-whitelisted recipients has a non zero spamassassin limit + bool want_spamassassin; // at least one non-whitelisted recipient has a non zero spamassassin limit + bool want_dccgrey; // at least one non-whitelisted recipient wants dcc greylisting + bool want_dccbulk; // at least one non-whitelisted recipient wants dcc bulk filtering + CONTEXT *content_context; // first non-whitelisted recipient with a content filtering context context_map env_to; // map each non-whitelisted recipient to their filtering context recorder *memory; // memory for the content scanner url_scanner *scanner; // object to handle body scanning @@ -46,6 +50,7 @@ char *uribl_message; // "" string_set *content_host_ignore; // "" SpamAssassin *assassin; + DccInterface *dccifd; mlfiPriv(); diff -r a4d313c2460b -r d6531c702be3 src/tokenizer.cpp --- a/src/tokenizer.cpp Sun Sep 30 10:27:14 2007 -0700 +++ b/src/tokenizer.cpp Thu Oct 04 22:45:21 2007 -0700 @@ -373,7 +373,7 @@ } if (streams.empty()) return NULL; const int PENDING_LIMIT = 1000; - static u_char buffer[PENDING_LIMIT]; + u_char buffer[PENDING_LIMIT]; int count = 0; state st = s_init; while (true) { diff -r a4d313c2460b -r d6531c702be3 test.bash --- a/test.bash Sun Sep 30 10:27:14 2007 -0700 +++ b/test.bash Thu Oct 04 22:45:21 2007 -0700 @@ -13,9 +13,12 @@ chmod 700 /var/run/dnsbl #chown dnsbl:dnsbl /var/run/dnsbl [ -f "$pid" ] && mv -f $pid $pid.save -#src/dnsbl -d 10 -r /var/run/dnsbl/dnsbl.resolver.sock2 -p local:/var/run/dnsbl/dnsbl.sock2 -#valgrind --leak-check=full --show-reachable=yes src/dnsbl -d 10 -r /var/run/dnsbl/dnsbl.resolver.sock2 -p local:/var/run/dnsbl/dnsbl.sock2 -valgrind src/dnsbl -d 10 -r /var/run/dnsbl/dnsbl.resolver.sock2 -p local:/var/run/dnsbl/dnsbl.sock2 +DCCIFD= +[ -S /var/dcc/dccifd ] && DCCIFD='-b /var/dcc/dccifd' +#valgrind --leak-check=full --show-reachable=yes src/dnsbl -d 10 $DCCIFD -r /var/run/dnsbl/dnsbl.resolver.sock2 -p local:/var/run/dnsbl/dnsbl.sock2 +valgrind --leak-check=full src/dnsbl -d 10 $DCCIFD -r /var/run/dnsbl/dnsbl.resolver.sock2 -p local:/var/run/dnsbl/dnsbl.sock2 +rm -f tracelog* +#strace -e trace=open,close,read,write -o tracelog -f -ff -x src/dnsbl -d 10 $DCCIFD -r /var/run/dnsbl/dnsbl.resolver.sock2 -p local:/var/run/dnsbl/dnsbl.sock2 & sleep 5 P2=`cat $pid` [ -f "$pid.save" ] && mv -f $pid.save $pid diff -r a4d313c2460b -r d6531c702be3 xml/dnsbl.in --- a/xml/dnsbl.in Sun Sep 30 10:27:14 2007 -0700 +++ b/xml/dnsbl.in Thu Oct 04 22:45:21 2007 -0700 @@ -588,8 +588,8 @@ CONTENT = "content" ("on" | "off") "{" {CONTENT-ST}+ "}" CONTENT-ST = (FILTER | URIBL | IGNORE | TLD | CCTLD | HTML-TAGS | - HTML-LIMIT | HOST-LIMIT | SPAMASS) ";" -SPAMASS = "spamassassin" INTEGER + HTML-LIMIT | HOST-LIMIT | SPAMASS | REQUIRE | DCCGREY | + DCCBULK) ";" FILTER = "filter" DNSPREFIX ERROR-MSG2 URIBL = "uribl" DNSPREFIX ERROR-MSG3 IGNORE = "ignore" "{" {HOSTNAME [";"]}+ "}" @@ -608,6 +608,10 @@ HOST-LIMIT = "host_limit" ("on" INTEGER ERROR-MSG | "off" | "soft" INTEGER) +SPAMASS = "spamassassin" INTEGER +REQUIRE = "require_match" ("yes" | "no") +DCCGREY = "dcc_greylist" ("yes" | "no") +DCCBULK = "dcc_bulk_threshold" (INTEGER | "many" | "off") ENV-TO = "env_to" "{" {(TO-ADDR | DCC-TO)}+ "}" TO-ADDR = ADDRESS [";"] @@ -653,6 +657,9 @@ host_limit on 20 "Mail containing excessive host names rejected"; host_limit soft 20; spamassassin 4; + require_match yes; + dcc_greylist yes; + dcc_bulk_threshold 50; }; // backscatter prevention - don't send bounces for mail that we accepted but could not forward @@ -686,6 +693,9 @@ html_limit off; host_limit soft 20; spamassassin 5; + require_match yes; + dcc_greylist yes; + dcc_bulk_threshold 20; }; generic "(^|[.-])(ppp|h|host)?([0-9]{1,3}[.-](Red-|dynamic[.-])?){4}" @@ -719,8 +729,10 @@ context minimal { dnsbl_list sbl; - content on {}; + content on { spamassassin 10; + dcc_bulk_threshold many; + }; generic "^$ " " "; # regex cannot match, to disable generic rdns rejects env_to { };