Add retry type "lookup". Bug 1566
[exim.git] / src / src / routers / dnslookup.c
index aced23747489f2a6375d4ecf74e593e96e4e5d58..8ef4e0da97af339a8c0991cc684d4cbd7bc12064 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/routers/dnslookup.c,v 1.6 2005/09/15 16:02:07 fanf2 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2009 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 #include "../exim.h"
@@ -20,6 +18,12 @@ optionlist dnslookup_router_options[] = {
       (void *)(offsetof(dnslookup_router_options_block, check_secondary_mx)) },
   { "check_srv",          opt_stringptr,
       (void *)(offsetof(dnslookup_router_options_block, check_srv)) },
+  { "dnssec_request_domains",         opt_stringptr,
+      (void *)(offsetof(dnslookup_router_options_block, dnssec_request_domains)) },
+  { "dnssec_require_domains",         opt_stringptr,
+      (void *)(offsetof(dnslookup_router_options_block, dnssec_require_domains)) },
+  { "fail_defer_domains", opt_stringptr,
+      (void *)(offsetof(dnslookup_router_options_block, fail_defer_domains)) },
   { "mx_domains",         opt_stringptr,
       (void *)(offsetof(dnslookup_router_options_block, mx_domains)) },
   { "mx_fail_domains",    opt_stringptr,
@@ -55,7 +59,10 @@ dnslookup_router_options_block dnslookup_router_option_defaults = {
   NULL,            /* mx_domains */
   NULL,            /* mx_fail_domains */
   NULL,            /* srv_fail_domains */
-  NULL             /* check_srv */
+  NULL,            /* check_srv */
+  NULL,            /* dnssec_request_domains */
+  NULL,            /* dnssec_require_domains */
+  NULL             /* fail_defer_domains */
 };
 
 
@@ -142,10 +149,10 @@ dnslookup_router_options_block *ob =
   (dnslookup_router_options_block *)(rblock->options_block);
 uschar *srv_service = NULL;
 uschar *widen = NULL;
-uschar *pre_widen = addr->domain;
-uschar *post_widen = NULL;
-uschar *fully_qualified_name;
-uschar *listptr;
+const uschar *pre_widen = addr->domain;
+const uschar *post_widen = NULL;
+const uschar *fully_qualified_name;
+const uschar *listptr;
 uschar widen_buffer[256];
 
 addr_new = addr_new;          /* Keep picky compilers happy */
@@ -157,10 +164,10 @@ DEBUG(D_route)
 
 /* If an SRV check is required, expand the service name */
 
-if (ob->check_srv != NULL)
+if (ob->check_srv)
   {
-  srv_service = expand_string(ob->check_srv);
-  if (srv_service == NULL && !expand_string_forcedfail)
+  if (  !(srv_service = expand_string(ob->check_srv))
+     && !expand_string_forcedfail)
     {
     addr->message = string_sprintf("%s router: failed to expand \"%s\": %s",
       rblock->name, ob->check_srv, expand_string_message);
@@ -191,8 +198,8 @@ does not appear in the message header so it is also OK to widen. The
 suppression of widening for sender addresses is silent because it is the
 normal desirable behaviour. */
 
-if (ob->widen_domains != NULL &&
-    (verify != v_sender || !ob->rewrite_headers || addr->parent != NULL))
+if (  ob->widen_domains
+   && (verify != v_sender || !ob->rewrite_headers || addr->parent))
   {
   listptr = ob->widen_domains;
   widen = string_nextinlist(&listptr, &widen_sep, widen_buffer,
@@ -216,12 +223,12 @@ for (;;)
   int flags = whichrrs;
   BOOL removed = FALSE;
 
-  if (pre_widen != NULL)
+  if (pre_widen)
     {
     h.name = pre_widen;
     pre_widen = NULL;
     }
-  else if (widen != NULL)
+  else if (widen)
     {
     h.name = string_sprintf("%s.%s", addr->domain, widen);
     widen = string_nextinlist(&listptr, &widen_sep, widen_buffer,
@@ -229,7 +236,7 @@ for (;;)
     DEBUG(D_route) debug_printf("%s router widened %s to %s\n", rblock->name,
       addr->domain, h.name);
     }
-  else if (post_widen != NULL)
+  else if (post_widen)
     {
     h.name = post_widen;
     post_widen = NULL;
@@ -253,13 +260,19 @@ for (;;)
 
   /* Unfortunately, we cannot set the mx_only option in advance, because the
   DNS lookup may extend an unqualified name. Therefore, we must do the test
-  subsequently. */
+  subsequently. We use the same logic as that for widen_domains above to avoid
+  requesting a header rewrite that cannot work. */
 
-  if (ob->qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
-  if (ob->search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
+  if (verify != v_sender || !ob->rewrite_headers || addr->parent)
+    {
+    if (ob->qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
+    if (ob->search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
+    }
 
-  rc = host_find_bydns(&h, rblock->ignore_target_hosts, flags, srv_service,
-    ob->srv_fail_domains, ob->mx_fail_domains, &fully_qualified_name, &removed);
+  rc = host_find_bydns(&h, CUS rblock->ignore_target_hosts, flags, srv_service,
+    ob->srv_fail_domains, ob->mx_fail_domains,
+    ob->dnssec_request_domains, ob->dnssec_require_domains,
+    &fully_qualified_name, &removed);
   if (removed) setflag(addr, af_local_host_removed);
 
   /* If host found with only address records, test for the domain's being in
@@ -267,9 +280,9 @@ for (;;)
   the option is historical. */
 
   if ((rc == HOST_FOUND || rc == HOST_FOUND_LOCAL) && h.mx < 0 &&
-       ob->mx_domains != NULL)
-    {
-    switch(match_isinlist(fully_qualified_name, &(ob->mx_domains), 0,
+       ob->mx_domains)
+    switch(match_isinlist(fully_qualified_name,
+          CUSS &(ob->mx_domains), 0,
           &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL))
       {
       case DEFER:
@@ -281,7 +294,6 @@ for (;;)
         rblock->name, fully_qualified_name);
       continue;
       }
-    }
 
   /* Deferral returns forthwith, and anything other than failure breaks the
   loop. */
@@ -300,9 +312,9 @@ for (;;)
 
   if (rc != HOST_FIND_FAILED) break;
 
-  /* Check to see if the failure is the result of MX records pointing
-  to non-existent domains, and if so, set an appropriate error message; the
-  case of an SRV record pointing to "." is another special case that we can
+  /* Check to see if the failure is the result of MX records pointing to
+  non-existent domains, and if so, set an appropriate error message; the case
+  of an MX or SRV record pointing to "." is another special case that we can
   detect. Otherwise "unknown mail domain" is used, which is confusing. Also, in
   this case don't do the widening. We need check only the first host to see if
   its MX has been filled in, but there is no address, because if there were any
@@ -315,11 +327,12 @@ for (;;)
     {
     setflag(addr, af_pass_message);   /* This is not a security risk */
     if (h.name[0] == 0)
-      addr->message = US"an SRV record indicated no SMTP service";
+      addr->message = US"an MX or SRV record indicated no SMTP service";
     else
       {
+      addr->basic_errno = ERRNO_UNKNOWNHOST;
       addr->message = US"all relevant MX records point to non-existent hosts";
-      if (!allow_mx_to_ip && string_is_ip_address(h.name, NULL) > 0)
+      if (!allow_mx_to_ip && string_is_ip_address(h.name, NULL) != 0)
         {
         addr->user_message =
           string_sprintf("It appears that the DNS operator for %s\n"
@@ -329,6 +342,22 @@ for (;;)
           addr->message);
         }
       }
+    if (ob->fail_defer_domains)
+      {
+      switch(match_isinlist(fully_qualified_name,
+           CUSS &ob->fail_defer_domains, 0,
+           &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL))
+       {
+       case DEFER:
+         addr->message = US"lookup defer for fail_defer_domains";
+         return DEFER;
+
+       case OK:
+         DEBUG(D_route) debug_printf("%s router: matched fail_defer_domains\n",
+           rblock->name);
+         return DEFER;
+       }
+      }
     return DECLINE;
     }
 
@@ -420,3 +449,5 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
 }
 
 /* End of routers/dnslookup.c */
+/* vi: aw ai sw=2
+*/