changeset 350:f4ca91f49cb6

send the original mail from address to the verify server, not the srs/pvrs unwrapped version; recognize our own dkim signatures
author Carl Byington <carl@five-ten-sg.com>
date Mon, 26 Dec 2016 09:31:57 -0800
parents 3c39051699bd
children d4be824a3870
files dnsbl.conf src/dnsbl.cpp src/dnsbl.h
diffstat 3 files changed, 132 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
--- 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";
--- 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);
     }
--- 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<DNSBLP, bool> checked_black;        // map of dnsblp to result of (ip listed on that dnsbl)
     map<DNSWLP, bool> 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);