Mercurial > dnsbl
diff src/context.cpp @ 462:f3f1ece619ba stable-6-0-75
change dkim_from syntax to allow "signer1,signer2;spf data"
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Sat, 09 Mar 2019 18:46:25 -0800 |
parents | ad05c61d6372 |
children | 428de28b34b7 |
line wrap: on
line diff
--- a/src/context.cpp Mon Dec 24 09:41:04 2018 -0800 +++ b/src/context.cpp Sat Mar 09 18:46:25 2019 -0800 @@ -1111,22 +1111,36 @@ } +const char *CONTEXT::extra_spf_data(const char *signers) { + const char *e = strchr(signers, ';'); + if (e) e++; + return e; +} + + bool CONTEXT::in_signing_set(const char *s, const char *signers) { // s is an actual signer // signers is the set of acceptable signers, separated by commas size_t n = strlen(s); const char *p = signers; + char *e = (char *)strchr(p, ';'); // only search up to ; which separates signers from extra spf data + if (e) *e = '\0'; + bool rc = true; do { const char *c = strchr(p, ','); size_t m = (c) ? c-p : strlen(p); // length of this element in the signing set - if ((m == n) && (strncasecmp(p, s, n) == 0)) return true; // exact match + if ((m == n) && (strncasecmp(p, s, n) == 0)) break; // exact match if ((*p == '*') && (n >= m)) { - // try for wildcard match - if (strncasecmp(p+1, s+n-(m-1), m-1) == 0) return true; + if (strncasecmp(p+1, s+n-(m-1), m-1) == 0) break; // wildcard match } - if (!c) return false; + if (!c) { + rc = false; + break; + } p = c + 1; } while (true); + if (e) *e = ';'; + return rc; } @@ -1146,8 +1160,9 @@ } -bool CONTEXT::resolve_spf(const char *from, uint32_t ip, mlfiPriv *priv) +bool CONTEXT::resolve_spf(const char *from, uint32_t ip, mlfiPriv *priv, const char *signers) { + const char *extraspf = extra_spf_data(signers); // ip is in host order if (priv->mailaddr) { const char *f = strchr(priv->mailaddr, '@'); @@ -1160,20 +1175,26 @@ if ((f[off-1] == '.') && (strcmp(f+off,from) == 0)) { // envelope from is a strict child of header from // use envelope from rather than header from - if (resolve_one_spf(f, ip, priv)) return true; + if (resolve_one_spf(f, ip, priv, extraspf)) return true; } } } } - return resolve_one_spf(from, ip, priv); + return resolve_one_spf(from, ip, priv, extraspf); } -bool CONTEXT::resolve_one_spf(const char *from, uint32_t ip, mlfiPriv *priv, int level) +bool CONTEXT::resolve_one_spf(const char *from, uint32_t ip, mlfiPriv *priv, const char *extraspf, int level) { char buf[maxdnslength]; log(priv->queueid, "looking for %s txt record", from); dns_interface(*priv, from, ns_t_txt, false, NULL, buf, maxdnslength); + if ((level == 0) && + extraspf && + ((strlen(buf) + strlen(extraspf) + 1) < sizeof(buf))) { + strcat(buf, " "); + strcat(buf, extraspf); + } if (*buf) { log(priv->queueid, "found txt record %s", buf); // expand some macros here - a very restricted subset of all possible spf macros @@ -1297,11 +1318,11 @@ } else if ((level < 5) && (strncmp(p, "redirect=", 9) == 0)) { p += 9; - if (resolve_one_spf(p, ip, priv, level+1)) return true; + if (resolve_one_spf(p, ip, priv, NULL, level+1)) return true; } else if ((level < 5) && (strncmp(p, "include:", 8) == 0)) { p += 8; - if (resolve_one_spf(p, ip, priv, level+1)) return true; + if (resolve_one_spf(p, ip, priv, NULL, level+1)) return true; } } p = (b) ? b+1 : e; @@ -1354,7 +1375,7 @@ if (st == token_unsigned_black) { // enforce dmarc if (!dmarc) { - dmarc = resolve_spf(from, ntohl(priv->ip), priv); + dmarc = resolve_spf(from, ntohl(priv->ip), priv, dk->signer); } if (!dmarc) { // not signed and does not pass spf, reject it @@ -1366,7 +1387,7 @@ } if (st == token_signed_white) { // not signed by a white listed signer, but maybe passes strong spf check - if (resolve_spf(from, ntohl(priv->ip), priv)) { + if (resolve_spf(from, ntohl(priv->ip), priv, dk->signer)) { log(queueid, "spf pass for %s rather than whitelisted dkim signer", from); return token_white; } @@ -1374,7 +1395,7 @@ if (st == token_require_signed) { // not signed by a required signer, but maybe passes strong spf check // only check spf if the list of required signers is not a single dot. - if (strcmp(dk->signer, ".") && resolve_spf(from, ntohl(priv->ip), priv)) { + if (strcmp(dk->signer, ".") && resolve_spf(from, ntohl(priv->ip), priv, dk->signer)) { log(queueid, "spf pass for %s rather than required dkim signer", from); return token_white; }