Allow port setting on lists of hosts in manualroute, queryprogram,
[exim.git] / src / src / host.c
index 8cc239b0fe19771027a40e8cb3c6652b5187db1e..9f3a068707fa758953e95829d54daecf04b8c335 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/host.c,v 1.8 2005/01/25 14:16:33 ph10 Exp $ */
+/* $Cambridge: exim/src/src/host.c,v 1.12 2005/08/09 13:31:52 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -40,6 +40,9 @@ with these comments:
   code by Stuart Levy
   as seen in comp.sys.sgi.admin
 
+August 2005: Apparently this is also needed for AIX systems; USE_INET_NTOA_FIX
+should now be set for them as well.
+
 Arguments:  sa  an in_addr structure
 Returns:        pointer to static text string
 */
@@ -102,9 +105,9 @@ and IPv6 addresses!
 Arguments:
   host        -> the first host item
   last        -> the last host item
-  
+
 Returns:      nothing
-*/  
+*/
 
 static void
 sort_addresses(host_item *host, host_item *last)
@@ -234,7 +237,7 @@ Returns:     0 if there is no port, else the port number. If there's a syntax
 */
 
 int
-host_extract_port(uschar *address)
+host_address_extract_port(uschar *address)
 {
 int port = 0;
 uschar *endptr;
@@ -278,6 +281,59 @@ return port;
 }
 
 
+/*************************************************
+*         Get port from a host item's name       *
+*************************************************/
+
+/* This function is called when finding the IP address for a host that is in a
+list of hosts explicitly configured, such as in the manualroute router, or in a
+fallback hosts list. We see if there is a port specification at the end of the
+host name, and if so, remove it. A minimum length of 3 is required for the
+original name; nothing shorter is recognized as having a port.
+
+We test for a name ending with a sequence of digits; if preceded by colon we
+have a port if the character before the colon is ] and the name starts with [
+or if there are no other colons in the name (i.e. it's not an IPv6 address).
+
+Arguments:  pointer to the host item
+Returns:    a port number or PORT_NONE
+*/
+
+int
+host_item_get_port(host_item *h)
+{
+uschar *p;
+int port, x;
+int len = Ustrlen(h->name);
+
+if (len < 3 || (p = h->name + len - 1, !isdigit(*p))) return PORT_NONE;
+
+/* Extract potential port number */
+
+port = *p-- - '0';
+x = 10;
+
+while (p > h->name + 1 && isdigit(*p))
+  {
+  port += (*p-- - '0') * x;
+  x *= 10;
+  }
+
+/* The smallest value of p at this point is h->name + 1. */
+
+if (*p != ':') return PORT_NONE;
+
+if (p[-1] == ']' && h->name[0] == '[')
+  h->name = string_copyn(h->name + 1, p - h->name - 2);
+else if (Ustrchr(h->name, ':') == p)
+  h->name = string_copyn(h->name, p - h->name);
+else return PORT_NONE;
+
+DEBUG(D_route|D_host_lookup) debug_printf("host=%s port=%d\n", h->name, port);
+return port;
+}
+
+
 
 #ifndef STAND_ALONE    /* Omit when standalone testing */
 
@@ -492,7 +548,7 @@ ip_address_item *next;
 
 while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
   {
-  int port = host_extract_port(s);            /* Leaves just the IP address */
+  int port = host_address_extract_port(s);            /* Leaves just the IP address */
   if (string_is_ip_address(s, NULL) == 0)
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Malformed IP address \"%s\" in %s",
       s, name);
@@ -735,7 +791,7 @@ host_aton(uschar *address, int *bin)
 int x[4];
 int v4offset = 0;
 
-/* Handle IPv6 address, which may end with an IPv4 address. It may also end 
+/* Handle IPv6 address, which may end with an IPv4 address. It may also end
 with a "scope", introduced by a percent sign. This code is NOT enclosed in #if
 HAVE_IPV6 in order that IPv6 addresses are recognized even if IPv6 is not
 supported. */
@@ -752,21 +808,21 @@ if (Ustrchr(address, ':') != NULL)
 
   /* If the address starts with a colon, it will start with two colons.
   Just lose the first one, which will leave a null first component. */
-  
+
   if (*p == ':') p++;
 
-  /* Split the address into components separated by colons. The input address 
-  is supposed to be checked for syntax. There was a case where this was 
-  overlooked; to guard against that happening again, check here and crash if 
+  /* Split the address into components separated by colons. The input address
+  is supposed to be checked for syntax. There was a case where this was
+  overlooked; to guard against that happening again, check here and crash if
   there are too many components. */
 
   while (*p != 0 && *p != '%')
     {
     int len = Ustrcspn(p, ":%");
     if (len == 0) nulloffset = ci;
-    if (ci > 7) log_write(0, LOG_MAIN|LOG_PANIC_DIE, 
+    if (ci > 7) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
       "Internal error: invalid IPv6 address \"%s\" passed to host_aton()",
-      address);  
+      address);
     component[ci++] = p;
     p += len;
     if (*p == ':') p++;
@@ -809,7 +865,7 @@ if (Ustrchr(address, ':') != NULL)
 
 /* Handle IPv4 address */
 
-sscanf(CS address, "%d.%d.%d.%d", x, x+1, x+2, x+3);
+(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];
 return v4offset+1;
 }
@@ -865,7 +921,7 @@ byte order, and these are the result of host_aton(), which puts them in ints in
 host byte order. Also, we really want IPv6 addresses to be in a canonical
 format, so we output them with no abbreviation. In a number of cases we can't
 use the normal colon separator in them because it terminates keys in lsearch
-files, so we want to use dot instead. There's an argument that specifies what 
+files, so we want to use dot instead. There's an argument that specifies what
 to use for IPv6 addresses.
 
 Arguments:
@@ -873,7 +929,7 @@ Arguments:
   binary      points to the ints
   mask        mask value; if < 0 don't add to result
   buffer      big enough to hold the result
-  sep         component separator character for IPv6 addresses 
+  sep         component separator character for IPv6 addresses
 
 Returns:      the number of characters placed in buffer, not counting
               the final nul.
@@ -1336,7 +1392,7 @@ Returns:      OK on success, the answer being placed in the global variable
 
 The variable host_lookup_msg is set to an empty string on sucess, 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 
+message, and also host_lookup_failed is set TRUE if the lookup failed. If there
 was a defer, host_lookup_deferred is set TRUE.
 
 Any dynamically constructed string for host_lookup_msg must be in permanent
@@ -1370,7 +1426,7 @@ if (running_in_test_harness &&
   {
   HDEBUG(D_host_lookup)
     debug_printf("Test harness: host name lookup returns DEFER\n");
-  host_lookup_deferred = TRUE;   
+  host_lookup_deferred = TRUE;
   return DEFER;
   }
 
@@ -1460,7 +1516,7 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))
       {
       HDEBUG(D_host_lookup)
         debug_printf("IP address PTR lookup gave temporary error\n");
-      host_lookup_deferred = TRUE;   
+      host_lookup_deferred = TRUE;
       return DEFER;
       }
     }
@@ -1472,11 +1528,11 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))
     HDEBUG(D_host_lookup)
       debug_printf("IP address lookup using gethostbyaddr()\n");
     rc = host_name_lookup_byaddr();
-    if (rc == DEFER) 
+    if (rc == DEFER)
       {
-      host_lookup_deferred = TRUE;   
+      host_lookup_deferred = TRUE;
       return rc;                       /* Can't carry on */
-      } 
+      }
     if (rc == OK) break;               /* Found a name */
     }
   }      /* Loop for bydns/byaddr scanning */
@@ -1578,7 +1634,7 @@ for (hname = sender_host_name; hname != NULL; hname = *aliases++)
   else if (rc == HOST_FIND_AGAIN)
     {
     HDEBUG(D_host_lookup) debug_printf("temporary error for host name lookup\n");
-    host_lookup_deferred = TRUE;   
+    host_lookup_deferred = TRUE;
     return DEFER;
     }
   else
@@ -1684,7 +1740,7 @@ if (running_in_test_harness)
   uschar *endname = host->name + Ustrlen(host->name);
   if (Ustrcmp(endname - 14, "test.again.dns") == 0)
     return HOST_FIND_AGAIN;
-  }   
+  }
 
 /* In an IPv6 world, we need to scan for both kinds of address, so go round the
 loop twice. Note that we have ensured that AF_INET6 is defined even in an IPv4
@@ -2002,7 +2058,7 @@ for (; i >= 0; i--)
   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.) */
-  
+
   if (rc != DNS_SUCCEED)
     {
     if (i == 0)  /* Just tried for an A record, i.e. end of loop */
@@ -2292,7 +2348,7 @@ if (rc != DNS_SUCCEED)
 
   /* When running in the test harness, sort into the order of addresses so as
   to get repeatability. */
-  
+
   if (running_in_test_harness) sort_addresses(host, last);
 
   DEBUG(D_host_lookup)
@@ -2969,12 +3025,12 @@ while (Ufgets(buffer, 256, stdin) != NULL)
   else if (Ustrcmp(buffer, "no_search_parents") == 0) search_parents = FALSE;
   else if (Ustrncmp(buffer, "retrans", 7) == 0)
     {
-    sscanf(CS(buffer+8), "%d", &dns_retrans);
+    (void)sscanf(CS(buffer+8), "%d", &dns_retrans);
     _res.retrans = dns_retrans;
     }
   else if (Ustrncmp(buffer, "retry", 5) == 0)
     {
-    sscanf(CS(buffer+6), "%d", &dns_retry);
+    (void)sscanf(CS(buffer+6), "%d", &dns_retry);
     _res.retry = dns_retry;
     }
   else if (alldigits(buffer))