# HG changeset patch # User carl # Date 1085959064 25200 # Node ID fc7f8f3ea90f33909f2689b57659190d0ce35033 # Parent ce229348cdbeb07f0a12765d571f6344d5b9b341 look for NS records on the SBL also diff -r ce229348cdbe -r fc7f8f3ea90f sendmail.st Binary file sendmail.st has changed diff -r ce229348cdbe -r fc7f8f3ea90f src/dnsbl.cpp --- a/src/dnsbl.cpp Sat May 29 15:36:14 2004 -0700 +++ b/src/dnsbl.cpp Sun May 30 16:17:44 2004 -0700 @@ -23,6 +23,8 @@ recipients are rejected even if they would be whitelisted, and the data is rejected if sent. +3) Add option to only allow one recipient if the return path is empty. + */ @@ -113,6 +115,7 @@ typedef map dnsbllp_map; typedef set string_set; typedef list string_list; +typedef map ns_map; struct CONFIG { // the only mutable stuff once it has been loaded from the config file @@ -178,6 +181,29 @@ //////////////////////////////////////////////// +// helper to discard the strings and objects held by an ns_map +// +static void discard(ns_map &s); +static void discard(ns_map &s) { + for (ns_map::iterator i=s.begin(); i!=s.end(); i++) { + char *x = (*i).first; + free(x); + } + s.clear(); +} + +//////////////////////////////////////////////// +// helper to register a string in an ns_map +// +static void register_string(ns_map &s, char *name); +static void register_string(ns_map &s, char *name) { + ns_map::iterator i = s.find(name); + if (i != s.end()) return; + char *x = strdup(name); + s[x] = 0; +} + +//////////////////////////////////////////////// // helper to discard the strings held by a string_set // static void discard(string_set &s); @@ -379,8 +405,8 @@ // caller must ensure thread safety. // // -static int dns_interface(char *question, bool maybe_ip); -static int dns_interface(char *question, bool maybe_ip) { +static int dns_interface(char *question, bool maybe_ip, ns_map *nameservers); +static int dns_interface(char *question, bool maybe_ip, ns_map *nameservers) { #ifdef NS_PACKETSZ u_char answer[NS_PACKETSZ]; int length = res_search(question, ns_c_in, ns_t_a, answer, sizeof(answer)); @@ -389,6 +415,51 @@ ns_msg handle; ns_rr rr; if (ns_initparse(answer, length, &handle) == 0) { + // look for ns names + if (nameservers) { + ns_map &ns = *nameservers; + int rrnum = 0; + while (ns_parserr(&handle, ns_s_ns, rrnum++, &rr) == 0) { + if (ns_rr_type(rr) == ns_t_ns) { + char nam[NS_MAXDNAME+1]; + char *n = nam; + const u_char *p = ns_rr_rdata(rr); + while (((n-nam) < NS_MAXDNAME) && ((p-answer) < length) && *p) { + size_t s = *(p++); + if (s > 191) { + // compression pointer + s = (s-192)*256 + *(p++); + if (s >= length) break; // pointer outside bounds of answer + p = answer + s; + s = *(p++); + } + if (s > 0) { + if ((n-nam) >= (NS_MAXDNAME-s)) break; // destination would overflow name buffer + if ((p-answer) >= (length-s)) break; // source outside bounds of answer + memcpy(n, p, s); + n += s; + p += s; + *(n++) = '.'; + } + } + *(--n) = '\0'; // remove trailing . + register_string(ns, nam); // ns host to lookup later + } + } + rrnum = 0; + while (ns_parserr(&handle, ns_s_ar, rrnum++, &rr) == 0) { + if (ns_rr_type(rr) == ns_t_a) { + char* nam = (char*)ns_rr_name(rr); + ns_map::iterator i = ns.find(nam); + if (i != ns.end()) { + // we want this ip address + int address; + memcpy(&address, ns_rr_rdata(rr), sizeof(address)); + ns[nam] = address; + } + } + } + } int rrnum = 0; while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) { if (ns_rr_type(rr) == ns_t_a) { @@ -417,11 +488,11 @@ #endif } -static int protected_dns_interface(char *question, bool maybe_ip); -static int protected_dns_interface(char *question, bool maybe_ip) { +static int protected_dns_interface(char *question, bool maybe_ip, ns_map *nameservers); +static int protected_dns_interface(char *question, bool maybe_ip, ns_map *nameservers) { int ans; pthread_mutex_lock(&resolve_mutex); - ans = dns_interface(question, maybe_ip); + ans = dns_interface(question, maybe_ip, nameservers); pthread_mutex_unlock(&resolve_mutex); return ans; @@ -442,7 +513,7 @@ #endif snprintf(question, sizeof(question), "%u.%u.%u.%u.%s.", src[3], src[2], src[1], src[0], suffix); // ask the question, if we get an A record it implies a blacklisted ip address - return (protected_dns_interface(question, false)) ? reject : oksofar; + return (protected_dns_interface(question, false, NULL)) ? reject : oksofar; } @@ -491,12 +562,16 @@ CONFIG &dc = *priv.pc; if (!dc.content_suffix) return oksofar; int count = 0; + ns_map nameservers; + int lim = priv.pc->host_limit; for (string_set::iterator i=priv.memory->hosts.begin(); i!=priv.memory->hosts.end(); i++) { count++; - int lim = priv.pc->host_limit; - if ((count > lim) && (lim > 0)) return reject_host; + if ((count > lim) && (lim > 0)) { + discard(nameservers); + return reject_host; + } host = *i; - ip = protected_dns_interface(host, true); + ip = protected_dns_interface(host, true, &nameservers); if (debug_syslog) { char buf[200]; if (ip) { @@ -512,13 +587,48 @@ } if (ip) { status st = check_single(ip, dc.content_suffix); - if (st == reject) return st; + if (st == reject) { + discard(nameservers); + return st; + } } } + lim *= 4; // allow average of 3 ns per host name + for (ns_map::iterator i=nameservers.begin(); i!=nameservers.end(); i++) { + count++; + if ((count > lim) && (lim > 0)) { + discard(nameservers); + return reject_host; + } + host = (*i).first; + ip = (*i).second; + if (!ip) ip = protected_dns_interface(host, false, NULL); + if (debug_syslog) { + char buf[200]; + if (ip) { + char adr[sizeof "255.255.255.255"]; + adr[0] = '\0'; + inet_ntop(AF_INET, (const u_char *)&ip, adr, sizeof(adr)); + snprintf(buf, sizeof(buf), "ns %s found at %s", host, adr); + } + else { + snprintf(buf, sizeof(buf), "ns %s not found", host); + } + my_syslog(buf); + } + if (ip) { + status st = check_single(ip, dc.content_suffix); + if (st == reject) { + discard(nameservers); + return st; + } + } + } + discard(nameservers); host = NULL; int bin = priv.memory->binary_tags; int bad = priv.memory->bad_html_tags; - int lim = priv.pc->tag_limit; + lim = priv.pc->tag_limit; if (bin > bad) return oksofar; // probably .zip or .tar.gz with random content if ((bad > lim) && (lim > 0)) return reject_tag; return oksofar; diff -r ce229348cdbe -r fc7f8f3ea90f src/package --- a/src/package Sat May 29 15:36:14 2004 -0700 +++ b/src/package Sun May 30 16:17:44 2004 -0700 @@ -27,7 +27,7 @@ scp $target1 ams:/tmp/$bt1 scp $target2 ams:/tmp/$bt2 scp $target3 ams:/tmp/$bt3 - ssh ams "scp /tmp/$bt1 ns1.five-ten-sg.com:$target1" - ssh ams "scp /tmp/$bt2 ns1.five-ten-sg.com:$target2" - ssh ams "scp /tmp/$bt3 ns1.five-ten-sg.com:$target3" + ssh -t ams "scp /tmp/$bt1 ns1.five-ten-sg.com:$target1" + ssh -t ams "scp /tmp/$bt2 ns1.five-ten-sg.com:$target2" + ssh -t ams "scp /tmp/$bt3 ns1.five-ten-sg.com:$target3" rm -rf $VER diff -r ce229348cdbe -r fc7f8f3ea90f xml/dnsbl.in --- a/xml/dnsbl.in Sat May 29 15:36:14 2004 -0700 +++ b/xml/dnsbl.in Sun May 30 16:17:44 2004 -0700 @@ -21,11 +21,11 @@

This milter will also decode (base64, mime, html entity, url encodings) and scan for HTTP and HTTPS URLs and bare hostnames in the -body of the mail. If any of those host names have A records on the SBL -(or a single configurable DNSBL), the mail will be rejected unless -previously whitelisted. This milter also counts the number of invalid -HTML tags, and can reject mail if that count exceeds your specified -limit. +body of the mail. If any of those host names have A or NS records on +the SBL (or a single configurable DNSBL), the mail will be rejected +unless previously whitelisted. This milter also counts the number of +invalid HTML tags, and can reject mail if that count exceeds your +specified limit.

The DNSBL milter reads a text configuration file (dnsbl.conf) on startup, and whenever the config file (or any of the referenced include