Fix mariadb/mysql macro confusion
[exim.git] / src / src / host.c
index 3c685b0e4686c26e18bdae3ec3ff3f9356cf07b4..b3b8b1882a127eb473663d37df4c512949133927 100644 (file)
@@ -2,7 +2,7 @@
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2012 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or
@@ -257,7 +257,7 @@ else
       count++;
 
   yield = store_get(sizeof(struct hostent));
-  alist = store_get((count + 1) * sizeof(char **));
+  alist = store_get((count + 1) * sizeof(char *));
   adds  = store_get(count *alen);
 
   yield->h_name = CS name;
@@ -544,7 +544,7 @@ use this directly as the first item for Received: because it ain't an RFC 2822
 domain. Sigh. */
 
 address = string_sprintf("[%s]:%d", sender_host_address, sender_host_port);
-if ((log_extra_selector & LX_incoming_port) == 0 || sender_host_port <= 0)
+if (!LOGGING(incoming_port) || sender_host_port <= 0)
   *(Ustrrchr(address, ':')) = 0;
 
 /* If there's no EHLO/HELO data, we can't show it. */
@@ -554,7 +554,7 @@ if (sender_helo_name == NULL) show_helo = FALSE;
 /* If HELO/EHLO was followed by an IP literal, it's messy because of two
 features of IPv6. Firstly, there's the "IPv6:" prefix (Exim is liberal and
 doesn't require this, for historical reasons). Secondly, IPv6 addresses may not
-be given in canonical form, so we have to canonicize them before comparing. As
+be given in canonical form, so we have to canonicalize them before comparing. As
 it happens, the code works for both IPv4 and IPv6. */
 
 else if (sender_helo_name[0] == '[' &&
@@ -597,12 +597,12 @@ if (sender_host_name == NULL)
   sender_fullhost = (sender_helo_name == NULL)? address :
     string_sprintf("(%s) %s", sender_helo_name, address);
 
-  sender_rcvhost = string_cat(NULL, &size, &ptr, address, adlen);
+  sender_rcvhost = string_catn(NULL, &size, &ptr, address, adlen);
 
   if (sender_ident != NULL || show_helo || portptr != NULL)
     {
     int firstptr;
-    sender_rcvhost = string_cat(sender_rcvhost, &size, &ptr, US" (", 2);
+    sender_rcvhost = string_catn(sender_rcvhost, &size, &ptr, US" (", 2);
     firstptr = ptr;
 
     if (portptr != NULL)
@@ -617,7 +617,7 @@ if (sender_host_name == NULL)
       sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2,
         (firstptr == ptr)? US"ident=" : US" ident=", sender_ident);
 
-    sender_rcvhost = string_cat(sender_rcvhost, &size, &ptr, US")", 1);
+    sender_rcvhost = string_catn(sender_rcvhost, &size, &ptr, US")", 1);
     }
 
   sender_rcvhost[ptr] = 0;   /* string_cat() always leaves room */
@@ -695,8 +695,7 @@ else
   {
   uschar *flag = useflag? US"H=" : US"";
   uschar *iface = US"";
-  if ((log_extra_selector & LX_incoming_interface) != 0 &&
-       interface_address != NULL)
+  if (LOGGING(incoming_interface) && interface_address != NULL)
     iface = string_sprintf(" I=[%s]:%d", interface_address, interface_port);
   if (sender_ident == NULL)
     (void)string_format(big_buffer, big_buffer_size, "%s%s%s",
@@ -1068,7 +1067,7 @@ if (Ustrchr(address, ':') != NULL)
 /* Handle IPv4 address */
 
 (void)sscanf(CS address, "%d.%d.%d.%d", x, x+1, x+2, x+3);
-bin[v4offset] = (x[0] << 24) + (x[1] << 16) + (x[2] << 8) + x[3];
+bin[v4offset] = ((uint)x[0] << 24) + (x[1] << 16) + (x[2] << 8) + x[3];
 return v4offset+1;
 }
 
@@ -1099,7 +1098,7 @@ for (i = 0; i < count; i++)
   if (mask == 0) wordmask = 0;
   else if (mask < 32)
     {
-    wordmask = (-1) << (32 - mask);
+    wordmask = (uint)(-1) << (32 - mask);
     mask = 0;
     }
   else
@@ -1147,20 +1146,14 @@ if (count == 1)
   {
   j = binary[0];
   for (i = 24; i >= 0; i -= 8)
-    {
-    sprintf(CS tt, "%d.", (j >> i) & 255);
-    while (*tt) tt++;
-    }
+    tt += sprintf(CS tt, "%d.", (j >> i) & 255);
   }
 else
-  {
   for (i = 0; i < 4; i++)
     {
     j = binary[i];
-    sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep);
-    while (*tt) tt++;
+    tt += sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep);
     }
-  }
 
 tt--;   /* lose final separator */
 
@@ -1176,6 +1169,63 @@ return tt - buffer;
 }
 
 
+/* Like host_nmtoa() but: ipv6-only, canonical output, no mask
+
+Arguments:
+  binary      points to the ints
+  buffer      big enough to hold the result
+
+Returns:      the number of characters placed in buffer, not counting
+             the final nul.
+*/
+
+int
+ipv6_nmtoa(int * binary, uschar * buffer)
+{
+int i, j, k;
+uschar * c = buffer;
+uschar * d = NULL;     /* shut insufficiently "clever" compiler up */
+
+for (i = 0; i < 4; i++)
+  {                    /* expand to text */
+  j = binary[i];
+  c += sprintf(CS c, "%x:%x:", (j >> 16) & 0xffff, j & 0xffff);
+  }
+
+for (c = buffer, k = -1, i = 0; i < 8; i++)
+  {                    /* find longest 0-group sequence */
+  if (*c == '0')       /* must be "0:" */
+    {
+    uschar * s = c;
+    j = i;
+    while (c[2] == '0') i++, c += 2;
+    if (i-j > k)
+      {
+      k = i-j;         /* length of sequence */
+      d = s;           /* start of sequence */
+      }
+    }
+  while (*++c != ':') ;
+  c++;
+  }
+
+c[-1] = '\0';  /* drop trailing colon */
+
+/* debug_printf("%s: D k %d <%s> <%s>\n", __FUNCTION__, k, d, d + 2*(k+1)); */
+if (k >= 0)
+  {                    /* collapse */
+  c = d + 2*(k+1);
+  if (d == buffer) c--;        /* need extra colon */
+  *d++ = ':';  /* 1st 0 */
+  while ((*d++ = *c++)) ;
+  }
+else
+  d = c;
+
+return d - buffer;
+}
+
+
 
 /*************************************************
 *        Check port for tls_on_connect           *
@@ -1271,7 +1321,7 @@ for (i = 0; i < size; i++)
   if (mlen == 0) mask = 0;
   else if (mlen < 32)
     {
-    mask = (-1) << (32 - mlen);
+    mask = (uint)(-1) << (32 - mlen);
     mlen = 0;
     }
   else
@@ -1471,7 +1521,7 @@ int len;
 uschar *s, *t;
 struct hostent *hosts;
 struct in_addr addr;
-unsigned long time_msec;
+unsigned long time_msec = 0;   /* init to quieten dumb static analysis */
 
 if (slow_lookup_log) time_msec = get_time_in_ms();
 
@@ -1596,7 +1646,7 @@ Returns:      OK on success, the answer being placed in the global variable
               FAIL if no host name can be found
               DEFER if a temporary error was encountered
 
-The variable host_lookup_msg is set to an empty string on sucess, or to a
+The variable host_lookup_msg is set to an empty string on success, or to a
 reason for the failure otherwise, in a form suitable for tagging onto an error
 message, and also host_lookup_failed is set TRUE if the lookup failed. If there
 was a defer, host_lookup_deferred is set TRUE.
@@ -1928,16 +1978,6 @@ BOOL temp_error = FALSE;
 int af;
 #endif
 
-/* If we are in the test harness, a name ending in .test.again.dns always
-forces a temporary error response, unless the name is in
-dns_again_means_nonexist. */
-
-if (running_in_test_harness)
-  {
-  const uschar *endname = host->name + Ustrlen(host->name);
-  if (Ustrcmp(endname - 14, "test.again.dns") == 0) goto RETURN_AGAIN;
-  }
-
 /* Make sure DNS options are set as required. This appears to be necessary in
 some circumstances when the get..byname() function actually calls the DNS. */
 
@@ -1987,7 +2027,7 @@ for (i = 1; i <= times;
   BOOL ipv4_addr;
   int error_num = 0;
   struct hostent *hostdata;
-  unsigned long time_msec;
+  unsigned long time_msec = 0; /* compiler quietening */
 
   #ifdef STAND_ALONE
   printf("Looking up: %s\n", host->name);
@@ -2018,7 +2058,7 @@ for (i = 1; i <= times;
     }
   #endif   /* HAVE_IPV6 */
 
-  if (slow_lookup_log
+  if (   slow_lookup_log
       && (time_msec = get_time_in_ms() - time_msec) > slow_lookup_log)
     log_long_lookup(US"name", host->name, time_msec);
 
@@ -2265,11 +2305,10 @@ if (allow_ip && string_is_ip_address(host->name, NULL) != 0)
   return HOST_FOUND;
   }
 
-/* On an IPv6 system, unless IPv6 is disabled, go round the loop up to three
-times, looking for A6 and AAAA records the first two times. However, unless
+/* On an IPv6 system, unless IPv6 is disabled, go round the loop up to twice,
+looking for AAAA records the first time. However, unless
 doing standalone testing, we force an IPv4 lookup if the domain matches
-dns_ipv4_lookup is set. Since A6 records look like being abandoned, support
-them only if explicitly configured to do so. On an IPv4 system, go round the
+dns_ipv4_lookup is set.  On an IPv4 system, go round the
 loop once only, looking only for A records. */
 
 #if HAVE_IPV6
@@ -2291,7 +2330,7 @@ loop once only, looking only for A records. */
 
 for (; i >= 0; i--)
   {
-  static int types[] = { T_A, T_AAAA, T_A6 };
+  static int types[] = { T_A, T_AAAA };
   int type = types[i];
   int randoffset = (i == 0)? 500 : 0;  /* Ensures v6 sorts before v4 */
   dns_answer dnsa;
@@ -2302,12 +2341,13 @@ for (; i >= 0; i--)
     : dns_is_secure(&dnsa) ? US"yes" : US"no";
 
   DEBUG(D_dns)
-    if ((dnssec_request || dnssec_require)
-       & !dns_is_secure(&dnsa)
-       & dns_is_aa(&dnsa))
-      debug_printf("DNS lookup of %.256s (A/AAA/A6) requested AD, but got AA\n", host->name);
+    if (  (dnssec_request || dnssec_require)
+       && !dns_is_secure(&dnsa)
+       && dns_is_aa(&dnsa)
+       )
+      debug_printf("DNS lookup of %.256s (A/AAAA) requested AD, but got AA\n", host->name);
 
-  /* We want to return HOST_FIND_AGAIN if one of the A, A6, or AAAA lookups
+  /* We want to return HOST_FIND_AGAIN if one of the A or AAAA lookups
   fails or times out, but not if another one succeeds. (In the early
   IPv6 days there are name servers that always fail on AAAA, but are happy
   to give out an A record. We want to proceed with that A record.) */
@@ -2316,13 +2356,13 @@ for (; i >= 0; i--)
     {
     if (i == 0)  /* Just tried for an A record, i.e. end of loop */
       {
-      if (host->address != NULL) return HOST_FOUND;  /* A6 or AAAA was found */
+      if (host->address != NULL) return HOST_FOUND;  /* AAAA was found */
       if (rc == DNS_AGAIN || rc == DNS_FAIL || v6_find_again)
         return HOST_FIND_AGAIN;
       return HOST_FIND_FAILED;    /* DNS_NOMATCH or DNS_NODATA */
       }
 
-    /* Tried for an A6 or AAAA record: remember if this was a temporary
+    /* Tried for an AAAA record: remember if this was a temporary
     error, and look for the next record type. */
 
     if (rc != DNS_NOMATCH && rc != DNS_NODATA) v6_find_again = TRUE;
@@ -2343,7 +2383,7 @@ for (; i >= 0; i--)
        {
        log_write(L_host_lookup_failed, LOG_MAIN,
                "dnssec fail on %s for %.256s",
-               i>1 ? "A6" : i>0 ? "AAAA" : "A", host->name);
+               i>0 ? "AAAA" : "A", host->name);
        continue;
        }
       if (host->dnssec == DS_YES) /* set in host_find_bydns() */
@@ -2368,16 +2408,11 @@ for (; i >= 0; i--)
     {
     if (rr->type == type)
       {
-      /* dns_address *da = dns_address_from_rr(&dnsa, rr); */
-
-      dns_address *da;
-      da = dns_address_from_rr(&dnsa, rr);
+      dns_address *da = dns_address_from_rr(&dnsa, rr);
 
       DEBUG(D_host_lookup)
-        {
         if (!da) debug_printf("no addresses extracted from A6 RR for %s\n",
             host->name);
-        }
 
       /* This loop runs only once for A and AAAA records, but may run
       several times for an A6 record that generated multiple addresses. */
@@ -2469,10 +2504,10 @@ for (; i >= 0; i--)
     }
   }
 
-/* Control gets here only if the third lookup (the A record) succeeded.
+/* Control gets here only if the econdookup (the A record) succeeded.
 However, the address may not be filled in if it was ignored. */
 
-return (host->address == NULL)? HOST_IGNORED : HOST_FOUND;
+return host->address ? HOST_FOUND : HOST_IGNORED;
 }
 
 
@@ -2633,7 +2668,7 @@ if (rc != DNS_SUCCEED && (whichrrs & HOST_FIND_BY_MX) != 0)
   if (dnssec_request)
     {
     if (dns_is_secure(&dnsa))
-      { 
+      {
       DEBUG(D_host_lookup) debug_printf("%s MX DNSSEC\n", host->name);
       dnssec = DS_YES; lookup_dnssec_authenticated = US"yes";
       }
@@ -2742,17 +2777,15 @@ host which is not the primary hostname. */
 last = NULL;    /* Indicates that not even the first item is filled yet */
 
 for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
-     rr != NULL;
-     rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
+     rr;
+     rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == ind_type)
   {
   int precedence;
   int weight = 0;        /* For SRV records */
   int port = PORT_NONE;
-  uschar *s;             /* MUST be unsigned for GETSHORT */
+  const uschar * s = rr->data; /* MUST be unsigned for GETSHORT */
   uschar data[256];
 
-  if (rr->type != ind_type) continue;
-  s = rr->data;
   GETSHORT(precedence, s);      /* Pointer s is advanced */
 
   /* For MX records, we use a random "weight" which causes multiple records of
@@ -2885,6 +2918,12 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
   NEXT_MX_RR: continue;
   }
 
+if (!last)     /* No rr of correct type; give up */
+  {
+  yield = HOST_FIND_FAILED;
+  goto out;
+  }
+
 /* If the list of hosts was obtained from SRV records, there are two things to
 do. First, if there is only one host, and it's name is ".", it means there is
 no SMTP service at this domain. Otherwise, we have to sort the hosts of equal
@@ -2911,7 +2950,7 @@ if (ind_type == T_SRV)
       debug_printf("  %s P=%d W=%d\n", h->name, h->mx, h->sort_key % 1000);
     }
 
-  for (pptr = &host, h = host; h != last; pptr = &(h->next), h = h->next)
+  for (pptr = &host, h = host; h != last; pptr = &h->next, h = h->next)
     {
     int sum = 0;
     host_item *hh;
@@ -3016,7 +3055,8 @@ dns_init(FALSE, FALSE,       /* Disable qualify_single and search_parents */
 
 for (h = host; h != last->next; h = h->next)
   {
-  if (h->address != NULL) continue;  /* Inserted by a multihomed host */
+  if (h->address) continue;  /* Inserted by a multihomed host */
+
   rc = set_address_from_dns(h, &last, ignore_target_hosts, allow_mx_to_ip,
     NULL, dnssec_request, dnssec_require);
   if (rc != HOST_FOUND)
@@ -3028,7 +3068,7 @@ for (h = host; h != last->next; h = h->next)
       h->why = hwhy_deferred;
       }
     else
-      h->why = (rc == HOST_IGNORED)? hwhy_ignored : hwhy_failed;
+      h->why = rc == HOST_IGNORED ? hwhy_ignored : hwhy_failed;
     }
   }
 
@@ -3203,7 +3243,7 @@ while (Ufgets(buffer, 256, stdin) != NULL)
   else if (Ustrcmp(buffer, "request_dnssec")    == 0) request_dnssec = TRUE;
   else if (Ustrcmp(buffer, "no_request_dnssec") == 0) request_dnssec = FALSE;
   else if (Ustrcmp(buffer, "require_dnssec")    == 0) require_dnssec = TRUE;
-  else if (Ustrcmp(buffer, "no_reqiret_dnssec") == 0) require_dnssec = FALSE;
+  else if (Ustrcmp(buffer, "no_require_dnssec") == 0) require_dnssec = FALSE;
   else if (Ustrcmp(buffer, "test_harness") == 0)
     running_in_test_harness = !running_in_test_harness;
   else if (Ustrcmp(buffer, "ipv6") == 0) disable_ipv6 = !disable_ipv6;
@@ -3224,7 +3264,7 @@ while (Ufgets(buffer, 256, stdin) != NULL)
   else
     {
     int flags = whichrrs;
-    dnssec d;
+    dnssec_domains d;
 
     h.name = buffer;
     h.next = NULL;