X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fhost.c;h=00524f41631db22ebf98bde88f75fe37dab4ab56;hb=071c51f70266916a7be153ce67c0045beb58b841;hp=87cd7c494cf08f0c11d9382954cb606d1f2db684;hpb=1349e1e5bcfa5fb3db8aa2f02825b7e70bf47cdb;p=exim.git diff --git a/src/src/host.c b/src/src/host.c index 87cd7c494..00524f416 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -1,10 +1,8 @@ -/* $Cambridge: exim/src/src/host.c,v 1.21 2006/02/07 16:36:25 ph10 Exp $ */ - /************************************************* * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2006 */ +/* Copyright (c) University of Cambridge 1995 - 2012 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or @@ -70,6 +68,9 @@ sprintf(addr, "%d.%d.%d.%d", very good for the uses to which it is put. When running the regression tests, start with a fixed seed. +If you need better, see vaguely_random_number() which is potentially stronger, +if a crypto library is available, but might end up just calling this instead. + Arguments: limit: one more than the largest number required @@ -79,6 +80,8 @@ Returns: a pseudo-random number in the range 0 to limit-1 int random_number(int limit) { +if (limit < 1) + return 0; if (random_seed == 0) { if (running_in_test_harness) random_seed = 42; else @@ -93,55 +96,6 @@ 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 * *************************************************/ @@ -151,9 +105,8 @@ 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. +to find the host name. In the test harness, this means it will access only the +fake DNS resolver. Arguments: name the host name or a textual IP address @@ -267,6 +220,8 @@ else int rc = dns_lookup(&dnsa, lname, type, NULL); int count = 0; + lookup_dnssec_authenticated = NULL; + switch(rc) { case DNS_SUCCEED: break; @@ -1224,19 +1179,15 @@ host_is_tls_on_connect_port(int port) { int sep = 0; uschar buffer[32]; -uschar *list = tls_on_connect_ports; +uschar *list = tls_in.on_connect_ports; uschar *s; +uschar *end; -if (tls_on_connect) return TRUE; +if (tls_in.on_connect) return TRUE; -while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) - { - uschar *end; - int lport = Ustrtol(s, &end, 10); - if (*end != 0) log_write(0, LOG_MAIN|LOG_PANIC_DIE, "tls_on_connect_ports " - "contains \"%s\", which is not a port number: exim abandoned", s); - if (lport == port) return TRUE; - } +while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) + if (Ustrtol(s, &end, 10) == port) + return TRUE; return FALSE; } @@ -1552,7 +1503,7 @@ if (hosts == NULL) treat this as non-existent. In some operating systems, this is returned as an empty string; in others as a single dot. */ -if (hosts->h_name[0] == 0 || hosts->h_name[0] == '.') +if (hosts->h_name == NULL || hosts->h_name[0] == 0 || hosts->h_name[0] == '.') { HDEBUG(D_host_lookup) debug_printf("IP address lookup yielded an empty name: " "treated as non-existent host name\n"); @@ -1644,7 +1595,7 @@ dns_record *rr; dns_answer dnsa; dns_scan dnss; -host_lookup_deferred = host_lookup_failed = FALSE; +sender_host_dnssec = host_lookup_deferred = host_lookup_failed = FALSE; HDEBUG(D_host_lookup) debug_printf("looking up host name for %s\n", sender_host_address); @@ -1669,7 +1620,7 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) { if (strcmpic(ordername, US"bydns") == 0) { - dns_init(FALSE, FALSE); + dns_init(FALSE, FALSE, FALSE); /* dnssec ctrl by dns_dnssec_ok glbl */ dns_build_reverse(sender_host_address, buffer); rc = dns_lookup(&dnsa, buffer, T_PTR, NULL); @@ -1686,6 +1637,13 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) int count = 0; int old_pool = store_pool; + /* Ideally we'd check DNSSEC both forward and reverse, but we use the + gethost* routines for forward, so can't do that unless/until we rewrite. */ + sender_host_dnssec = dns_is_secure(&dnsa); + DEBUG(D_dns) + debug_printf("Reverse DNS security status: %s\n", + sender_host_dnssec ? "DNSSEC verified (AD)" : "unverified"); + store_pool = POOL_PERM; /* Save names in permanent storage */ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); @@ -1781,27 +1739,6 @@ if (sender_host_name == NULL) return FAIL; } -/* We have a host name. If we are running in the test harness, we want the host -name and its alias to appear always the same way round. There are only ever two -names in these tests. If one of them contains "alias", make sure it is second; -otherwise put them in alphabetical order. */ - -if (running_in_test_harness && *sender_host_aliases != NULL && - ( - Ustrstr(sender_host_name, "alias") != NULL || - ( - Ustrstr(*sender_host_aliases, "alias") == NULL && - Ustrcmp(sender_host_name, *sender_host_aliases) > 0 - ) - )) - { - uschar *temp = sender_host_name; - sender_host_name = *sender_host_aliases; - *sender_host_aliases = temp; - } - -/* Debug output what was found, after test harness swapping, for consistency */ - HDEBUG(D_host_lookup) { uschar **aliases = sender_host_aliases; @@ -1834,11 +1771,11 @@ for (hname = sender_host_name; hname != NULL; hname = *aliases++) 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); @@ -1863,6 +1800,7 @@ for (hname = sender_host_name; hname != NULL; hname = *aliases++) { HDEBUG(D_host_lookup) debug_printf("temporary error for host name lookup\n"); host_lookup_deferred = TRUE; + sender_host_name = NULL; return DEFER; } else @@ -1919,9 +1857,12 @@ return FAIL; *************************************************/ /* 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 @@ -1938,6 +1879,8 @@ Arguments: 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 @@ -1949,7 +1892,7 @@ Returns: HOST_FIND_FAILED Failed to find the host or domain */ 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; @@ -1961,15 +1904,22 @@ int af; #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, + FALSE); /*XXX dnssec? */ + /* 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 @@ -1977,14 +1927,17 @@ code. However, if dns_ipv4_lookup matches the domain, we also just do IPv4 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 */ @@ -2007,9 +1960,13 @@ for (i = 1; i <= times; 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); @@ -2104,6 +2061,7 @@ for (i = 1; i <= times; host->port = PORT_NONE; host->status = hstatus_unknown; host->why = hwhy_unknown; + host->dnssec = DS_UNK; last = host; } @@ -2119,6 +2077,7 @@ for (i = 1; i <= times; next->port = PORT_NONE; next->status = hstatus_unknown; next->why = hwhy_unknown; + next->dnssec = DS_UNK; next->last_try = 0; next->next = last->next; last->next = next; @@ -2142,7 +2101,7 @@ if (host->address == NULL) 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; @@ -2155,11 +2114,6 @@ host_remove_duplicates(host, &last); 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. */ - -if (running_in_test_harness) sort_addresses(host, last); - HDEBUG(D_host_lookup) { host_item *h; @@ -2184,6 +2138,28 @@ HDEBUG(D_host_lookup) /* 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; + } } @@ -2220,6 +2196,7 @@ Arguments: fully_qualified_name if not NULL, return fully qualified name here if the contents are different (i.e. it must be preset to something) + dnnssec_require if TRUE check the DNS result AD bit Returns: HOST_FIND_FAILED couldn't find A record HOST_FIND_AGAIN try again later @@ -2229,7 +2206,8 @@ Returns: HOST_FIND_FAILED couldn't find A record static int set_address_from_dns(host_item *host, host_item **lastptr, - uschar *ignore_target_hosts, BOOL allow_ip, uschar **fully_qualified_name) + uschar *ignore_target_hosts, BOOL allow_ip, uschar **fully_qualified_name, + BOOL dnssec_requested, BOOL dnssec_require) { dns_record *rr; host_item *thishostlast = NULL; /* Indicates not yet filled in anything */ @@ -2290,6 +2268,8 @@ for (; i >= 0; i--) dns_scan dnss; int rc = dns_lookup(&dnsa, host->name, type, fully_qualified_name); + lookup_dnssec_authenticated = !dnssec_requested ? NULL + : dns_is_secure(&dnsa) ? US"yes" : US"no"; /* We want to return HOST_FIND_AGAIN if one of the A, A6, or AAAA lookups fails or times out, but not if another one succeeds. (In the early @@ -2312,6 +2292,12 @@ for (; i >= 0; i--) if (rc != DNS_NOMATCH && rc != DNS_NODATA) v6_find_again = TRUE; continue; } + if (dnssec_require && !dns_is_secure(&dnsa)) + { + log_write(L_host_lookup_failed, LOG_MAIN, "dnssec fail on %s for %.256s", + i>1 ? "A6" : i>0 ? "AAAA" : "A", host->name); + continue; + } /* Lookup succeeded: fill in the given host item with the first non-ignored address found; create additional items for any others. A single A6 record @@ -2458,6 +2444,8 @@ Arguments: srv_service when SRV used, the service name srv_fail_domains DNS errors for these domains => assume nonexist mx_fail_domains DNS errors for these domains => assume nonexist + dnssec_request_domains => make dnssec request + dnssec_require_domains => ditto and nonexist failures fully_qualified_name if not NULL, return fully-qualified name removed set TRUE if local host was removed from the list @@ -2475,6 +2463,7 @@ Returns: HOST_FIND_FAILED Failed to find the host or domain; int host_find_bydns(host_item *host, uschar *ignore_target_hosts, int whichrrs, uschar *srv_service, uschar *srv_fail_domains, uschar *mx_fail_domains, + uschar *dnssec_request_domains, uschar *dnssec_require_domains, uschar **fully_qualified_name, BOOL *removed) { host_item *h, *last; @@ -2484,6 +2473,12 @@ int ind_type = 0; int yield; dns_answer dnsa; dns_scan dnss; +BOOL dnssec_require = match_isinlist(host->name, &dnssec_require_domains, + 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK; +BOOL dnssec_request = dnssec_require + || match_isinlist(host->name, &dnssec_request_domains, + 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK; +dnssec_status_t dnssec; /* Set the default fully qualified name to the incoming name, initialize the resolver if necessary, set up the relevant options, and initialize the flag @@ -2491,7 +2486,9 @@ that gets set for DNS syntax check errors. */ if (fully_qualified_name != NULL) *fully_qualified_name = host->name; dns_init((whichrrs & HOST_FIND_QUALIFY_SINGLE) != 0, - (whichrrs & HOST_FIND_SEARCH_PARENTS) != 0); + (whichrrs & HOST_FIND_SEARCH_PARENTS) != 0, + dnssec_request + ); host_find_failed_syntax = FALSE; /* First, if requested, look for SRV records. The service name is given; we @@ -2512,20 +2509,37 @@ if ((whichrrs & HOST_FIND_BY_SRV) != 0) the input name, pass back the new original domain, without the prepended magic. */ + dnssec = DS_UNK; + lookup_dnssec_authenticated = NULL; rc = dns_lookup(&dnsa, buffer, ind_type, &temp_fully_qualified_name); + + if (dnssec_request) + { + if (dns_is_secure(&dnsa)) + { dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } + else + { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } + } + if (temp_fully_qualified_name != buffer && fully_qualified_name != NULL) *fully_qualified_name = temp_fully_qualified_name + prefix_length; /* On DNS failures, we give the "try again" error unless the domain is listed as one for which we continue. */ + if (rc == DNS_SUCCEED && dnssec_require && !dns_is_secure(&dnsa)) + { + log_write(L_host_lookup_failed, LOG_MAIN, + "dnssec fail on SRV for %.256s", host->name); + rc = DNS_FAIL; + } 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; + { yield = HOST_FIND_AGAIN; goto out; } DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA " "(domain in srv_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN"); } @@ -2541,17 +2555,41 @@ listed as one for which we continue. */ if (rc != DNS_SUCCEED && (whichrrs & HOST_FIND_BY_MX) != 0) { ind_type = T_MX; + dnssec = DS_UNK; + lookup_dnssec_authenticated = NULL; rc = dns_lookup(&dnsa, host->name, ind_type, fully_qualified_name); - if (rc == DNS_NOMATCH) return HOST_FIND_FAILED; - if (rc == DNS_FAIL || rc == DNS_AGAIN) + + if (dnssec_request) { - #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"); + if (dns_is_secure(&dnsa)) + { dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } + else + { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } + } + + switch (rc) + { + case DNS_NOMATCH: + yield = HOST_FIND_FAILED; goto out; + + case DNS_SUCCEED: + if (!dnssec_require || dns_is_secure(&dnsa)) + break; + log_write(L_host_lookup_failed, LOG_MAIN, + "dnssec fail on MX for %.256s", host->name); + rc = DNS_FAIL; + /*FALLTRHOUGH*/ + + case DNS_FAIL: + case DNS_AGAIN: + #ifndef STAND_ALONE + if (match_isinlist(host->name, &mx_fail_domains, 0, NULL, NULL, MCL_DOMAIN, + TRUE, NULL) != OK) + #endif + { yield = HOST_FIND_AGAIN; goto out; } + DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA " + "(domain in mx_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN"); + break; } } @@ -2564,14 +2602,25 @@ if (rc != DNS_SUCCEED) if ((whichrrs & HOST_FIND_BY_A) == 0) { DEBUG(D_host_lookup) debug_printf("Address records are not being sought\n"); - return HOST_FIND_FAILED; + yield = HOST_FIND_FAILED; + goto out; } last = host; /* End of local chainlet */ host->mx = MX_NONE; host->port = PORT_NONE; + dnssec = DS_UNK; + lookup_dnssec_authenticated = NULL; rc = set_address_from_dns(host, &last, ignore_target_hosts, FALSE, - fully_qualified_name); + fully_qualified_name, dnssec_request, dnssec_require); + + if (dnssec_request) + { + if (dns_is_secure(&dnsa)) + { dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } + else + { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } + } /* If one or more address records have been found, check that none of them are local. Since we know the host items all have their IP addresses @@ -2584,11 +2633,6 @@ 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; @@ -2603,7 +2647,8 @@ if (rc != DNS_SUCCEED) } } - return rc; + yield = rc; + goto out; } /* We have found one or more MX or SRV records. Sort them according to @@ -2646,9 +2691,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); the same precedence to sort randomly. */ if (ind_type == T_MX) - { weight = random_number(500); - } /* SRV records are specified with a port and a weight. The weight is used in a special algorithm. However, to start with, we just use it to order the @@ -2712,6 +2755,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); host->sort_key = precedence * 1000 + weight; host->status = hstatus_unknown; host->why = hwhy_unknown; + host->dnssec = dnssec; last = host; } @@ -2728,6 +2772,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); next->sort_key = sort_key; next->status = hstatus_unknown; next->why = hwhy_unknown; + next->dnssec = dnssec; next->last_try = 0; /* Handle the case when we have to insert before the first item. */ @@ -2787,7 +2832,8 @@ if (ind_type == T_SRV) if (host == last && host->name[0] == 0) { DEBUG(D_host_lookup) debug_printf("the single SRV record is \".\"\n"); - return HOST_FIND_FAILED; + yield = HOST_FIND_FAILED; + goto out; } DEBUG(D_host_lookup) @@ -2897,12 +2943,14 @@ otherwise invalid host names obtained from MX or SRV records can cause trouble if they happen to match something local. */ yield = HOST_FIND_FAILED; /* Default yield */ -dns_init(FALSE, FALSE); /* Disable qualify_single and search_parents */ +dns_init(FALSE, FALSE, /* Disable qualify_single and search_parents */ + dnssec_request || dnssec_require); for (h = host; h != last->next; h = h->next) { if (h->address != NULL) continue; /* Inserted by a multihomed host */ - rc = set_address_from_dns(h, &last, ignore_target_hosts, allow_mx_to_ip, NULL); + rc = set_address_from_dns(h, &last, ignore_target_hosts, allow_mx_to_ip, + NULL, dnssec_request, dnssec_require); if (rc != HOST_FOUND) { h->status = hstatus_unusable; @@ -2957,17 +3005,19 @@ single MX preference value, IPv6 addresses come first. This can separate the 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; @@ -2976,39 +3026,6 @@ if (h != last) } #endif -/* When running in the test harness, we want the hosts always to be in the same -order so that the debugging output is the same and can be compared. Having a -fixed set of "random" numbers doesn't actually achieve this, because the RRs -come back from the resolver in a random order, so the non-random random numbers -get used in a different order. We therefore have to sort the hosts that have -the same MX values. We chose do to this by their name and then by IP address. -The fact that the sort is slow matters not - this is testing only! */ - -if (running_in_test_harness) - { - BOOL done; - do - { - done = TRUE; - for (h = host; h != last; h = h->next) - { - int c = Ustrcmp(h->name, h->next->name); - if (c == 0) c = Ustrcmp(h->address, h->next->address); - if (h->mx == h->next->mx && c > 0) - { - host_item *next = h->next; - host_item temp = *h; - temp.next = next->next; - *h = *next; - h->next = next; - *next = temp; - done = FALSE; - } - } - } - while (!done); - } - /* Remove any duplicate IP addresses and then scan the list of hosts for any whose IP addresses are on the local host. If any are found, all hosts with the same or higher MX values are removed. However, if the local host has the lowest @@ -3042,6 +3059,9 @@ DEBUG(D_host_lookup) } } +out: + +dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ return yield; } @@ -3063,9 +3083,12 @@ int whichrrs = HOST_FIND_BY_MX | HOST_FIND_BY_A; BOOL byname = FALSE; BOOL qualify_single = TRUE; BOOL search_parents = FALSE; +BOOL request_dnssec = FALSE; +BOOL require_dnssec = FALSE; uschar **argv = USS cargv; uschar buffer[256]; +disable_ipv6 = FALSE; primary_hostname = US""; store_pool = POOL_MAIN; debug_selector = D_host_lookup|D_interface; @@ -3081,7 +3104,7 @@ if (argc > 1) primary_hostname = argv[1]; /* So that debug level changes can be done first */ -dns_init(qualify_single, search_parents); +dns_init(qualify_single, search_parents, FALSE); printf("Testing host lookup\n"); printf("> "); @@ -3107,12 +3130,17 @@ while (Ufgets(buffer, 256, stdin) != NULL) whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_MX; else if (Ustrcmp(buffer, "srv+mx+a") == 0) whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_MX | HOST_FIND_BY_A; - else if (Ustrcmp(buffer, "qualify_single") == 0) qualify_single = TRUE; + else if (Ustrcmp(buffer, "qualify_single") == 0) qualify_single = TRUE; 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, "search_parents") == 0) search_parents = TRUE; else if (Ustrcmp(buffer, "no_search_parents") == 0) search_parents = FALSE; + else if (Ustrcmp(buffer, "request_dnssec") == 0) request_dnssec = TRUE; + else if (Ustrcmp(buffer, "no_request_dnssec") == 0) request_dnssec = FALSE; + else if (Ustrcmp(buffer, "require_dnssec") == 0) require_dnssec = TRUE; + else if (Ustrcmp(buffer, "no_reqiret_dnssec") == 0) require_dnssec = 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; @@ -3142,11 +3170,12 @@ while (Ufgets(buffer, 256, stdin) != NULL) if (qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE; if (search_parents) flags |= HOST_FIND_SEARCH_PARENTS; - rc = byname? - host_find_byname(&h, NULL, &fully_qualified_name, TRUE) - : - host_find_bydns(&h, NULL, flags, US"smtp", NULL, NULL, - &fully_qualified_name, NULL); + rc = byname + ? host_find_byname(&h, NULL, flags, &fully_qualified_name, TRUE) + : host_find_bydns(&h, NULL, flags, US"smtp", NULL, NULL, + request_dnssec ? &h.name : NULL, + require_dnssec ? &h.name : NULL, + &fully_qualified_name, NULL); if (rc == HOST_FIND_FAILED) printf("Failed\n"); else if (rc == HOST_FIND_AGAIN) printf("Again\n"); @@ -3205,4 +3234,6 @@ return 0; } #endif /* STAND_ALONE */ +/* vi: aw ai sw=2 +*/ /* End of host.c */