Copyright updates:
[exim.git] / src / src / routers / rf_lookup_hostlist.c
index 78eda22fba3ce0d469c07917d2d2012be9be80ce..79a7799279932891e77a040482cf6d65611b51ae 100644 (file)
@@ -3,6 +3,7 @@
 *************************************************/
 
 /* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) The Exim Maintainers 2020 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 
@@ -35,7 +36,8 @@ Arguments:
   rblock               the router block
   addr                 the address being routed
   ignore_target_hosts  list of hosts to ignore
-  lookup_type          lk_default or lk_byname or lk_bydns
+  lookup_type          LK_DEFAULT or LK_BYNAME or LK_BYDNS,
+                      plus LK_IPV4_{ONLY,PREFER}
   hff_code             what to do for host find failed
   addr_new             passed to rf_self_action for self=reroute
 
@@ -52,7 +54,6 @@ rf_lookup_hostlist(router_instance *rblock, address_item *addr,
   address_item **addr_new)
 {
 BOOL self_send = FALSE;
-host_item *h, *next_h, *prev;
 
 /* Look up each host address. A lookup may add additional items into the chain
 if there are multiple addresses. Hence the use of next_h to start each cycle of
@@ -61,7 +62,7 @@ host, omit it and any subsequent hosts - i.e. treat the list like an ordered
 list of MX hosts. If the first host is the local host, act according to the
 "self" option in the configuration. */
 
-for (prev = NULL, h = addr->host_list; h; h = next_h)
+for (host_item * prev = NULL, * h = addr->host_list, *next_h; h; h = next_h)
   {
   const uschar *canonical_name;
   int rc, len, port, mx, sort_key;
@@ -90,6 +91,12 @@ for (prev = NULL, h = addr->host_list; h; h = next_h)
   len = Ustrlen(h->name);
   if (len > 3 && strcmpic(h->name + len - 3, US"/mx") == 0)
     {
+    int whichrrs = lookup_type & LK_IPV4_ONLY
+      ? HOST_FIND_BY_MX | HOST_FIND_IPV4_ONLY
+      : lookup_type & LK_IPV4_PREFER
+      ? HOST_FIND_BY_MX | HOST_FIND_IPV4_FIRST
+      : HOST_FIND_BY_MX;
+
     DEBUG(D_route|D_host_lookup)
       debug_printf("doing DNS MX lookup for %s\n", h->name);
 
@@ -97,19 +104,19 @@ for (prev = NULL, h = addr->host_list; h; h = next_h)
     h->name = string_copyn(h->name, len - 3);
     rc = host_find_bydns(h,
         ignore_target_hosts,
-        HOST_FIND_BY_MX,                /* look only for MX records */
-        NULL,                           /* SRV service not relevant */
-        NULL,                           /* failing srv domains not relevant */
-        NULL,                           /* no special mx failing domains */
+        whichrrs,                      /* look only for MX records */
+        NULL,                          /* SRV service not relevant */
+        NULL,                          /* failing srv domains not relevant */
+        NULL,                          /* no special mx failing domains */
         &rblock->dnssec,               /* dnssec request/require */
-        NULL,                           /* fully_qualified_name */
-        NULL);                          /* indicate local host removed */
+        NULL,                          /* fully_qualified_name */
+        NULL);                         /* indicate local host removed */
     }
 
   /* If explicitly configured to look up by name, or if the "host name" is
   actually an IP address, do a byname lookup. */
 
-  else if (lookup_type == lk_byname || string_is_ip_address(h->name, NULL) != 0)
+  else if (lookup_type & LK_BYNAME || string_is_ip_address(h->name, NULL) != 0)
     {
     DEBUG(D_route|D_host_lookup) debug_printf("calling host_find_byname\n");
     rc = host_find_byname(h, ignore_target_hosts, HOST_FIND_QUALIFY_SINGLE,
@@ -123,8 +130,14 @@ for (prev = NULL, h = addr->host_list; h; h = next_h)
   else
     {
     BOOL removed;
+    int whichrrs = lookup_type & LK_IPV4_ONLY
+      ? HOST_FIND_BY_A
+      : lookup_type & LK_IPV4_PREFER
+      ? HOST_FIND_BY_A | HOST_FIND_BY_AAAA | HOST_FIND_IPV4_FIRST
+      : HOST_FIND_BY_A | HOST_FIND_BY_AAAA;
+
     DEBUG(D_route|D_host_lookup) debug_printf("doing DNS lookup\n");
-    switch (rc = host_find_bydns(h, ignore_target_hosts, HOST_FIND_BY_A, NULL,
+    switch (rc = host_find_bydns(h, ignore_target_hosts, whichrrs, NULL,
        NULL, NULL,
        &rblock->dnssec,                        /* domains for request/require */
        &canonical_name, &removed))
@@ -133,10 +146,12 @@ for (prev = NULL, h = addr->host_list; h; h = next_h)
         if (removed) setflag(addr, af_local_host_removed);
        break;
       case HOST_FIND_FAILED:
-       if (lookup_type == lk_default)
+       if (lookup_type & LK_DEFAULT)
          {
          DEBUG(D_route|D_host_lookup)
-           debug_printf("DNS lookup failed: trying getipnodebyname\n");
+           debug_printf("DNS lookup failed: trying %s\n",
+             f.running_in_test_harness
+             ? "host_fake_gethostbyname" : "getipnodebyname");
          rc = host_find_byname(h, ignore_target_hosts, HOST_FIND_QUALIFY_SINGLE,
            &canonical_name, TRUE);
          }
@@ -146,6 +161,12 @@ for (prev = NULL, h = addr->host_list; h; h = next_h)
 
   /* Temporary failure defers, unless pass_on_timeout is set */
 
+  if (rc == HOST_FIND_SECURITY)
+    {
+    addr->message = string_sprintf("host lookup for %s done insecurely" , h->name);
+    addr->basic_errno = ERRNO_DNSDEFER;
+    return DEFER;
+    }
   if (rc == HOST_FIND_AGAIN)
     {
     if (rblock->pass_on_timeout)
@@ -178,7 +199,7 @@ for (prev = NULL, h = addr->host_list; h; h = next_h)
     addr->message =
       string_sprintf("lookup of host \"%s\" failed in %s router%s",
         h->name, rblock->name,
-        host_find_failed_syntax? ": syntax error in name" : "");
+        f.host_find_failed_syntax? ": syntax error in name" : "");
 
     if (hff_code == hff_defer) return DEFER;
     if (hff_code == hff_fail) return FAIL;
@@ -191,20 +212,15 @@ for (prev = NULL, h = addr->host_list; h; h = next_h)
   port, mx and sort_key. */
 
   if (port != PORT_NONE)
-    {
-    host_item *hh;
-    for (hh = h; hh != next_h; hh = hh->next) hh->port = port;
-    }
+    for (host_item * hh = h; hh != next_h; hh = hh->next)
+      hh->port = port;
 
   if (mx != MX_NONE)
-    {
-    host_item *hh;
-    for (hh = h; hh != next_h; hh = hh->next)
+    for (host_item * hh = h; hh != next_h; hh = hh->next)
       {
       hh->mx = mx;
       hh->sort_key = sort_key;
       }
-    }
 
   /* A local host gets chopped, with its successors, if there are previous
   hosts. Otherwise the self option is used. If it is set to "send", any
@@ -217,7 +233,7 @@ for (prev = NULL, h = addr->host_list; h; h = next_h)
       DEBUG(D_route)
         {
         debug_printf("Removed from host list:\n");
-        for (; h != NULL; h = h->next) debug_printf("  %s\n", h->name);
+        for (; h; h = h->next) debug_printf("  %s\n", h->name);
         }
       prev->next = NULL;
       setflag(addr, af_local_host_removed);