X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fhost.c;h=f3652c3090e0907d3d6ab9c15ab0fb7913425b9f;hb=a0d6ba8acc09196843fdea4132bb0814b2e81132;hp=0acafd8a83f97c262f9bfefc84bedc9237979a0d;hpb=059ec3d9952740285fb1ebf47961b8aca2eb1b4a;p=exim.git diff --git a/src/src/host.c b/src/src/host.c index 0acafd8a8..f3652c309 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -1,10 +1,10 @@ -/* $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.17 2005/11/11 10:02:04 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 @@ -40,6 +40,9 @@ with these comments: code by Stuart Levy as seen in comp.sys.sgi.admin +August 2005: Apparently this is also needed for AIX systems; USE_INET_NTOA_FIX +should now be set for them as well. + Arguments: sa an in_addr structure Returns: pointer to static text string */ @@ -90,6 +93,235 @@ 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! + +NOTE: +This sorting is not necessary for the new test harness, because it +doesn't call the real DNS resolver, and its output is repeatable. However, +until the old test harness is discarded, we need to retain this capability. +The new harness is being developed towards the end of 2005. It will be some +time before it can do everything that the old one can do. + +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; + } + } + } +} + + + +/************************************************* +* Replace gethostbyname() when testing * +*************************************************/ + +/* This function is called instead of gethostbyname(), gethostbyname2(), or +getipnodebyname() when running in the test harness. It recognizes the name +"manyhome.test.ex" and generates a humungous number of IP addresses. It also +recognizes an unqualified "localhost" and forces it to the appropriate loopback +address. IP addresses are treated as literals. For other names, it uses the DNS +to find the host name. In the new test harness, this means it will access only +the fake DNS resolver. In the old harness it will call the real resolver and +access the test zone. + +Arguments: + name the host name or a textual IP address + af AF_INET or AF_INET6 + error_num where to put an error code: + HOST_NOT_FOUND/TRY_AGAIN/NO_RECOVERY/NO_DATA + +Returns: a hostent structure or NULL for an error +*/ + +static struct hostent * +host_fake_gethostbyname(uschar *name, int af, int *error_num) +{ +#if HAVE_IPV6 +int alen = (af == AF_INET)? sizeof(struct in_addr):sizeof(struct in6_addr); +#else +int alen = sizeof(struct in_addr); +#endif + +int ipa; +uschar *lname = name; +uschar *adds; +uschar **alist; +struct hostent *yield; +dns_answer dnsa; +dns_scan dnss; +dns_record *rr; + +DEBUG(D_host_lookup) + debug_printf("using host_fake_gethostbyname for %s (%s)\n", name, + (af == AF_INET)? "IPv4" : "IPv6"); + +/* Handle the name that needs a vast number of IP addresses */ + +if (Ustrcmp(name, "manyhome.test.ex") == 0 && af == AF_INET) + { + int i, j; + yield = store_get(sizeof(struct hostent)); + alist = store_get(2049 * sizeof(char *)); + adds = store_get(2048 * alen); + yield->h_name = CS name; + yield->h_aliases = NULL; + yield->h_addrtype = af; + yield->h_length = alen; + yield->h_addr_list = CSS alist; + for (i = 104; i <= 111; i++) + { + for (j = 0; j <= 255; j++) + { + *alist++ = adds; + *adds++ = 10; + *adds++ = 250; + *adds++ = i; + *adds++ = j; + } + } + *alist = NULL; + return yield; + } + +/* Handle unqualified "localhost" */ + +if (Ustrcmp(name, "localhost") == 0) + lname = (af == AF_INET)? US"127.0.0.1" : US"::1"; + +/* Handle a literal IP address */ + +ipa = string_is_ip_address(lname, NULL); +if (ipa != 0) + { + if ((ipa == 4 && af == AF_INET) || + (ipa == 6 && af == AF_INET6)) + { + int i, n; + int x[4]; + yield = store_get(sizeof(struct hostent)); + alist = store_get(2 * sizeof(char *)); + adds = store_get(alen); + yield->h_name = CS name; + yield->h_aliases = NULL; + yield->h_addrtype = af; + yield->h_length = alen; + yield->h_addr_list = CSS alist; + *alist++ = adds; + n = host_aton(lname, x); + for (i = 0; i < n; i++) + { + int y = x[i]; + *adds++ = (y >> 24) & 255; + *adds++ = (y >> 16) & 255; + *adds++ = (y >> 8) & 255; + *adds++ = y & 255; + } + *alist = NULL; + } + + /* Wrong kind of literal address */ + + else + { + *error_num = HOST_NOT_FOUND; + return NULL; + } + } + +/* Handle a host name */ + +else + { + int type = (af == AF_INET)? T_A:T_AAAA; + int rc = dns_lookup(&dnsa, lname, type, NULL); + int count = 0; + + switch(rc) + { + case DNS_SUCCEED: break; + case DNS_NOMATCH: *error_num = HOST_NOT_FOUND; return NULL; + case DNS_NODATA: *error_num = NO_DATA; return NULL; + case DNS_AGAIN: *error_num = TRY_AGAIN; return NULL; + default: + case DNS_FAIL: *error_num = NO_RECOVERY; return NULL; + } + + for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + rr != NULL; + rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + { + if (rr->type == type) count++; + } + + yield = store_get(sizeof(struct hostent)); + alist = store_get((count + 1) * sizeof(char **)); + adds = store_get(count *alen); + + yield->h_name = CS name; + yield->h_aliases = NULL; + yield->h_addrtype = af; + yield->h_length = alen; + yield->h_addr_list = CSS alist; + + for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + rr != NULL; + rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + { + int i, n; + int x[4]; + dns_address *da; + if (rr->type != type) continue; + da = dns_address_from_rr(&dnsa, rr); + *alist++ = adds; + n = host_aton(da->address, x); + for (i = 0; i < n; i++) + { + int y = x[i]; + *adds++ = (y >> 24) & 255; + *adds++ = (y >> 16) & 255; + *adds++ = (y >> 8) & 255; + *adds++ = y & 255; + } + } + *alist = NULL; + } + +return yield; +} + + + /************************************************* * Build chain of host items from list * *************************************************/ @@ -192,7 +424,7 @@ Returns: 0 if there is no port, else the port number. If there's a syntax */ int -host_extract_port(uschar *address) +host_address_extract_port(uschar *address) { int port = 0; uschar *endptr; @@ -236,6 +468,59 @@ return port; } +/************************************************* +* Get port from a host item's name * +*************************************************/ + +/* This function is called when finding the IP address for a host that is in a +list of hosts explicitly configured, such as in the manualroute router, or in a +fallback hosts list. We see if there is a port specification at the end of the +host name, and if so, remove it. A minimum length of 3 is required for the +original name; nothing shorter is recognized as having a port. + +We test for a name ending with a sequence of digits; if preceded by colon we +have a port if the character before the colon is ] and the name starts with [ +or if there are no other colons in the name (i.e. it's not an IPv6 address). + +Arguments: pointer to the host item +Returns: a port number or PORT_NONE +*/ + +int +host_item_get_port(host_item *h) +{ +uschar *p; +int port, x; +int len = Ustrlen(h->name); + +if (len < 3 || (p = h->name + len - 1, !isdigit(*p))) return PORT_NONE; + +/* Extract potential port number */ + +port = *p-- - '0'; +x = 10; + +while (p > h->name + 1 && isdigit(*p)) + { + port += (*p-- - '0') * x; + x *= 10; + } + +/* The smallest value of p at this point is h->name + 1. */ + +if (*p != ':') return PORT_NONE; + +if (p[-1] == ']' && h->name[0] == '[') + h->name = string_copyn(h->name + 1, p - h->name - 2); +else if (Ustrchr(h->name, ':') == p) + h->name = string_copyn(h->name, p - h->name); +else return PORT_NONE; + +DEBUG(D_route|D_host_lookup) debug_printf("host=%s port=%d\n", h->name, port); +return port; +} + + #ifndef STAND_ALONE /* Omit when standalone testing */ @@ -250,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 @@ -272,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; @@ -288,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) @@ -303,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); @@ -313,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); @@ -332,24 +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; - if (sender_helo_name == NULL || - strcmpic(sender_host_name, sender_helo_name) == 0 || - (sender_helo_name[0] == '[' && - sender_helo_name[(len=Ustrlen(sender_helo_name))-1] == ']' && - strncmpic(sender_helo_name+1, sender_host_address, len - 2) == 0)) - { - 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 && strcmpic(sender_host_name, sender_helo_name) == 0) + show_helo = FALSE; + + if (show_helo) { sender_fullhost = string_sprintf("%s (%s) %s", sender_host_name, sender_helo_name, address); @@ -359,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; @@ -450,8 +774,8 @@ ip_address_item *next; 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)) + int port = host_address_extract_port(s); /* Leaves just the IP address */ + if (string_is_ip_address(s, NULL) == 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Malformed IP address \"%s\" in %s", s, name); @@ -693,9 +1017,10 @@ host_aton(uschar *address, int *bin) 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) { @@ -712,12 +1037,18 @@ if (Ustrchr(address, ':') != NULL) 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++; @@ -760,7 +1091,7 @@ if (Ustrchr(address, ':') != NULL) /* Handle IPv4 address */ -sscanf(CS address, "%d.%d.%d.%d", x, x+1, x+2, x+3); +(void)sscanf(CS address, "%d.%d.%d.%d", x, x+1, x+2, x+3); bin[v4offset] = (x[0] << 24) + (x[1] << 16) + (x[2] << 8) + x[3]; return v4offset+1; } @@ -814,22 +1145,24 @@ for (i = 0; i < count; i++) /* 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; @@ -848,12 +1181,12 @@ else 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; @@ -1285,9 +1618,11 @@ Returns: OK on success, the answer being placed in the global variable 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 @@ -1304,6 +1639,8 @@ dns_record *rr; 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); @@ -1315,6 +1652,7 @@ if (running_in_test_harness && { HDEBUG(D_host_lookup) debug_printf("Test harness: host name lookup returns DEFER\n"); + host_lookup_deferred = TRUE; return DEFER; } @@ -1404,6 +1742,7 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) { HDEBUG(D_host_lookup) debug_printf("IP address PTR lookup gave temporary error\n"); + host_lookup_deferred = TRUE; return DEFER; } } @@ -1414,9 +1753,12 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) { 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 */ @@ -1430,8 +1772,7 @@ if (sender_host_name == NULL) 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; } @@ -1519,6 +1860,7 @@ for (hname = sender_host_name; hname != NULL; hname = *aliases++) 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 @@ -1563,7 +1905,6 @@ store_pool = POOL_PERM; 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; } @@ -1613,6 +1954,19 @@ int i, yield, times; 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 @@ -1621,8 +1975,6 @@ matches the domain, we also just do IPv4 lookups here (except when testing 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, @@ -1657,16 +2009,27 @@ for (i = 1; i <= times; struct hostent *hostdata; #if HAVE_IPV6 + if (running_in_test_harness) + hostdata = host_fake_gethostbyname(host->name, af, &error_num); + else + { #if HAVE_GETIPNODEBYNAME hostdata = getipnodebyname(CS host->name, af, 0, &error_num); #else hostdata = gethostbyname2(CS host->name, af); error_num = h_errno; #endif - #else - hostdata = gethostbyname(CS host->name); - error_num = h_errno; - #endif + } + + #else /* not HAVE_IPV6 */ + if (running_in_test_harness) + hostdata = host_fake_gethostbyname(host->name, AF_INET, &error_num); + else + { + hostdata = gethostbyname(CS host->name); + error_num = h_errno; + } + #endif /* HAVE_IPV6 */ if (hostdata == NULL) { @@ -1791,31 +2154,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) { @@ -1919,7 +2260,6 @@ 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 && match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN, @@ -2183,8 +2523,10 @@ if ((whichrrs & HOST_FIND_BY_SRV) != 0) if (rc == DNS_FAIL || rc == DNS_AGAIN) { + #ifndef STAND_ALONE if (match_isinlist(host->name, &srv_fail_domains, 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) != OK) + #endif return HOST_FIND_AGAIN; DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA " "(domain in srv_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN"); @@ -2205,8 +2547,10 @@ if (rc != DNS_SUCCEED && (whichrrs & HOST_FIND_BY_MX) != 0) if (rc == DNS_NOMATCH) return HOST_FIND_FAILED; if (rc == DNS_FAIL || rc == DNS_AGAIN) { + #ifndef STAND_ALONE if (match_isinlist(host->name, &mx_fail_domains, 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) != OK) + #endif return HOST_FIND_AGAIN; DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA " "(domain in mx_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN"); @@ -2242,6 +2586,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; @@ -2847,18 +3196,6 @@ return yield; #ifdef STAND_ALONE -BOOL alldigits(uschar *buffer) -{ -if (!isdigit(*buffer)) return FALSE; -if (*buffer == '0' && buffer[1] == 'x') - { - buffer++; - while (isxdigit(*(++buffer))); - } -else while (isdigit(*(++buffer))); -return (*buffer == 0); -} - int main(int argc, char **cargv) { host_item h; @@ -2914,22 +3251,22 @@ while (Ufgets(buffer, 256, stdin) != NULL) else if (Ustrcmp(buffer, "no_qualify_single") == 0) qualify_single = FALSE; else if (Ustrcmp(buffer, "search_parents") == 0) search_parents = TRUE; 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, "res_debug") == 0) + { + _res.options ^= RES_DEBUG; + } else if (Ustrncmp(buffer, "retrans", 7) == 0) { - sscanf(CS(buffer+8), "%d", &dns_retrans); + (void)sscanf(CS(buffer+8), "%d", &dns_retrans); _res.retrans = dns_retrans; } else if (Ustrncmp(buffer, "retry", 5) == 0) { - sscanf(CS(buffer+6), "%d", &dns_retry); + (void)sscanf(CS(buffer+6), "%d", &dns_retry); _res.retry = dns_retry; } - else if (alldigits(buffer)) - { - debug_selector = Ustrtol(buffer, NULL, 0); - _res.options &= ~RES_DEBUG; - DEBUG(D_resolver) _res.options |= RES_DEBUG; - } else { int flags = whichrrs;