Mercurial > dnsbl
diff src/context.cpp @ 414:d5a1ed33d3ae
spf code now handles mx,exists,ptr tags, multiple A records, %{i} macro
author | Carl Byington <carl@five-ten-sg.com> |
---|---|
date | Tue, 25 Apr 2017 14:48:19 -0700 |
parents | e63c6b4835ef |
children | 16451edcb962 |
line wrap: on
line diff
--- a/src/context.cpp Wed Apr 19 09:36:16 2017 -0700 +++ b/src/context.cpp Tue Apr 25 14:48:19 2017 -0700 @@ -1138,7 +1138,27 @@ dns_interface(*priv, from, ns_t_txt, false, NULL, buf, maxlen); if (*buf) { log(priv->queueid, "found txt record %s", buf); - char *p = strchr(buf, ' '); // must start with 'v=spf1 ' + // expand some macros here - a very restricted subset of all possible spf macros + // only expand the first one. + char *p = strstr(buf, "%{i}"); + if (p) { + char repl[maxlen]; + char adr[sizeof "255.255.255.255 "]; + adr[0] = '\0'; + inet_ntop(AF_INET, (const u_char *)&priv->ip, adr, sizeof(adr)); + size_t bn = strlen(buf); + size_t an = strlen(adr); + if ((bn - 4 + an) < maxlen) { + size_t n = p - buf; // leading part length + strncpy(repl, buf, n); // leading part + strcpy(repl+n, adr); // replacement + strcpy(repl+n+an, buf+n+4); // trailing part + strcpy(buf, repl); + } + log(priv->queueid, "have txt record %s", buf); + } + // + p = strchr(buf, ' '); // must start with 'v=spf1 ' if (!p) return false; // broken spf char *e = p + strlen(p); // point to trailing null while (true) { @@ -1146,7 +1166,7 @@ if (p >= e) break; char *b = strchr(p, ' '); if (b) *b = '\0'; - if ((*p != '-') && (*p != '~')) { + if ((*p != '-') && (*p != '~') && (*p != '?')) { if (*p == '+') p++; if (strncmp(p, "ip4:", 4) == 0) { p += 4; @@ -1161,27 +1181,72 @@ ipy &= low ^ 0xffffffff; if ((ipy <= ip) && (ip <= ipy + low)) { if (s) *s = '/'; - log(priv->queueid, "match %s", p); + log(priv->queueid, "match ip4:%s", p); return true; } } } } - else if (strncmp(p, "a:", 2) == 0) { - p += 2; - uint32_t ipy = ntohl(dns_interface(*priv, p, ns_t_a)); - if (ipy == ip) { - log(priv->queueid, "match %s", p); + else if (strncmp(p, "all", 3) == 0) { + // ignore it before looking for (a or a:) below + } + else if (strncmp(p, "exists:", 7) == 0) { + p += 7; + char buf[maxlen]; + uint32_t ipy = ntohl(dns_interface(*priv, p, ns_t_a, false, NULL, buf, maxlen)); + uint32_t *a = (uint32_t *)buf; + if (a[0]) { + log(priv->queueid, "match exists:%s", p); return true; } } - else if (strcmp(p, "a") == 0) { - uint32_t ipy = ntohl(dns_interface(*priv, from, ns_t_a)); + else if (strncmp(p, "mx", 2) == 0) { + const char *name = (p[2] == ':') ? p+2 : from; + char buf[maxlen]; + uint32_t c = ntohl(dns_interface(*priv, name, ns_t_mx, false, NULL, buf, maxlen)); + char *b = buf; + while (*b) { + log(priv->queueid, "found mx %s", b); + char abuf[maxlen]; + uint32_t ipy = ntohl(dns_interface(*priv, b, ns_t_a, false, NULL, buf, maxlen)); + uint32_t *a = (uint32_t *)buf; + size_t c = a[0]; + for (size_t i=1; i++; i<=c) { + ipy = ntohl(a[i]); if (ipy == ip) { - log(priv->queueid, "match %s", from); + log(priv->queueid, "match mx:%s", name); return true; } } + b += strlen(b) + 1; + } + } + else if (p[0] == 'a') { + const char *name = (p[1] == ':') ? p+2 : from; + char buf[maxlen]; + uint32_t ipy = ntohl(dns_interface(*priv, name, ns_t_a, false, NULL, buf, maxlen)); + uint32_t *a = (uint32_t *)buf; + size_t c = a[0]; + for (size_t i=1; i++; i<=c) { + ipy = ntohl(a[i]); + if (ipy == ip) { + log(priv->queueid, "match a:%s", name); + return true; + } + } + } + else if (priv->client_dns_name && (!priv->client_dns_forged) && (strncmp(p, "ptr", 3) == 0)) { + const char *name = (p[3] == ':') ? p+4 : from; + size_t n = strlen(name); + size_t d = strlen(priv->client_dns_name); + if (d >= n) { + if ((strncmp(priv->client_dns_name+d-n, name, n) == 0) && // trailing part matches + ((d == n) || (priv->client_dns_name[d-n-1] == '.'))) { // same length, or dot just before match + log(priv->queueid, "match ptr:%s", priv->client_dns_name); + return true; + } + } + } else if ((level < 5) && (strncmp(p, "redirect=", 9) == 0)) { p += 9; if (resolve_spf(p, ip, priv, level+1)) return true;