diff src/dnsbl.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 6b03435868cb
children 16451edcb962
line wrap: on
line diff
--- a/src/dnsbl.cpp	Wed Apr 19 09:36:16 2017 -0700
+++ b/src/dnsbl.cpp	Tue Apr 25 14:48:19 2017 -0700
@@ -297,14 +297,16 @@
 //  Ask a dns question and get an A record answer in network byte order.
 //  We don't try very hard, just using the default resolver retry settings.
 //  If we cannot get an answer, we just accept the mail.
-//  If the qtype is ns_t_txt, the answer is placed in txt_answer which
+//  If the qtype is ns_t_txt, the answer is placed in my_answer which
 //  must be non-null, and the return value can be ignored.
-//  A null string is returned in txt_answer in the case of errors.
-//  If the qtype is ns_t_a, the ip address is returned in network byte order.
+//  A null string is returned in my_answer in the case of errors.
+//  If the qtype is ns_t_a, one of the ip addresses is returned in network byte order,
+//  and if my_answer is non-null, all the ip addresses are returned in
+//  my_answer (in network byte order), prepended with the count.
 //  IP address 0 is returned in case of errors.
 //
-uint32_t dns_interface(mlfiPriv &priv, const char *question, int qtype, bool maybe_ip, ns_map *nameservers, char *txt_answer, size_t txt_size) {
-    if (txt_answer) txt_answer[0] = '\0';   // return null string if there are no txt answers
+uint32_t dns_interface(mlfiPriv &priv, const char *question, int qtype, bool maybe_ip, ns_map *nameservers, char *my_answer, size_t my_size) {
+    if (my_answer) my_answer[0] = '\0';   // return null string if there are no txt answers
 
     // tell sendmail we are still working
     #if _FFR_SMFI_PROGRESS
@@ -412,17 +414,45 @@
             }
             int rrnum = 0;
             if (qtype == ns_t_a) {
+                uint32_t *ans = (uint32_t *)my_answer;
+                size_t c = 0;
+                size_t m = my_size/4;   // 1 + max ipv4 addresses that will fit in the answer buffer
                 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) {
                     if (ns_rr_type(rr) == qtype) {
                         uint32_t address;
                         memcpy(&address, ns_rr_rdata(rr), sizeof(address));
                         ret_address = address;
+                        if (ans && (c < m-1)) {
+                            c++;
+                            ans[c] = address;
                     }
                 }
             }
-            if ((qtype == ns_t_txt) && (txt_answer) && (txt_size > 7)) {
-                txt_answer[0] = '\0';  // return null string if there are no txt answers
-                txt_size--; // allow room for terminating null;
+                if (ans && (c < m)) ans[0] = c;
+            }
+            if ((qtype == ns_t_mx) && (my_answer) && (my_size > 1)) {
+                uint32_t c = 0;
+                while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) {
+                    if (ns_rr_type(rr) == qtype) {
+                        char exchange[NS_MAXDNAME];
+                        size_t rdlen = ns_rr_rdlen(rr);
+                        const unsigned char *rdata = ns_rr_rdata(rr);
+                        const uint16_t pri = ns_get16(rdata);
+                        int len = dn_expand(glom.answer, glom.answer+glom.length, rdata + 2, exchange, sizeof(exchange));
+                        if ((len > 0) && (my_size > len+2)) {
+                            strcpy(my_answer, exchange);
+                            my_answer += len + 1;
+                            my_size   -= len + 1;
+                            c++;
+                        }
+                    }
+                }
+                *my_answer = '\0';    // final trailing null
+                ret_address = htonl(c);
+            }
+            if ((qtype == ns_t_txt) && (my_answer) && (my_size > 7)) {
+                my_answer[0] = '\0';  // return null string if there are no txt answers
+                my_size--; // allow room for terminating null;
                 while (ns_parserr(&handle, ns_s_an, rrnum++, &rr) == 0) {
                     if (ns_rr_type(rr) == qtype) {
                         size_t offset = 0;
@@ -433,26 +463,26 @@
                             snprintf(text, sizeof(text), "found txt record rdlen = %d", rdlen);
                             my_syslog(text);
                         #endif
-                        while ((offset < txt_size) && rdlen) {
+                        while ((offset < my_size) && rdlen) {
                             size_t slen = size_t(*(rdata++));
                             rdlen--;
                             size_t m = min(slen, rdlen);
-                            m = min(m, txt_size-offset);
-                            memcpy(txt_answer+offset, rdata, m);
+                            m = min(m, my_size-offset);
+                            memcpy(my_answer+offset, rdata, m);
                             offset += m;
                             rdata  += m;
                             rdlen  -= m;
                         }
-                        txt_answer[offset] = '\0';  // trailing null
+                        my_answer[offset] = '\0';  // trailing null
                         #ifdef RESOLVER_DEBUG
-                            snprintf(text, sizeof(text), "found txt record %s", txt_answer);
+                            snprintf(text, sizeof(text), "found txt record %s", my_answer);
                             my_syslog(text);
                         #endif
-                        if (strncasecmp(txt_answer, "v=spf1 ", 7) == 0) break;
+                        if (strncasecmp(my_answer, "v=spf1 ", 7) == 0) break;
                     }
                 }
-                if (strncasecmp(txt_answer, "v=spf1 ", 7) != 0) {
-                    txt_answer[0] = '\0';  // return null string if there are no spf1 txt answers
+                if (strncasecmp(my_answer, "v=spf1 ", 7) != 0) {
+                    my_answer[0] = '\0';  // return null string if there are no spf1 txt answers
                 }
             }
         }