Add dnsdb lookup pseudo-type "a+". Addresses bug 1269.
authorJeremy Harris <jgh146exb@wizmail.org>
Wed, 5 Sep 2012 20:38:23 +0000 (21:38 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Wed, 5 Sep 2012 20:38:23 +0000 (21:38 +0100)
doc/doc-docbook/spec.xfpt
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
src/src/exim.h
src/src/lookups/dnsdb.c
test/scripts/2250-dnsdb-ipv6/2250
test/stdout/2250

index 99de287..f902fe8 100644 (file)
@@ -6911,6 +6911,14 @@ has two space-separated fields: an authorization code and a target host name.
 The authorization code can be &"Y"& for yes, &"N"& for no, &"X"& for explicit
 authorization required but absent, or &"?"& for unknown.
 
+.cindex "A+" "in &(dnsdb)& lookup"
+The pseudo-type A+ performs an A6 lookup (if configured) followed by an AAAA
+and then an A lookup.  All results are returned; defer processing
+(see below) is handled separately for each lookup.  Example:
+.code
+${lookup dnsdb {>; a+=$sender_helo_name}}
+.endd
+
 
 .section "Multiple dnsdb lookups" "SECID67"
 In the previous sections, &(dnsdb)& lookups for a single domain are described.
index e3d2fc2..c528ada 100644 (file)
@@ -66,6 +66,8 @@ JH/04 Add expansion item ${acl {name}{arg}...}, expansion condition
 
 JH/05 Permit multiple router/transport headers_add/remove lines.
 
+JH/06 Add dnsdb pseudo-lookup "a+" to do an "aaaa" + "a" combination.
+
 Exim version 4.80
 -----------------
 
index 94307c8..7c02afb 100644 (file)
@@ -112,6 +112,9 @@ Version 4.81
 12. New ACL modifier "remove_header" can remove headers before message gets
     handled by routers/transports.
 
+13. New dnsdb lookup pseudo-type "a+".  A sequence of "a6" (if configured),
+    "aaaa" and "a" lookups is done and the full set of results returned.
+
 Version 4.80
 ------------
 
index 3287166..2816fc9 100644 (file)
@@ -354,6 +354,7 @@ side, put in definitions for all the ones that Exim uses. */
 #define T_ZNS (-1)
 #define T_MXH (-2)
 #define T_CSA (-3)
+#define T_APL (-4)
 
 /* The resolv.h header defines __P(x) on some Solaris 2.5.1 systems (without
 checking that it is already defined, in fact). This conflicts with other
index 0bbc86a..ec1cd15 100644 (file)
@@ -27,6 +27,7 @@ header files. */
 static const char *type_names[] = {
   "a",
 #if HAVE_IPV6
+  "a+",
   "aaaa",
   #ifdef SUPPORT_A6
   "a6",
@@ -47,6 +48,7 @@ static const char *type_names[] = {
 static int type_values[] = {
   T_A,
 #if HAVE_IPV6
+  T_APL,     /* Private type for AAAA + A */
   T_AAAA,
   #ifdef SUPPORT_A6
   T_A6,
@@ -280,157 +282,178 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer)))
     domain = rbuffer;
     }
 
-  DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", domain);
-
-  /* Do the lookup and sort out the result. There are three special types that
-  are handled specially: T_CSA, T_ZNS and T_MXH. The former two are handled in
-  a special lookup function so that the facility could be used from other
-  parts of the Exim code. The latter affects only what happens later on in
-  this function, but for tidiness it is handled in a similar way. If the
-  lookup fails, continue with the next domain. In the case of DEFER, adjust
-  the final "nothing found" result, but carry on to the next domain. */
-
-  found = domain;
-  rc = dns_special_lookup(&dnsa, domain, type, &found);
-
-  if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue;
-  if (rc != DNS_SUCCEED)
+  do
     {
-    if (defer_mode == DEFER) return DEFER;          /* always defer */
-      else if (defer_mode == PASS) failrc = DEFER;  /* defer only if all do */
-    continue;                                       /* treat defer as fail */
-    }
-
-  /* Search the returned records */
+    DEBUG(D_lookup) debug_printf("dnsdb key: %s\n", domain);
+
+    /* Do the lookup and sort out the result. There are four special types that
+    are handled specially: T_CSA, T_ZNS, T_APL and T_MXH.
+    The first two are handled in a special lookup function so that the facility
+    could be used from other parts of the Exim code. T_APL is handled by looping
+    over the types of A lookup.  T_MXH affects only what happens later on in
+    this function, but for tidiness it is handled by the "special". If the
+    lookup fails, continue with the next domain. In the case of DEFER, adjust
+    the final "nothing found" result, but carry on to the next domain. */
+
+    found = domain;
+    if (type == T_APL)         /* NB cannot happen unless HAVE_IPV6 */
+      {
+#if HAVE_IPV6 && defined(SUPPORT_A6)
+      if (searchtype == T_APL)  searchtype = T_A6;
+#endif
+#if HAVE_IPV6 && !defined(SUPPORT_A6)
+      if (searchtype == T_APL)  searchtype = T_AAAA;
+#endif
+      else if (searchtype == T_A6)   searchtype = T_AAAA;
+      else if (searchtype == T_AAAA) searchtype = T_A;
+      rc = dns_special_lookup(&dnsa, domain, searchtype, &found);
+      }
+    else
+      rc = dns_special_lookup(&dnsa, domain, type, &found);
 
-  for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
-       rr != NULL;
-       rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
-    {
-    if (rr->type != searchtype) continue;
+    if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue;
+    if (rc != DNS_SUCCEED)
+      {
+      if (defer_mode == DEFER) return DEFER;          /* always defer */
+      if (defer_mode == PASS) failrc = DEFER;         /* defer only if all do */
+      continue;                                       /* treat defer as fail */
+      }
 
-    /* There may be several addresses from an A6 record. Put the configured
-    separator between them, just as for between several records. However, A6
-    support is not normally configured these days. */
+    /* Search the returned records */
 
-    if (type == T_A ||
-        #ifdef SUPPORT_A6
-        type == T_A6 ||
-        #endif
-        type == T_AAAA)
+    for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+         rr != NULL;
+         rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
       {
-      dns_address *da;
-      for (da = dns_address_from_rr(&dnsa, rr); da != NULL; da = da->next)
+      if (rr->type != searchtype) continue;
+
+      /* There may be several addresses from an A6 record. Put the configured
+      separator between them, just as for between several records. However, A6
+      support is not normally configured these days. */
+
+      if (type == T_A ||
+          #ifdef SUPPORT_A6
+          type == T_A6 ||
+          #endif
+          type == T_AAAA ||
+         type == T_APL)
         {
-        if (ptr != 0) yield = string_cat(yield, &size, &ptr, outsep, 1);
-        yield = string_cat(yield, &size, &ptr, da->address,
-          Ustrlen(da->address));
+        dns_address *da;
+        for (da = dns_address_from_rr(&dnsa, rr); da != NULL; da = da->next)
+          {
+          if (ptr != 0) yield = string_cat(yield, &size, &ptr, outsep, 1);
+          yield = string_cat(yield, &size, &ptr, da->address,
+            Ustrlen(da->address));
+          }
+        continue;
         }
-      continue;
-      }
 
-    /* Other kinds of record just have one piece of data each, but there may be
-    several of them, of course. */
+      /* Other kinds of record just have one piece of data each, but there may be
+      several of them, of course. */
 
-    if (ptr != 0) yield = string_cat(yield, &size, &ptr, outsep, 1);
+      if (ptr != 0) yield = string_cat(yield, &size, &ptr, outsep, 1);
 
-    if (type == T_TXT || type == T_SPF)
-      {
-      if (outsep2 == NULL)
-        {
-        /* output only the first item of data */
-        yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1),
-          (rr->data)[0]);
-        }
-      else
+      if (type == T_TXT || type == T_SPF)
         {
-        /* output all items */
-        int data_offset = 0;
-        while (data_offset < rr->size)
+        if (outsep2 == NULL)
           {
-          uschar chunk_len = (rr->data)[data_offset++];
-          if (outsep2[0] != '\0' && data_offset != 1)
-            yield = string_cat(yield, &size, &ptr, outsep2, 1);
-          yield = string_cat(yield, &size, &ptr,
+          /* output only the first item of data */
+          yield = string_cat(yield, &size, &ptr, (uschar *)(rr->data+1),
+            (rr->data)[0]);
+          }
+        else
+          {
+          /* output all items */
+          int data_offset = 0;
+          while (data_offset < rr->size)
+            {
+            uschar chunk_len = (rr->data)[data_offset++];
+            if (outsep2[0] != '\0' && data_offset != 1)
+              yield = string_cat(yield, &size, &ptr, outsep2, 1);
+            yield = string_cat(yield, &size, &ptr,
                              (uschar *)((rr->data)+data_offset), chunk_len);
-          data_offset += chunk_len;
+            data_offset += chunk_len;
+            }
           }
         }
-      }
-    else   /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SRV */
-      {
-      int priority, weight, port;
-      uschar s[264];
-      uschar *p = (uschar *)(rr->data);
-
-      if (type == T_MXH)
-        {
-        /* mxh ignores the priority number and includes only the hostnames */
-        GETSHORT(priority, p);
-        }
-      else if (type == T_MX)
-        {
-        GETSHORT(priority, p);
-        sprintf(CS s, "%d ", priority);
-        yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
-        }
-      else if (type == T_SRV)
-        {
-        GETSHORT(priority, p);
-        GETSHORT(weight, p);
-        GETSHORT(port, p);
-        sprintf(CS s, "%d %d %d ", priority, weight, port);
-        yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
-        }
-      else if (type == T_CSA)
+      else   /* T_CNAME, T_CSA, T_MX, T_MXH, T_NS, T_PTR, T_SRV */
         {
-        /* See acl_verify_csa() for more comments about CSA. */
-
-        GETSHORT(priority, p);
-        GETSHORT(weight, p);
-        GETSHORT(port, p);
-
-        if (priority != 1) continue;      /* CSA version must be 1 */
+        int priority, weight, port;
+        uschar s[264];
+        uschar *p = (uschar *)(rr->data);
 
-        /* If the CSA record we found is not the one we asked for, analyse
-        the subdomain assertions in the port field, else analyse the direct
-        authorization status in the weight field. */
-
-        if (found != domain)
+        if (type == T_MXH)
           {
-          if (port & 1) *s = 'X';         /* explicit authorization required */
-          else *s = '?';                  /* no subdomain assertions here */
+          /* mxh ignores the priority number and includes only the hostnames */
+          GETSHORT(priority, p);
           }
-        else
+        else if (type == T_MX)
           {
-          if (weight < 2) *s = 'N';       /* not authorized */
-          else if (weight == 2) *s = 'Y'; /* authorized */
-          else if (weight == 3) *s = '?'; /* unauthorizable */
-          else continue;                  /* invalid */
+          GETSHORT(priority, p);
+          sprintf(CS s, "%d ", priority);
+          yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+          }
+        else if (type == T_SRV)
+          {
+          GETSHORT(priority, p);
+          GETSHORT(weight, p);
+          GETSHORT(port, p);
+          sprintf(CS s, "%d %d %d ", priority, weight, port);
+          yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
+          }
+        else if (type == T_CSA)
+          {
+          /* See acl_verify_csa() for more comments about CSA. */
+
+          GETSHORT(priority, p);
+          GETSHORT(weight, p);
+          GETSHORT(port, p);
+
+          if (priority != 1) continue;      /* CSA version must be 1 */
+
+          /* If the CSA record we found is not the one we asked for, analyse
+          the subdomain assertions in the port field, else analyse the direct
+          authorization status in the weight field. */
+
+          if (found != domain)
+            {
+            if (port & 1) *s = 'X';         /* explicit authorization required */
+            else *s = '?';                  /* no subdomain assertions here */
+            }
+          else
+            {
+            if (weight < 2) *s = 'N';       /* not authorized */
+            else if (weight == 2) *s = 'Y'; /* authorized */
+            else if (weight == 3) *s = '?'; /* unauthorizable */
+            else continue;                  /* invalid */
+            }
+
+          s[1] = ' ';
+          yield = string_cat(yield, &size, &ptr, s, 2);
           }
 
-        s[1] = ' ';
-        yield = string_cat(yield, &size, &ptr, s, 2);
-        }
-
-      /* GETSHORT() has advanced the pointer to the target domain. */
+        /* GETSHORT() has advanced the pointer to the target domain. */
 
-      rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
-        (DN_EXPAND_ARG4_TYPE)(s), sizeof(s));
+        rc = dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, p,
+          (DN_EXPAND_ARG4_TYPE)(s), sizeof(s));
 
-      /* If an overlong response was received, the data will have been
-      truncated and dn_expand may fail. */
+        /* If an overlong response was received, the data will have been
+        truncated and dn_expand may fail. */
 
-      if (rc < 0)
-        {
-        log_write(0, LOG_MAIN, "host name alias list truncated: type=%s "
-          "domain=%s", dns_text_type(type), domain);
-        break;
+        if (rc < 0)
+          {
+          log_write(0, LOG_MAIN, "host name alias list truncated: type=%s "
+            "domain=%s", dns_text_type(type), domain);
+          break;
+          }
+        else yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
         }
-      else yield = string_cat(yield, &size, &ptr, s, Ustrlen(s));
-      }
-    }    /* Loop for list of returned records */
-  }      /* Loop for list of domains */
+      }    /* Loop for list of returned records */
+
+           /* Loop for set of A-lookupu types */
+    } while (type == T_APL && searchtype != T_A);
+
+  }        /* Loop for list of domains */
 
 /* Reclaim unused memory */
 
index 08cd326..fe5a41b 100644 (file)
@@ -3,4 +3,8 @@
 exim -be
 ptr=V6NET:0:12:1:a00:20ff:fe86:a062 ${lookup dnsdb {ptr=<;V6NET:0:12:1:a00:20ff:fe86:a062}{$value}{fail}}
 ptr=V6NET:0:12:1:a00:20ff:fe86:a062 ${lookup dnsdb {ptr=V6NET:0:12:1:a00:20ff:fe86:a062}{$value}{fail}}
+
+a=46.test.ex       ${lookup dnsdb{>; a=46.test.ex}{$value}fail}
+aaaa=46.test.ex    ${lookup dnsdb{>; aaaa=46.test.ex}{$value}fail}
+a+=46.test.ex      ${lookup dnsdb{>; a+=46.test.ex}{$value}fail}
 ****
index 3b9e93a..8a3cf33 100644 (file)
@@ -1,3 +1,7 @@
 > ptr=V6NET:0:12:1:a00:20ff:fe86:a062 testptr-arpa.ipv6.test.ex
 > ptr=V6NET:0:12:1:a00:20ff:fe86:a062 testptr-arpa.ipv6.test.ex
 > 
+> a=46.test.ex       V4NET.0.0.4
+> aaaa=46.test.ex    V6NET:ffff:836f:a00:a:800:200a:c031
+> a+=46.test.ex      V6NET:ffff:836f:a00:a:800:200a:c031;V4NET.0.0.4
+>