(1) Typo in redirect router; (2) Update version number; (3) Update
[exim.git] / src / src / lookups / dnsdb.c
index 29a36081e951b0fc4dd6a5bf28fa28b3cc80592f..7f42963a5937bfe36d80261f2cff3e0d2c5eee43 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/lookups/dnsdb.c,v 1.4 2004/11/24 15:43:36 ph10 Exp $ */
+/* $Cambridge: exim/src/src/lookups/dnsdb.c,v 1.8 2005/01/04 10:00:44 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2004 */
+/* Copyright (c) University of Cambridge 1995 - 2005 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 #include "../exim.h"
@@ -86,11 +86,17 @@ consist of a number of parts.
 separator character that is used when multiple records are found. The default 
 separator is newline.
 
-(b) If the next sequence of characters is a sequence of letters and digits 
+(b) If the next sequence of characters is 'defer_FOO' followed by a comma,
+the defer behaviour is set to FOO. The possible behaviours are: 'strict', where
+any defer causes the whole lookup to defer; 'lax', where a defer causes the
+whole lookup to defer only if none of the DNS queries succeeds; and 'never',
+where all defers are as if the lookup failed. The default is 'lax'.
+
+(c) If the next sequence of characters is a sequence of letters and digits 
 followed by '=', it is interpreted as the name of the DNS record type. The 
-default is "A".
+default is "TXT".
 
-(c) Then there follows list of domain names. This is a generalized Exim list, 
+(d) Then there follows list of domain names. This is a generalized Exim list, 
 which may start with '<' in order to set a specific separator. The default 
 separator, as always, is colon. */
 
@@ -102,7 +108,9 @@ int rc;
 int size = 256;
 int ptr = 0;
 int sep = 0;
+int defer_mode = PASS;
 int type = T_TXT;
+int failrc = FAIL;
 uschar *outsep = US"\n";
 uschar *equals, *domain;
 uschar buffer[256];
@@ -131,6 +139,40 @@ if (*keystring == '>')
   while (isspace(*keystring)) keystring++;
   } 
 
+/* Check for a defer behaviour keyword. */
+
+if (strncmpic(keystring, US"defer_", 6) == 0)
+  {
+  keystring += 6;
+  if (strncmpic(keystring, US"strict", 6) == 0)
+    {
+    defer_mode = DEFER;
+    keystring += 6;
+    }
+  else if (strncmpic(keystring, US"lax", 3) == 0)
+    {
+    defer_mode = PASS;
+    keystring += 3;
+    }
+  else if (strncmpic(keystring, US"never", 5) == 0)
+    {
+    defer_mode = OK;
+    keystring += 5;
+    }
+  else
+    {
+    *errmsg = US"unsupported dnsdb defer behaviour";
+    return DEFER;
+    }
+  while (isspace(*keystring)) keystring++;
+  if (*keystring++ != ',')
+    {
+    *errmsg = US"dnsdb defer behaviour syntax error";
+    return DEFER;
+    }
+  while (isspace(*keystring)) keystring++;
+  }
+
 /* If the keystring contains an = this must be preceded by a valid type name. */
 
 if ((equals = Ustrchr(keystring, '=')) != NULL)
@@ -189,10 +231,12 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer)))
   int searchtype = (type == T_ZNS)? T_NS :          /* record type we want */
                    (type == T_MXH)? T_MX : type; 
 
-  /* If the type is PTR, we have to construct the relevant magic lookup
-  key. This code is now in a separate function. */
+  /* If the type is PTR, we have to construct the relevant magic lookup key if
+  the original is an IP address (some experimental protocols are using PTR
+  records for different purposes where the key string is a host name). This
+  code for doing the reversal is now in a separate function. */
   
-  if (type == T_PTR)
+  if (type == T_PTR && string_is_ip_address(domain, NULL)) 
     {
     dns_build_reverse(domain, rbuffer);
     domain = rbuffer;
@@ -205,12 +249,18 @@ while ((domain = string_nextinlist(&keystring, &sep, buffer, sizeof(buffer)))
   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. */
+  continue with the next domain. In the case of DEFER, adjust the final 
+  "nothing found" result, but carry on to the next domain. */
   
   rc = dns_special_lookup(&dnsa, domain, type, NULL);
   
   if (rc == DNS_NOMATCH || rc == DNS_NODATA) continue;
-  if (rc != DNS_SUCCEED) return DEFER;
+  if (rc != DNS_SUCCEED)
+    {
+    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 */
 
@@ -301,7 +351,7 @@ store_reset(yield + ptr + 1);
 /* If ptr == 0 we have not found anything. Otherwise, insert the terminating 
 zero and return the result. */
 
-if (ptr == 0) return FAIL;
+if (ptr == 0) return failrc;
 yield[ptr] = 0;
 *result = yield;
 return OK;