Mercurial > dnsbl
diff src/context.cpp @ 382:c378e9d03f37
start parsing spf txt records
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Mon, 06 Mar 2017 12:21:05 -0800 |
parents | 879a470c6ac3 |
children | 7b7066a51c33 |
line wrap: on
line diff
--- a/src/context.cpp Tue Feb 28 17:02:07 2017 -0800 +++ b/src/context.cpp Mon Mar 06 12:21:05 2017 -0800 @@ -9,6 +9,7 @@ #include "includes.h" #include <arpa/inet.h> +#include <arpa/nameser.h> #include <net/if.h> #include <netdb.h> #include <netinet/in.h> @@ -1122,17 +1123,52 @@ } -#ifdef NS_PACKETSZ -bool CONTEXT::resolve_spf(const char *from, int32_t ip, mlfiPriv *priv) +bool CONTEXT::resolve_spf(const char *from, uint32_t ip, mlfiPriv *priv, int level) { char buf[maxlen]; dns_interface(*priv, from, ns_t_txt, false, NULL, buf, maxlen); if (*buf) { - log(priv->queueid, "found txt record %s", buf); + log(priv->queueid, "found txt record for %s", from); + log(priv->queueid, "found txt record value %s", buf); + char *p = buf; + char *e = p + strlen(p); // point to trailing null + while (p = strstr(p, " ip4:")) { + p += 5; + char *b = strchr(p, ' '); + if (b) *b = '\0'; + char *s = strchr(p, '/'); + if (s) *s = '\0'; + in_addr ipx; + if (inet_aton(p, &ipx)) { + if (s) { + int mask = atoi(s+1); + if ((mask >= 16) && (mask <= 32)) { + int low = (1 << (32-mask)) - 1; + ipx.s_addr &= low ^ 0xffffffff; + if ((ip >= ipx.s_addr) && (ip <= ipx.s_addr + low)) { + log(priv->queueid, "match %s", p); + if (s) log(priv->queueid, "match /%s", s+1); + return true; + } + } + } + } + if (b) *b = ' '; + if (s) *s = '/'; + p = (b) ? b+1 : e; + } + p = buf; + while ((level < 5) && (p = strstr(p, " include:"))) { + p += 9; + char *b = strchr(p, ' '); + if (b) *b = '\0'; + if (resolve_spf(p, ip, priv, level+1)) return true; + if (b) *b = ' '; + p = (b) ? b+1 : e; + } } return false; } -#endif const char *CONTEXT::acceptable_content(recorder &memory, int score, int bulk, const char *queueid, string_set &signers, const char *from, mlfiPriv *priv, string& msg) { @@ -1149,6 +1185,12 @@ if (dk) { const char *st = dk->action; + if ((st == token_require_signed) && + dk->signer && + strcmp(dk->signer, " ") && + resolve_spf(from, priv->ip, priv)) { + log(queueid, "spf pass for %s with required dkim signer", from); + } for (string_set::iterator s=signers.begin(); s!=signers.end(); s++) { // signed by a white listed signer if ((st == token_signed_white) && in_signing_set(*s,dk->signer)) { @@ -1169,13 +1211,12 @@ } } if (st == token_require_signed) { -#ifdef NS_PACKETSZ - // not signed by the required signers, but maybe passes strong spf check - if (resolve_spf(from, priv->ip, priv) { + // 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 blank. + if (dk->signer && strcmp(dk->signer, " ") && resolve_spf(from, priv->ip, priv)) { log(queueid, "spf pass for %s rather than required dkim signer", from); return token_white; } -#endif char buf[maxlen]; snprintf(buf, sizeof(buf), "Mail rejected - not dkim signed by %s", dk->signer); msg = string(buf);