# HG changeset patch # User Carl Byington # Date 1482773517 28800 # Node ID f4ca91f49cb6a2575c12becb7870beeab80b384b # Parent 3c39051699bd3ab1f20b2e8c6cc4dcc49fbbda9f send the original mail from address to the verify server, not the srs/pvrs unwrapped version; recognize our own dkim signatures diff -r 3c39051699bd -r f4ca91f49cb6 dnsbl.conf --- a/dnsbl.conf Fri Dec 23 09:47:40 2016 -0800 +++ b/dnsbl.conf Mon Dec 26 09:31:57 2016 -0800 @@ -67,33 +67,98 @@ // forged bulk senders like ebay and paypal. some.spammer require_signed some.spammer // reject if not signed + 123greetings.info require_signed 123greetings.info; + aadvantage.email.aa.com require_signed aadvantage.email.aa.com; + admarketing.yahoo.com require_signed admarketing.yahoo.com; adp.com require_signed adp.com; + alertsp.chase.com require_signed alertsp.chase.com; + allaboutjazz.com require_signed allaboutjazz.com; + alpineescrow.net require_signed alpineescrowarrowhead.onmicrosoft.com; amazon.com require_signed amazon.com; + applemusic.com require_signed applemusic.com; billpay.bankofamerica.com require_signed billpay.bankofamerica.com; + booking.com require_signed sg.booking.com; + cafepress.com require_signed cafepressinc.onmicrosoft.com; + checkin.email.aa.com require_signed checkin.email.aa.com; + connect.wellsfargoemail.com require_signed connect.wellsfargoemail.com; craigslist.org require_signed craigslist.org; + dailykos.com require_signed sg.actionnetwork.org; + daytimer.com require_signed daytimer.com; + deals.priceline.com require_signed deals.priceline.com; dhl.com require_signed dhl.com; dropbox.com require_signed dropbox.com; dvd.com require_signed dvd.com + e.bevmo.com require_signed e.bevmo.com; + e.bloomingdales.com require_signed e.bloomingdales.com; + e.business.officedepot.com require_signed e.business.officedepot.com; + e.shutterfly.com require_signed e.shutterfly.com; e.statefarm.com require_signed e.statefarm.com; + e1.llbean.com require_signed e1.llbean.com; ealerts.bankofamerica.com require_signed ealerts.bankofamerica.com; + easy.staples.com require_signed easy.staples.com; ebay.com require_signed ebay.com; ecommail.walgreens.com require_signed ecommail.walgreens.com; + email.aa.com require_signed email.aa.com; + email.aegeanair.com require_signed email.aegeanair.com; + email.chase.com require_signed email.chase.com; + email.consumerreports.org require_signed email.consumerreports.org; + email.dowjones.com require_signed email.dowjones.com; + email.homedepot.com require_signed email.homedepot.com; + email.jetblue.com require_signed email.jetblue.com; + email.ticketmaster.com require_signed email.ticketmaster.com; email.travelzoo.com require_signed email.travelzoo.com; - email.jetblue.com require_signed email.jetblue.com; + email.wetransfer.com require_signed email.wetransfer.com; + email.zazzle.com require_signed email.zazzle.com; + email.zionlodge.com require_signed email.zionlodge.com; + emails.cafepress.com require_signed cafepress.com; + et.uber.com require_signed et.uber.com; facebookmail.com require_signed facebookmail.com; fedex.com require_signed fedex.com; + harryanddavid-email.com require_signed harryanddavid-email.com; healthcare.gov require_signed healthcare.gov; - iheartmedia.com require_signed iheartmedia.onmicrosoft.com; + imail.register.com require_signed imail.register.com; + info1.networksolutions.com require_signed info1.networksolutions.com; + insideapple.apple.com require_signed insideapple.apple.com; + intuit.com require_signed intuit.com; + lakearrowheadchamber.com require_signed lakearrowhead.ccsend.com; + lehighvalleychamber.org require_signed lehighvalleychamber.ccsend.com; + libertymutual.com require_signed libertymutual.com; linkedin.com require_signed linkedin.com; + luv.southwest.com require_signed luv.southwest.com; + mail.sling.com require_signed mail.sling.com; + mail.zillow.com require_signed mail.zillow.com; + mailer.box.com require_signed box.com; + midjerseychamber.org require_signed midjerseychamber.ccsend.com; monster.com require_signed monster.com; - paypal.com require_signed paypal.com; + my.orbitz.com require_signed my.orbitz.com; + mystubhub.com require_signed mystubhub.com; + na.email.aa.com require_signed na.email.aa.com; + new.itunes.com require_signed new.itunes.com; + news.united.com require_signed news.united.com; + nextdayflyers.com require_signed nextdayflyers.com; + notices.rei.com require_signed notices.rei.com; + openemail.americanexpress.com require_signed openemail.americanexpress.com; + orders.staples.com signed_white orders.staples.com; // some unsigned mail via protection.outlook.com paychex.com require_signed paychex.com; + paypal.com require_signed paypal.com; + public.govdelivery.com require_signed public.govdelivery.com; r.groupon.com require_signed r.groupon.com; + reply1.ebay.com require_signed reply1.ebay.com; + response.nfcu.org require_signed response.nfcu.org; service.capitalone.com require_signed capitalone.com; + service.checkout.visa.com require_signed service.checkout.visa.com; + sg.booking.com require_signed sg.booking.com; + subscriptions.ssa.gov require_signed subscriptions.ssa.gov; support.facebook.com require_signed support.facebook.com; + support.zappos.com require_signed zappos.com; + ticketfly.com require_signed ticketfly.com; twitter.com require_signed twitter.com; + unionbank.com require_signed unionbank.com; ups.com require_signed ups.com; + welcome.aexp.com require_signed welcome.aexp.com; wellsfargo.com require_signed wellsfargo.com; + wetransfer.com require_signed email.wetransfer.com; + zappos.com require_signed zappos.com; }; filter sbl-xbl.spamhaus.org "Mail containing %s rejected - sbl; see http://www.spamhaus.org/query/bl?ip=%s"; uribl multi.surbl.org "Mail containing %s rejected - surbl; see http://www.surbl.org/surbl-analysis?d=%s"; diff -r 3c39051699bd -r f4ca91f49cb6 src/dnsbl.cpp --- a/src/dnsbl.cpp Fri Dec 23 09:47:40 2016 -0800 +++ b/src/dnsbl.cpp Mon Dec 26 09:31:57 2016 -0800 @@ -98,7 +98,8 @@ const int maxlen = 1000; // used for snprintf buffers regex_t srs_pattern; // used to detect srs coding in mail addresses regex_t prvs_pattern; // used to detect prvs coding in mail addresses -regex_t dkim_pattern; // used to detect dkim signatures in authentication header generated by the upstream opendkim milter +regex_t dkim_r_pattern; // used to detect dkim signatures authenticated by the upstream opendkim milter +regex_t dkim_s_pattern; // used to detect dkim signatures generated by the upstream opendkim milter regex_t from_pattern; // used to extract the senders mail domain from the body from: header pthread_mutex_t config_mutex; @@ -522,6 +523,7 @@ ip = 0; helo = NULL; mailaddr = NULL; + origaddr = NULL; fromaddr = NULL; header_count = 0; dkim_ok = true; @@ -572,6 +574,7 @@ delayer.pop_front(); } if (mailaddr) free((void*)mailaddr); + if (origaddr) free((void*)origaddr); if (fromaddr) free((void*)fromaddr); if (queueid) free((void*)queueid); if (authenticated) free((void*)authenticated); @@ -589,6 +592,7 @@ ctx = NULL; eom = false; mailaddr = NULL; + origaddr = NULL; fromaddr = NULL; header_count = 0; dkim_ok = true; @@ -716,7 +720,7 @@ return rs; } -void mlfiPriv::need_content_filter(const char *rcpt, CONTEXT &con) { +void mlfiPriv::need_content_filter(CONTEXT &con) { if (!memory) { // first recipient that needs content filtering sets // some of the content filtering parameters @@ -1186,6 +1190,7 @@ { mlfiPriv &priv = *MLFIPRIV; CONFIG &dc = *priv.pc; + priv.origaddr = to_lower_string(from[0], false); priv.mailaddr = to_lower_string(from[0]); priv.queueid = strdup(smfi_getsymval(ctx, (char*)"i")); priv.authenticated = smfi_getsymval(ctx, (char*)"{auth_authen}"); @@ -1302,8 +1307,8 @@ } else if ((fromvalue == token_white) && !self) { // whitelisting based on envelope from value, but ignore it if - // we have a dkim requirement for that domain - const char *domain = strchr(priv.mailaddr, '@'); + // we have a dkim requirement for the original domain + const char *domain = strchr(priv.origaddr, '@'); if (domain) { DKIMP dk = con.find_dkim_from(domain+1); if (dk && (dk->action == token_require_signed)) { @@ -1367,9 +1372,9 @@ } if (ver) { - // try to verify this from/to pair of addresses even if it might be explicitly whitelisted + // try to verify the original from/to pair of addresses even if it might be explicitly whitelisted const char *loto = to_lower_string(rcptaddr, false); - bool rc = ver->ok(priv.queueid, priv.mailaddr, loto); + bool rc = ver->ok(priv.queueid, priv.origaddr, loto); free((void*)loto); if (!rc) { smfi_setreply(ctx, (char*)"550", (char*)"5.7.1", (char*)"no such user"); @@ -1427,7 +1432,7 @@ smfi_setreply(ctx, (char*)"452", (char*)"4.2.1", (char*)"incompatible filtering contexts"); return SMFIS_TEMPFAIL; } - priv.need_content_filter(rcptaddr, con); + priv.need_content_filter(con); char bu[maxlen]; bool uri = false; // content filtering implies also checking helo name on uribl (if enabled) @@ -1482,13 +1487,12 @@ if (priv.dkim_ok) { if ((priv.header_count == 1) && (strcasecmp(headerf, "DKIM-Filter") != 0)) priv.dkim_ok = false; if (priv.header_count == 2) { - if (strcasecmp(headerf, "Authentication-Results") != 0) priv.dkim_ok = false; - if (strncasecmp(headerv, token_myhostname, strlen(token_myhostname)) != 0) priv.dkim_ok = false; - if (priv.dkim_ok) { + if ((strcasecmp(headerf, "Authentication-Results") == 0) && + (strncasecmp(headerv, token_myhostname, strlen(token_myhostname)) == 0)) { const int nmatch = 2; regmatch_t match[nmatch]; while (true) { - if (0 == regexec(&dkim_pattern, value, nmatch, match, 0)) { + if (0 == regexec(&dkim_r_pattern, value, nmatch, match, 0)) { int s1 = match[1].rm_so; // domain int e1 = match[1].rm_eo; if (s1 != -1) { @@ -1503,6 +1507,19 @@ else break; } } + else if (strcasecmp(headerf, "DKIM-Signature") == 0) { + const int nmatch = 2; + regmatch_t match[nmatch]; + if (0 == regexec(&dkim_s_pattern, value, nmatch, match, 0)) { + int s1 = match[1].rm_so; // domain + int e1 = match[1].rm_eo; + if (s1 != -1) { + value[e1] = '\0'; + priv.dkim_signers.insert(strdup(value+s1)); + } + } + } + else priv.dkim_ok = false; } } @@ -1510,8 +1527,7 @@ if ((!priv.fromaddr) && (strcasecmp(headerf, "from") == 0)) { const int nmatch = 2; regmatch_t match[nmatch]; - int err = regexec(&from_pattern, value, nmatch, match, 0); - if (err == 0) { + if (0 == regexec(&from_pattern, value, nmatch, match, 0)) { int s1 = match[1].rm_so; // domain int e1 = match[1].rm_eo; if (s1 != -1) { @@ -1887,8 +1903,14 @@ exit(3); } - // setup dkim signature detection - if (regcomp(&dkim_pattern, " dkim=pass .[0-9]*-bit key. header.d=([^ ]+) ", REG_ICASE | REG_EXTENDED)) { + // setup dkim results signature detection + if (regcomp(&dkim_r_pattern, " dkim=pass .[0-9]*-bit key. header.d=([^ ]+) ", REG_ICASE | REG_EXTENDED)) { + printf("cannot compile regex pattern to find dkim results gnatures\n"); + exit(3); + } + + // setup dkim results signature detection + if (regcomp(&dkim_s_pattern, " d=([^;]+);", REG_ICASE | REG_EXTENDED)) { printf("cannot compile regex pattern to find dkim signatures\n"); exit(3); } diff -r 3c39051699bd -r f4ca91f49cb6 src/dnsbl.h --- a/src/dnsbl.h Fri Dec 23 09:47:40 2016 -0800 +++ b/src/dnsbl.h Mon Dec 26 09:31:57 2016 -0800 @@ -38,7 +38,8 @@ map checked_black; // map of dnsblp to result of (ip listed on that dnsbl) map checked_white; // map of dnswlp to result of (ip listed on that dnswl) // message specific data - const char *mailaddr; // envelope from value + const char *origaddr; // envelope from value, lowercase, no srs/pvrs unwrapping + const char *mailaddr; // envelope from value, lowercase, srs/pvrs unwapped const char *fromaddr; // header from value, set by mlfi_header() int header_count; // count of headers already seen bool dkim_ok; // ok to proceed with dkim checking @@ -80,7 +81,7 @@ void return_fd(); size_t my_read(char *buf, size_t len); size_t my_write(const char *buf, size_t len); - void need_content_filter(const char *rcpt, CONTEXT &con); + void need_content_filter(CONTEXT &con); }; void my_syslog(const char *queueid, const char *text);