changeset 34:fc7f8f3ea90f

look for NS records on the SBL also
author carl
date Sun, 30 May 2004 16:17:44 -0700
parents ce229348cdbe
children d718dca81bc9
files sendmail.st src/dnsbl.cpp src/package xml/dnsbl.in
diffstat 4 files changed, 129 insertions(+), 19 deletions(-) [+]
line wrap: on
line diff
Binary file sendmail.st has changed
--- 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<char *, DNSBLLP, ltstr>       dnsbllp_map;
 typedef set<char *, ltstr>                string_set;
 typedef list<char *>                      string_list;
+typedef map<char *, int, ltstr>           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;
--- 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
--- 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 @@
 
 <p>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.
 
 <p>The DNSBL milter reads a text configuration file (dnsbl.conf) on
 startup, and whenever the config file (or any of the referenced include