-/* $Cambridge: exim/src/src/host.c,v 1.2 2004/11/12 16:54:55 ph10 Exp $ */
+/* $Cambridge: exim/src/src/host.c,v 1.8 2005/01/25 14:16:33 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2004 */
+/* Copyright (c) University of Cambridge 1995 - 2005 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or
while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
{
int port = host_extract_port(s); /* Leaves just the IP address */
- if (!string_is_ip_address(s, NULL))
+ if (string_is_ip_address(s, NULL) == 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Malformed IP address \"%s\" in %s",
s, name);
int x[4];
int v4offset = 0;
-/* Handle IPv6 address, which may end with an IPv4 address. This code is NOT
-enclosed in #if HAVE_IPV6 in order that IPv6 addresses are recognized even if
-IPv6 is not supported. */
+/* 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. */
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. */
+ /* 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)
+ while (*p != 0 && *p != '%')
{
- int len = Ustrcspn(p, ":");
+ int len = Ustrcspn(p, ":%");
if (len == 0) nulloffset = ci;
+ if (ci > 7) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+ "Internal error: invalid IPv6 address \"%s\" passed to host_aton()",
+ address);
component[ci++] = p;
p += len;
if (*p == ':') p++;
/* We can't use host_ntoa() because it assumes the binary values are in network
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. However, we can't use the
-normal colon separator in them because it terminates keys in lsearch files, so
-use dot instead.
+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
+to use for IPv6 addresses.
Arguments:
count 1 or 4 (number of ints)
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
Returns: the number of characters placed in buffer, not counting
the final nul.
*/
int
-host_nmtoa(int count, int *binary, int mask, uschar *buffer)
+host_nmtoa(int count, int *binary, int mask, uschar *buffer, int sep)
{
int i, j;
uschar *tt = buffer;
for (i = 0; i < 4; i++)
{
j = binary[i];
- sprintf(CS tt, "%04x.%04x.", (j >> 16) & 0xffff, j & 0xffff);
+ sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep);
while (*tt) tt++;
}
}
-tt--; /* lose final . */
+tt--; /* lose final separator */
if (mask < 0)
*tt = 0;
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. Any
-dynamically constructed string for host_lookup_msg must be in permanent store,
-because it might be used for several incoming messages on the same SMTP
+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
+store, because it might be used for several incoming messages on the same SMTP
connection. */
int
dns_answer dnsa;
dns_scan dnss;
+host_lookup_deferred = host_lookup_failed = FALSE;
+
HDEBUG(D_host_lookup)
debug_printf("looking up host name for %s\n", sender_host_address);
{
HDEBUG(D_host_lookup)
debug_printf("Test harness: host name lookup returns DEFER\n");
+ host_lookup_deferred = TRUE;
return DEFER;
}
{
HDEBUG(D_host_lookup)
debug_printf("IP address PTR lookup gave temporary error\n");
+ host_lookup_deferred = TRUE;
return DEFER;
}
}
{
HDEBUG(D_host_lookup)
debug_printf("IP address lookup using gethostbyaddr()\n");
-
rc = host_name_lookup_byaddr();
- if (rc == DEFER) return rc; /* Can't carry on */
+ if (rc == DEFER)
+ {
+ host_lookup_deferred = TRUE;
+ return rc; /* Can't carry on */
+ }
if (rc == OK) break; /* Found a name */
}
} /* Loop for bydns/byaddr scanning */
log_write(L_host_lookup_failed, LOG_MAIN, "no host name found for IP "
"address %s", sender_host_address);
host_lookup_msg = US" (failed to find host name from IP address)";
-
-host_lookup_failed = TRUE;
+ host_lookup_failed = TRUE;
return FAIL;
}
else if (rc == HOST_FIND_AGAIN)
{
HDEBUG(D_host_lookup) debug_printf("temporary error for host name lookup\n");
+ host_lookup_deferred = TRUE;
return DEFER;
}
else
host_lookup_msg = string_sprintf(" (%s does not match any IP address for %s)",
sender_host_address, save_hostname);
store_pool = old_pool;
-
host_lookup_failed = TRUE;
return FAIL;
}
uschar **addrlist;
host_item *last = NULL;
BOOL temp_error = FALSE;
+#if HAVE_IPV6
+int af;
+#endif
+
+/* If we are in the test harness, a name ending in .test.again.dns always
+forces a temporary error response. */
+
+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
standalone). */
#if HAVE_IPV6
- int af;
-
#ifndef STAND_ALONE
if (dns_ipv4_lookup != NULL &&
match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN,