Mercurial > dnsbl
diff src/context.cpp @ 464:428de28b34b7
cleanup code for adding extra spf data in dkim_from
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Sun, 10 Mar 2019 08:49:27 -0700 |
parents | f3f1ece619ba |
children | 79e944269c0b |
line wrap: on
line diff
--- a/src/context.cpp Sat Mar 09 18:53:12 2019 -0800 +++ b/src/context.cpp Sun Mar 10 08:49:27 2019 -0700 @@ -616,9 +616,10 @@ } -DKIM::DKIM(const char *action_, const char *signer_) { +DKIM::DKIM(const char *action_, const char *signer_, const char*extraspf_) { action = action_; signer = signer_; + extraspf = extraspf_; } @@ -1111,58 +1112,42 @@ } -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)) break; // exact match + if ((m == n) && (strncasecmp(p, s, n) == 0)) return true; // exact match if ((*p == '*') && (n >= m)) { - if (strncasecmp(p+1, s+n-(m-1), m-1) == 0) break; // wildcard match + if (strncasecmp(p+1, s+n-(m-1), m-1) == 0) return true; // wildcard match } - if (!c) { - rc = false; - break; - } + if (!c) return false; p = c + 1; } while (true); - if (e) *e = ';'; - return rc; } -void CONTEXT::replace(char *buf, char *p, const char *what) +void CONTEXT::replace(char *buf, char *p, int nn, const char *what) { - // replace 4 chars in buf starting at p with what + // replace nn chars in buf starting at p with what char repl[maxlen]; size_t bn = strlen(buf); size_t wn = strlen(what); - if ((bn - 4 + wn) < (size_t)maxlen) { + if ((bn - nn + wn) < (size_t)maxlen) { size_t n = p - buf; // leading part length strncpy(repl, buf, n); // leading part strcpy(repl+n, what); // replacement - strcpy(repl+n+wn, buf+n+4); // trailing part + strcpy(repl+n+wn, buf+n+nn); // trailing part strcpy(buf, repl); } } -bool CONTEXT::resolve_spf(const char *from, uint32_t ip, mlfiPriv *priv, const char *signers) +bool CONTEXT::resolve_spf(const char *from, uint32_t ip, mlfiPriv *priv, const char *extraspf) { - const char *extraspf = extra_spf_data(signers); // ip is in host order if (priv->mailaddr) { const char *f = strchr(priv->mailaddr, '@'); @@ -1189,12 +1174,18 @@ 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, " "); + if ((level == 0) && extraspf && ((strlen(buf) + strlen(extraspf) + 1) < sizeof(buf))) { + if (strlen(buf) >= 7) { + // modify existing spf record + replace(buf, buf+7, 0, extraspf); + replace(buf, buf+7+strlen(extraspf), 0, " "); + } + else { + // synthesize full spf record + strcat(buf, "v=spf1 "); 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 @@ -1204,17 +1195,17 @@ char adr[sizeof "255.255.255.255 "]; adr[0] = '\0'; inet_ntop(AF_INET, (const u_char *)&priv->ip, adr, sizeof(adr)); - replace(buf, p, adr); + replace(buf, p, 4, adr); log(priv->queueid, "have txt record %s", buf); } p = strstr(buf, "%{h}"); if (p) { - replace(buf, p, priv->helo); + replace(buf, p, 4, priv->helo); log(priv->queueid, "have txt record %s", buf); } p = strstr(buf, "%{d}"); if (p) { - replace(buf, p, from); + replace(buf, p, 4, from); log(priv->queueid, "have txt record %s", buf); } // @@ -1375,7 +1366,7 @@ if (st == token_unsigned_black) { // enforce dmarc if (!dmarc) { - dmarc = resolve_spf(from, ntohl(priv->ip), priv, dk->signer); + dmarc = resolve_spf(from, ntohl(priv->ip), priv, dk->extraspf); } if (!dmarc) { // not signed and does not pass spf, reject it @@ -1387,7 +1378,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, dk->signer)) { + if (resolve_spf(from, ntohl(priv->ip), priv, dk->extraspf)) { log(queueid, "spf pass for %s rather than whitelisted dkim signer", from); return token_white; } @@ -1395,7 +1386,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, dk->signer)) { + if (strcmp(dk->signer, ".") && resolve_spf(from, ntohl(priv->ip), priv, dk->extraspf)) { log(queueid, "spf pass for %s rather than required dkim signer", from); return token_white; } @@ -1499,8 +1490,13 @@ for (dkimp_map::iterator i=dkim_from_names.begin(); i!=dkim_from_names.end(); i++) { const char *n = (*i).first; DKIM &d = *(*i).second; + if (d.extraspf) { + printf("%s %s %s \"%s;%s\"; \n", indent, n, d.action, d.signer, d.extraspf); + } + else { printf("%s %s %s \"%s\"; \n", indent, n, d.action, d.signer); } + } printf("%s }; \n", indent); if (content_suffix) { printf("%s filter %s \"%s\"; \n", indent, content_suffix, content_message); @@ -1823,7 +1819,18 @@ if ((action == token_signed_white) || (action == token_signed_black) || (action == token_unsigned_black) || (action == token_require_signed)) { const char *signer = tok.next(); if (!signer) break; - else me.add_dkim_from(from, action, signer); + else { + const char *extraspf = NULL; + if (strchr(signer, ';')) { + char *x = strdup(signer); + char *e = strchr(x, ';'); + *e = '\0'; + signer = register_string(x); + extraspf = register_string(e+1); + free(x); + } + me.add_dkim_from(from, action, signer, extraspf); + } } else { tok.token_error("signed_white/signed_black/unsigned_black/require_signed", action);