-/* $Cambridge: exim/src/src/host.c,v 1.1 2004/10/07 10:39:01 ph10 Exp $ */
+/* $Cambridge: exim/src/src/host.c,v 1.6 2005/01/11 15:51:02 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
+/*************************************************
+* Sort addresses when testing *
+*************************************************/
+
+/* This function is called only when running in the test harness. It sorts a
+number of multihomed host IP addresses into the order, so as to get
+repeatability. This doesn't have to be efficient. But don't interchange IPv4
+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)
+{
+BOOL done = FALSE;
+while (!done)
+ {
+ host_item *h;
+ done = TRUE;
+ for (h = host; h != last; h = h->next)
+ {
+ if ((Ustrchr(h->address, ':') == NULL) !=
+ (Ustrchr(h->next->address, ':') == NULL))
+ continue;
+ if (Ustrcmp(h->address, h->next->address) > 0)
+ {
+ uschar *temp = h->address;
+ h->address = h->next->address;
+ h->next->address = temp;
+ done = FALSE;
+ }
+ }
+ }
+}
+
+
+
/*************************************************
* Build chain of host items from list *
*************************************************/
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);
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 is a violation. */
while (*p != 0)
{
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;
host_scan_for_local_hosts(host, &last, NULL) : HOST_FOUND;
/* When running in the test harness, sort into the order of addresses so as to
-get repeatability. This doesn't have to be efficient. But don't interchange
-IPv4 and IPv6 addresses! */
+get repeatability. */
-if (running_in_test_harness)
- {
- BOOL done = FALSE;
- while (!done)
- {
- host_item *h;
- done = TRUE;
- for (h = host; h != last; h = h->next)
- {
- if ((Ustrchr(h->address, ':') == NULL) !=
- (Ustrchr(h->next->address, ':') == NULL))
- continue;
- if (Ustrcmp(h->address, h->next->address) > 0)
- {
- uschar *temp = h->address;
- h->address = h->next->address;
- h->next->address = temp;
- done = FALSE;
- }
- }
- }
- }
+if (running_in_test_harness) sort_addresses(host, last);
HDEBUG(D_host_lookup)
{
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 */
else
if (rc == HOST_IGNORED) rc = HOST_FIND_FAILED; /* No special action */
+ /* 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)
{
host_item *h;