-/* $Cambridge: exim/src/src/host.c,v 1.22 2006/02/16 10:05:33 ph10 Exp $ */
+/* $Cambridge: exim/src/src/host.c,v 1.28 2007/01/08 10:50:18 ph10 Exp $ */
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2006 */
+/* Copyright (c) University of Cambridge 1995 - 2007 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or
h.mx = MX_NONE;
h.address = NULL;
- /* When called with the 5th argument FALSE, host_find_byname() won't return
+ /* When called with the last argument FALSE, host_find_byname() won't return
HOST_FOUND_LOCAL. If the incoming address is an IPv4 address expressed in
IPv6 format, we must compare the IPv4 part to any IPv4 addresses. */
- if ((rc = host_find_byname(&h, NULL, NULL, FALSE)) == HOST_FOUND)
+ if ((rc = host_find_byname(&h, NULL, 0, NULL, FALSE)) == HOST_FOUND)
{
host_item *hh;
HDEBUG(D_host_lookup) debug_printf("checking addresses for %s\n", hname);
{
HDEBUG(D_host_lookup) debug_printf("temporary error for host name lookup\n");
host_lookup_deferred = TRUE;
+ sender_host_name = NULL;
return DEFER;
}
else
*************************************************/
/* The input is a host_item structure with the name filled in and the address
-field set to NULL. We use gethostbyname(). Of course, gethostbyname() may use
-the DNS, but it doesn't do MX processing. If more than one address is given,
-chain on additional host items, with other relevant fields copied.
+field set to NULL. We use gethostbyname() or getipnodebyname() or
+gethostbyname2(), as appropriate. Of course, these functions may use the DNS,
+but they do not do MX processing. It appears, however, that in some systems the
+current setting of resolver options is used when one of these functions calls
+the resolver. For this reason, we call dns_init() at the start, with arguments
+influenced by bits in "flags", just as we do for host_find_bydns().
The second argument provides a host list (usually an IP list) of hosts to
ignore. This makes it possible to ignore IPv6 link-local addresses or loopback
multiple IP addresses cause other host items to be
chained on.
ignore_target_hosts a list of hosts to ignore
+ flags HOST_FIND_QUALIFY_SINGLE ) passed to
+ HOST_FIND_SEARCH_PARENTS ) dns_init()
fully_qualified_name if not NULL, set to point to host name for
compatibility with host_find_bydns
local_host_check TRUE if a check for the local host is wanted
*/
int
-host_find_byname(host_item *host, uschar *ignore_target_hosts,
+host_find_byname(host_item *host, uschar *ignore_target_hosts, int flags,
uschar **fully_qualified_name, BOOL local_host_check)
{
int i, yield, times;
#endif
/* If we are in the test harness, a name ending in .test.again.dns always
-forces a temporary error response. */
+forces a temporary error response, unless the name is in
+dns_again_means_nonexist. */
if (running_in_test_harness)
{
uschar *endname = host->name + Ustrlen(host->name);
- if (Ustrcmp(endname - 14, "test.again.dns") == 0)
- return HOST_FIND_AGAIN;
+ if (Ustrcmp(endname - 14, "test.again.dns") == 0) goto RETURN_AGAIN;
}
+/* Make sure DNS options are set as required. This appears to be necessary in
+some circumstances when the get..byname() function actually calls the DNS. */
+
+dns_init((flags & HOST_FIND_QUALIFY_SINGLE) != 0,
+ (flags & HOST_FIND_SEARCH_PARENTS) != 0);
+
/* 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
lookups here (except when testing standalone). */
#if HAVE_IPV6
- #ifndef STAND_ALONE
- if (disable_ipv6 || (dns_ipv4_lookup != NULL &&
+ #ifdef STAND_ALONE
+ if (disable_ipv6)
+ #else
+ if (disable_ipv6 ||
+ (dns_ipv4_lookup != NULL &&
match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN,
TRUE, NULL) == OK))
+ #endif
+
{ af = AF_INET; times = 1; }
else
- #endif /* STAND_ALONE */
-
{ af = AF_INET6; times = 2; }
/* No IPv6 support */
i++)
{
BOOL ipv4_addr;
- int error_num;
+ int error_num = 0;
struct hostent *hostdata;
+ #ifdef STAND_ALONE
+ printf("Looking up: %s\n", host->name);
+ #endif
+
#if HAVE_IPV6
if (running_in_test_harness)
hostdata = host_fake_gethostbyname(host->name, af, &error_num);
string_sprintf("no IP address found for host %s", host->name);
HDEBUG(D_host_lookup) debug_printf("%s\n", msg);
- if (temp_error) return HOST_FIND_AGAIN;
+ if (temp_error) goto RETURN_AGAIN;
if (host_checking || !log_testing_mode)
log_write(L_host_lookup_failed, LOG_MAIN, "%s", msg);
return HOST_FIND_FAILED;
/* Return the found status. */
return yield;
+
+/* Handle the case when there is a temporary error. If the name matches
+dns_again_means_nonexist, return permanent rather than temporary failure. */
+
+RETURN_AGAIN:
+ {
+ #ifndef STAND_ALONE
+ int rc;
+ uschar *save = deliver_domain;
+ deliver_domain = host->name; /* set $domain */
+ rc = match_isinlist(host->name, &dns_again_means_nonexist, 0, NULL, NULL,
+ MCL_DOMAIN, TRUE, NULL);
+ deliver_domain = save;
+ if (rc == OK)
+ {
+ DEBUG(D_host_lookup) debug_printf("%s is in dns_again_means_nonexist: "
+ "returning HOST_FIND_FAILED\n", host->name);
+ return HOST_FIND_FAILED;
+ }
+ #endif
+ return HOST_FIND_AGAIN;
+ }
}
addresses of a multihomed host, but that should not matter. */
#if HAVE_IPV6
-if (h != last)
+if (h != last && !disable_ipv6)
{
for (h = host; h != last; h = h->next)
{
host_item temp;
host_item *next = h->next;
- if (h->mx != next->mx || /* If next is different MX value */
- (h->sort_key % 1000) < 500 || /* OR this one is IPv6 */
- (next->sort_key % 1000) >= 500) /* OR next is IPv4 */
- continue; /* move on to next */
- temp = *h;
+ if (h->mx != next->mx || /* If next is different MX */
+ h->address == NULL || /* OR this one is unset */
+ Ustrchr(h->address, ':') != NULL || /* OR this one is IPv6 */
+ (next->address != NULL &&
+ Ustrchr(next->address, ':') == NULL)) /* OR next is IPv4 */
+ continue; /* move on to next */
+ temp = *h; /* otherwise, swap */
temp.next = next->next;
*h = *next;
h->next = next;
uschar **argv = USS cargv;
uschar buffer[256];
+disable_ipv6 = FALSE;
primary_hostname = US"";
store_pool = POOL_MAIN;
debug_selector = D_host_lookup|D_interface;
else if (Ustrcmp(buffer, "no_search_parents") == 0) search_parents = FALSE;
else if (Ustrcmp(buffer, "test_harness") == 0)
running_in_test_harness = !running_in_test_harness;
+ else if (Ustrcmp(buffer, "ipv6") == 0) disable_ipv6 = !disable_ipv6;
else if (Ustrcmp(buffer, "res_debug") == 0)
{
_res.options ^= RES_DEBUG;
if (search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
rc = byname?
- host_find_byname(&h, NULL, &fully_qualified_name, TRUE)
+ host_find_byname(&h, NULL, flags, &fully_qualified_name, TRUE)
:
host_find_bydns(&h, NULL, flags, US"smtp", NULL, NULL,
&fully_qualified_name, NULL);