Update copyright year in (most) files (those that my script finds).
[exim.git] / src / src / host.c
index 1e18940e952e3719fb8d61b1dbe266be4c132002..317d257bbfb56571287a2b3e1fc43726ae0d2f87 100644 (file)
@@ -1,10 +1,10 @@
-/* $Cambridge: exim/src/src/host.c,v 1.16 2005/10/03 09:51:04 ph10 Exp $ */
+/* $Cambridge: exim/src/src/host.c,v 1.20 2006/02/07 11:19:00 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2005 */
+/* Copyright (c) University of Cambridge 1995 - 2006 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or
@@ -535,8 +535,9 @@ as follows:
 
 (a) No sender_host_name or sender_helo_name: "[ip address]"
 (b) Just sender_host_name: "host_name [ip address]"
-(c) Just sender_helo_name: "(helo_name) [ip address]"
-(d) The two are identical: "host_name [ip address]"
+(c) Just sender_helo_name: "(helo_name) [ip address]" unless helo is IP
+            in which case: "[ip address}"
+(d) The two are identical: "host_name [ip address]" includes helo = IP
 (e) The two are different: "host_name (helo_name) [ip address]"
 
 If log_incoming_port is set, the sending host's port number is added to the IP
@@ -557,7 +558,9 @@ Returns:    nothing
 void
 host_build_sender_fullhost(void)
 {
+BOOL show_helo = TRUE;
 uschar *address;
+int len;
 int old_pool = store_pool;
 
 if (sender_host_address == NULL) return;
@@ -573,6 +576,43 @@ address = string_sprintf("[%s]:%d", sender_host_address, sender_host_port);
 if ((log_extra_selector & LX_incoming_port) == 0 || sender_host_port <= 0)
   *(Ustrrchr(address, ':')) = 0;
 
+/* If there's no EHLO/HELO data, we can't show it. */
+
+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
+it happens, the code works for both IPv4 and IPv6. */
+
+else if (sender_helo_name[0] == '[' &&
+         sender_helo_name[(len=Ustrlen(sender_helo_name))-1] == ']')
+  {
+  int offset = 1;
+  uschar *helo_ip;
+
+  if (strncmpic(sender_helo_name + 1, US"IPv6:", 5) == 0) offset += 5;
+  if (strncmpic(sender_helo_name + 1, US"IPv4:", 5) == 0) offset += 5;
+
+  helo_ip = string_copyn(sender_helo_name + offset, len - offset - 1);
+
+  if (string_is_ip_address(helo_ip, NULL) != 0)
+    {
+    int x[4], y[4];
+    int sizex, sizey;
+    uschar ipx[48], ipy[48];    /* large enough for full IPv6 */
+
+    sizex = host_aton(helo_ip, x);
+    sizey = host_aton(sender_host_address, y);
+
+    (void)host_nmtoa(sizex, x, -1, ipx, ':');
+    (void)host_nmtoa(sizey, y, -1, ipy, ':');
+
+    if (strcmpic(ipx, ipy) == 0) show_helo = FALSE;
+    }
+  }
+
 /* Host name is not verified */
 
 if (sender_host_name == NULL)
@@ -588,7 +628,7 @@ if (sender_host_name == NULL)
 
   sender_rcvhost = string_cat(NULL, &size, &ptr, address, adlen);
 
-  if (sender_ident != NULL || sender_helo_name != NULL || portptr != NULL)
+  if (sender_ident != NULL || show_helo || portptr != NULL)
     {
     int firstptr;
     sender_rcvhost = string_cat(sender_rcvhost, &size, &ptr, US" (", 2);
@@ -598,7 +638,7 @@ if (sender_host_name == NULL)
       sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2, US"port=",
         portptr + 1);
 
-    if (sender_helo_name != NULL)
+    if (show_helo)
       sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2,
         (firstptr == ptr)? US"helo=" : US" helo=", sender_helo_name);
 
@@ -617,54 +657,15 @@ if (sender_host_name == NULL)
   store_reset(sender_rcvhost + ptr + 1);
   }
 
-/* Host name is known and verified. */
+/* Host name is known and verified. Unless we've already found that the HELO
+data matches the IP address, compare it with the name. */
 
 else
   {
-  int len;
-  BOOL no_helo = FALSE;
-
-  /* Comparing a HELO name to a host name is easy */
-
-  if (sender_helo_name == NULL ||
-      strcmpic(sender_host_name, sender_helo_name) == 0)
-    no_helo = TRUE;
-
-  /* If HELO/EHLO was followed by an IP literal, it's much more 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, an IPv6 address
-  may not be given in canonical form, so we have to canonicize it before
-  comparing. As it happens, the code works for both IPv4 and IPv6. */
-
-  else if (sender_helo_name[0] == '[' &&
-           sender_helo_name[(len=Ustrlen(sender_helo_name))-1] == ']')
-    {
-    uschar *helo_ip;
-    int offset = 1;
-
-    if (strncmpic(sender_helo_name+1, US"IPv6:",5) == 0) offset += 5;
-    helo_ip = string_copyn(sender_helo_name + offset, len - offset - 1);
-
-    if (string_is_ip_address(helo_ip, NULL) != 0)
-      {
-      int x[4];
-      int size;
-      size = host_aton(helo_ip, x);
-      helo_ip = store_get(48);  /* large enough for full IPv6 */
-      (void)host_nmtoa(size, x, -1, helo_ip, ':');
-      if (strcmpic(helo_ip, sender_host_address) == 0) no_helo = TRUE;
-      }
-    }
+  if (show_helo && strcmpic(sender_host_name, sender_helo_name) == 0)
+    show_helo = FALSE;
 
-  if (no_helo)
-    {
-    sender_fullhost = string_sprintf("%s %s", sender_host_name, address);
-    sender_rcvhost = (sender_ident == NULL)?
-      string_sprintf("%s (%s)", sender_host_name, address) :
-      string_sprintf("%s (%s ident=%s)", sender_host_name, address,
-        sender_ident);
-    }
-  else
+  if (show_helo)
     {
     sender_fullhost = string_sprintf("%s (%s) %s", sender_host_name,
       sender_helo_name, address);
@@ -674,6 +675,14 @@ else
       string_sprintf("%s\n\t(%s helo=%s ident=%s)", sender_host_name,
         address, sender_helo_name, sender_ident);
     }
+  else
+    {
+    sender_fullhost = string_sprintf("%s %s", sender_host_name, address);
+    sender_rcvhost = (sender_ident == NULL)?
+      string_sprintf("%s (%s)", sender_host_name, address) :
+      string_sprintf("%s (%s ident=%s)", sender_host_name, address,
+        sender_ident);
+    }
   }
 
 store_pool = old_pool;
@@ -765,11 +774,16 @@ ip_address_item *next;
 
 while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
   {
+  int ipv;
   int port = host_address_extract_port(s);            /* Leaves just the IP address */
-  if (string_is_ip_address(s, NULL) == 0)
+  if ((ipv = string_is_ip_address(s, NULL)) == 0)
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Malformed IP address \"%s\" in %s",
       s, name);
 
+  /* Skip IPv6 addresses if IPv6 is disabled. */
+
+  if (disable_ipv6 && ipv == 6) continue;
+
   /* This use of strcpy() is OK because we have checked that s is a valid IP
   address above. The field in the ip_address_item is large enough to hold an
   IPv6 address. */
@@ -1827,13 +1841,10 @@ for (hname = sender_host_name; hname != NULL; hname = *aliases++)
   if ((rc = host_find_byname(&h, NULL, NULL, FALSE)) == HOST_FOUND)
     {
     host_item *hh;
-    uschar *address_ipv4 = (Ustrncmp(sender_host_address, "::ffff:", 7) == 0)?
-      sender_host_address + 7 : sender_host_address;
     HDEBUG(D_host_lookup) debug_printf("checking addresses for %s\n", hname);
     for (hh = &h; hh != NULL; hh = hh->next)
       {
-      if ((Ustrcmp(hh->address, (Ustrchr(hh->address, ':') == NULL)?
-          address_ipv4 : sender_host_address)) == 0)
+      if (host_is_in_net(hh->address, sender_host_address, 0))
         {
         HDEBUG(D_host_lookup) debug_printf("  %s OK\n", hh->address);
         ok = TRUE;
@@ -1959,17 +1970,17 @@ if (running_in_test_harness)
     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
-world, which makes for slightly tidier code. However, if dns_ipv4_lookup
-matches the domain, we also just do IPv4 lookups here (except when testing
-standalone). */
+/* In an IPv6 world, unless IPv6 has been disabled, 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 world, which makes for slightly tidier
+code. However, if dns_ipv4_lookup matches the domain, we also just do IPv4
+lookups here (except when testing standalone). */
 
 #if HAVE_IPV6
   #ifndef STAND_ALONE
-  if (dns_ipv4_lookup != NULL &&
+  if (disable_ipv6 || (dns_ipv4_lookup != NULL &&
         match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN,
-          TRUE, NULL) == OK)
+          TRUE, NULL) == OK))
     { af = AF_INET; times = 1; }
   else
   #endif  /* STAND_ALONE */
@@ -2243,18 +2254,18 @@ if (allow_ip && string_is_ip_address(host->name, NULL) != 0)
   return HOST_FOUND;
   }
 
-/* On an IPv6 system, go round the loop up to three times, looking for A6 and
-AAAA records the first two times. 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 loop once only, looking only for A
-records. */
+/* 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
+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
+loop once only, looking only for A records. */
 
 #if HAVE_IPV6
   #ifndef STAND_ALONE
-    if (dns_ipv4_lookup != NULL &&
+    if (disable_ipv6 || (dns_ipv4_lookup != NULL &&
         match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN,
-        TRUE, NULL) == OK)
+        TRUE, NULL) == OK))
       i = 0;    /* look up A records only */
     else
   #endif        /* STAND_ALONE */
@@ -2887,10 +2898,14 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ADDITIONAL);
 
   if (rr->type != T_A
   #if HAVE_IPV6
-    && rr->type != T_AAAA
-    #ifdef SUPPORT_A6
-    && rr->type != T_A6
-    #endif
+    && ( disable_ipv6 ||
+         (
+         rr->type != T_AAAA
+         #ifdef SUPPORT_A6
+         && rr->type != T_A6
+         #endif
+         )
+       )
   #endif
     ) continue;