summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Hazel <ph10@hermes.cam.ac.uk>2004-11-12 16:54:55 +0000
committerPhilip Hazel <ph10@hermes.cam.ac.uk>2004-11-12 16:54:55 +0000
commitd8ef35773b4c4c25c62a015928ed92b4a654b501 (patch)
tree4afe66bc2d8787bd1909ee0848e8763610f5de90
parentdd3f6d3071e2caad286e15a06364cd27b13ac0ff (diff)
Exim went into a mad DNS lookup loop when doing a callout where the
host was specified on the transport, if the DNS lookup yielded more than one IP address.
-rw-r--r--doc/doc-txt/ChangeLog6
-rw-r--r--src/src/host.c77
-rw-r--r--src/src/verify.c12
3 files changed, 64 insertions, 31 deletions
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index dba38e56f..249ef7cfe 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.27 2004/11/12 15:03:40 ph10 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.28 2004/11/12 16:54:55 ph10 Exp $
Change log file for Exim from version 4.21
-------------------------------------------
@@ -113,6 +113,10 @@ Exim version 4.44
contain a local part and a domain, and therefore, for them, an empty
address still always fails if the pattern is not itself empty.
+30. Exim went into a mad DNS loop when attempting to do a callout where the
+ host was specified on an smtp transport, and looking it up yielded more
+ than one IP address.
+
Exim version 4.43
-----------------
diff --git a/src/src/host.c b/src/src/host.c
index 0acafd8a8..2809e7e07 100644
--- a/src/src/host.c
+++ b/src/src/host.c
@@ -1,4 +1,4 @@
-/* $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.2 2004/11/12 16:54:55 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -91,6 +91,48 @@ return (unsigned int)(random_seed >> 16) % limit;
/*************************************************
+* 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 *
*************************************************/
@@ -1791,31 +1833,9 @@ yield = local_host_check?
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)
{
@@ -1954,7 +1974,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 */
@@ -2242,6 +2262,11 @@ if (rc != DNS_SUCCEED)
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;
diff --git a/src/src/verify.c b/src/src/verify.c
index de7a36642..e8d43eed9 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/verify.c,v 1.4 2004/11/11 11:40:36 ph10 Exp $ */
+/* $Cambridge: exim/src/src/verify.c,v 1.5 2004/11/12 16:54:55 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
@@ -1037,14 +1037,18 @@ while (addr_new != NULL)
else
{
uschar *canonical_name;
- host_item *host;
+ host_item *host, *nexthost;
host_build_hostlist(&host_list, s, tf.hosts_randomize);
/* Just ignore failures to find a host address. If we don't manage
- to find any addresses, the callout will defer. */
+ to find any addresses, the callout will defer. Note that more than
+ one address may be found for a single host, which will result in
+ additional host items being inserted into the chain. Hence we must
+ save the next host first. */
- for (host = host_list; host != NULL; host = host->next)
+ for (host = host_list; host != NULL; host = nexthost)
{
+ nexthost = host->next;
if (tf.gethostbyname || string_is_ip_address(host->name, NULL))
(void)host_find_byname(host, NULL, &canonical_name, TRUE);
else