X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fhost.c;h=eda56d76377e8de28be22986fe8064a26088e8d5;hb=d7978c0f8af20ff4c3f770589b1bb81568aecff3;hp=1f0d91959b9f1982e2cfedeba4328c96aadb338e;hpb=d4fd1b83a197d73cbac114fe53f3448d8b5c7cc2;p=exim.git diff --git a/src/src/host.c b/src/src/host.c index 1f0d91959..eda56d763 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -2,7 +2,7 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2017 */ +/* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or @@ -84,7 +84,7 @@ if (limit < 1) return 0; if (random_seed == 0) { - if (running_in_test_harness) random_seed = 42; else + if (f.running_in_test_harness) random_seed = 42; else { int p = (int)getpid(); random_seed = (int)time(NULL) ^ ((p << 16) | p); @@ -179,7 +179,6 @@ 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, @@ -192,13 +191,11 @@ if (Ustrcmp(name, "localhost") == 0) /* Handle a literal IP address */ -ipa = string_is_ip_address(lname, NULL); -if (ipa != 0) +if ((ipa = string_is_ip_address(lname, NULL)) != 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 *)); @@ -209,8 +206,7 @@ if (ipa != 0) yield->h_length = alen; yield->h_addr_list = CSS alist; *alist++ = adds; - n = host_aton(lname, x); - for (i = 0; i < n; i++) + for (int n = host_aton(lname, x), i = 0; i < n; i++) { int y = x[i]; *adds++ = (y >> 24) & 255; @@ -250,11 +246,10 @@ else case DNS_FAIL: *error_num = NO_RECOVERY; return NULL; } - for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) - if (rr->type == type) - count++; + 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 *)); @@ -266,18 +261,15 @@ else yield->h_length = alen; yield->h_addr_list = CSS alist; - for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == type) { - int i, n; int x[4]; dns_address *da; - if (rr->type != type) continue; if (!(da = dns_address_from_rr(&dnsa, rr))) break; *alist++ = adds; - n = host_aton(da->address, x); - for (i = 0; i < n; i++) + for (int n = host_aton(da->address, x), i = 0; i < n; i++) { int y = x[i]; *adds++ = (y >> 24) & 255; @@ -318,12 +310,12 @@ int sep = 0; int fake_mx = MX_NONE; /* This value is actually -1 */ uschar *name; -if (list == NULL) return; +if (!list) return; if (randomize) fake_mx--; /* Start at -2 for randomizing */ *anchor = NULL; -while ((name = string_nextinlist(&list, &sep, NULL, 0)) != NULL) +while ((name = string_nextinlist(&list, &sep, NULL, 0))) { host_item *h; @@ -343,7 +335,7 @@ while ((name = string_nextinlist(&list, &sep, NULL, 0)) != NULL) h->why = hwhy_unknown; h->last_try = 0; - if (*anchor == NULL) + if (!*anchor) { h->next = NULL; *anchor = h; @@ -358,7 +350,7 @@ while ((name = string_nextinlist(&list, &sep, NULL, 0)) != NULL) } else { - while (hh->next != NULL && h->sort_key >= (hh->next)->sort_key) + while (hh->next && h->sort_key >= hh->next->sort_key) hh = hh->next; h->next = hh->next; hh->next = h; @@ -520,7 +512,9 @@ There wouldn't be two different variables if I had got all this right in the first place. Because this data may survive over more than one incoming SMTP message, it has -to be in permanent store. +to be in permanent store. However, STARTTLS has to be forgotten and redone +on a multi-message conn, so this will be called once per message then. Hence +we use malloc, so we can free. Arguments: none Returns: nothing @@ -530,13 +524,12 @@ void host_build_sender_fullhost(void) { BOOL show_helo = TRUE; -uschar *address; +uschar * address, * fullhost, * rcvhost, * reset_point; int len; -int old_pool = store_pool; -if (sender_host_address == NULL) return; +if (!sender_host_address) return; -store_pool = POOL_PERM; +reset_point = store_get(0); /* Set up address, with or without the port. After discussion, it seems that the only format that doesn't cause trouble is [aaaa]:pppp. However, we can't @@ -549,7 +542,7 @@ if (!LOGGING(incoming_port) || sender_host_port <= 0) /* If there's no EHLO/HELO data, we can't show it. */ -if (sender_helo_name == NULL) show_helo = FALSE; +if (!sender_helo_name) 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 @@ -593,13 +586,13 @@ if (!sender_host_name) int adlen; /* Sun compiler doesn't like ++ in initializers */ adlen = portptr ? (++portptr - address) : Ustrlen(address); - sender_fullhost = sender_helo_name + fullhost = sender_helo_name ? string_sprintf("(%s) %s", sender_helo_name, address) : address; g = string_catn(NULL, address, adlen); - if (sender_ident != NULL || show_helo || portptr != NULL) + if (sender_ident || show_helo || portptr) { int firstptr; g = string_catn(g, US" (", 2); @@ -619,12 +612,7 @@ if (!sender_host_name) g = string_catn(g, US")", 1); } - sender_rcvhost = string_from_gstring(g); - - /* Release store, because string_cat allocated a minimum of 100 bytes that - are rarely completely used. */ - - store_reset(sender_rcvhost + g->ptr + 1); + rcvhost = string_from_gstring(g); } /* Host name is known and verified. Unless we've already found that the HELO @@ -637,25 +625,30 @@ else if (show_helo) { - sender_fullhost = string_sprintf("%s (%s) %s", sender_host_name, + fullhost = string_sprintf("%s (%s) %s", sender_host_name, sender_helo_name, address); - sender_rcvhost = (sender_ident == NULL)? - string_sprintf("%s (%s helo=%s)", sender_host_name, - address, sender_helo_name) : - string_sprintf("%s\n\t(%s helo=%s ident=%s)", sender_host_name, - address, sender_helo_name, sender_ident); + rcvhost = sender_ident + ? string_sprintf("%s\n\t(%s helo=%s ident=%s)", sender_host_name, + address, sender_helo_name, sender_ident) + : string_sprintf("%s (%s helo=%s)", sender_host_name, + address, sender_helo_name); } 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); + fullhost = string_sprintf("%s %s", sender_host_name, address); + rcvhost = sender_ident + ? string_sprintf("%s (%s ident=%s)", sender_host_name, address, + sender_ident) + : string_sprintf("%s (%s)", sender_host_name, address); } } -store_pool = old_pool; +if (sender_fullhost) store_free(sender_fullhost); +sender_fullhost = string_copy_malloc(fullhost); +if (sender_rcvhost) store_free(sender_rcvhost); +sender_rcvhost = string_copy_malloc(rcvhost); + +store_reset(reset_point); DEBUG(D_host_lookup) debug_printf("sender_fullhost = %s\n", sender_fullhost); DEBUG(D_host_lookup) debug_printf("sender_rcvhost = %s\n", sender_rcvhost); @@ -685,23 +678,21 @@ Returns: pointer to a string in big_buffer uschar * host_and_ident(BOOL useflag) { -if (sender_fullhost == NULL) - { - (void)string_format(big_buffer, big_buffer_size, "%s%s", useflag? "U=" : "", - (sender_ident == NULL)? US"unknown" : sender_ident); - } +if (!sender_fullhost) + (void)string_format(big_buffer, big_buffer_size, "%s%s", useflag ? "U=" : "", + sender_ident ? sender_ident : US"unknown"); else { - uschar *flag = useflag? US"H=" : US""; - uschar *iface = US""; - if (LOGGING(incoming_interface) && interface_address != NULL) + uschar * flag = useflag ? US"H=" : US""; + uschar * iface = US""; + if (LOGGING(incoming_interface) && interface_address) iface = string_sprintf(" I=[%s]:%d", interface_address, interface_port); - if (sender_ident == NULL) - (void)string_format(big_buffer, big_buffer_size, "%s%s%s", - flag, sender_fullhost, iface); - else + if (sender_ident) (void)string_format(big_buffer, big_buffer_size, "%s%s%s U=%s", flag, sender_fullhost, iface, sender_ident); + else + (void)string_format(big_buffer, big_buffer_size, "%s%s%s", + flag, sender_fullhost, iface); } return big_buffer; } @@ -806,7 +797,7 @@ static ip_address_item * add_unique_interface(ip_address_item *list, ip_address_item *ipa) { ip_address_item *ipa2; -for (ipa2 = list; ipa2 != NULL; ipa2 = ipa2->next) +for (ipa2 = list; ipa2; ipa2 = ipa2->next) if (Ustrcmp(ipa2->address, ipa->address) == 0) return list; ipa2 = store_get_perm(sizeof(ip_address_item)); *ipa2 = *ipa; @@ -831,27 +822,25 @@ if (local_interface_data == NULL) US"extra_local_interfaces"); ip_address_item *ipa; - if (dlist == NULL) dlist = xlist; else + if (!dlist) dlist = xlist; + else { - for (ipa = dlist; ipa->next != NULL; ipa = ipa->next); + for (ipa = dlist; ipa->next; ipa = ipa->next) ; ipa->next = xlist; } - for (ipa = dlist; ipa != NULL; ipa = ipa->next) + for (ipa = dlist; ipa; ipa = ipa->next) { if (Ustrcmp(ipa->address, "0.0.0.0") == 0 || Ustrcmp(ipa->address, "::0") == 0) { - ip_address_item *ipa2; BOOL ipv6 = ipa->address[0] == ':'; - if (running_interfaces == NULL) + if (!running_interfaces) running_interfaces = os_find_running_interfaces(); - for (ipa2 = running_interfaces; ipa2 != NULL; ipa2 = ipa2->next) - { + for (ip_address_item * ipa2 = running_interfaces; ipa2; ipa2 = ipa2->next) if ((Ustrchr(ipa2->address, ':') != NULL) == ipv6) local_interface_data = add_unique_interface(local_interface_data, - ipa2); - } + ipa2); } else { @@ -1089,9 +1078,8 @@ Returns: nothing void host_mask(int count, int *binary, int mask) { -int i; if (mask < 0) mask = 99999; -for (i = 0; i < count; i++) +for (int i = 0; i < count; i++) { int wordmask; if (mask == 0) wordmask = 0; @@ -1138,17 +1126,17 @@ Returns: the number of characters placed in buffer, not counting int host_nmtoa(int count, int *binary, int mask, uschar *buffer, int sep) { -int i, j; +int j; uschar *tt = buffer; if (count == 1) { j = binary[0]; - for (i = 24; i >= 0; i -= 8) + for (int i = 24; i >= 0; i -= 8) tt += sprintf(CS tt, "%d.", (j >> i) & 255); } else - for (i = 0; i < 4; i++) + for (int i = 0; i < 4; i++) { j = binary[i]; tt += sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep); @@ -1278,7 +1266,6 @@ Returns: BOOL host_is_in_net(const uschar *host, const uschar *net, int maskoffset) { -int i; int address[4]; int incoming[4]; int mlen; @@ -1311,7 +1298,7 @@ if (insize != size) return FALSE; /* Else do the masked comparison. */ -for (i = 0; i < size; i++) +for (int i = 0; i < size; i++) { int mask; if (mlen == 0) mask = 0; @@ -1406,9 +1393,8 @@ for (h = host; h != last->next; h = h->next) if (h->address != NULL) { - ip_address_item *ip; if (Ustrcmp(h->address, "0.0.0.0") == 0) goto FOUND_LOCAL; - for (ip = local_interface_data; ip != NULL; ip = ip->next) + for (ip_address_item * ip = local_interface_data; ip; ip = ip->next) if (Ustrcmp(h->address, ip->address) == 0) goto FOUND_LOCAL; yield = HOST_FOUND; /* At least one remote address has been found */ } @@ -1591,13 +1577,13 @@ while (*s != 0) *t++ = tolower(*s++); /* If the host has aliases, build a copy of the alias list */ -if (hosts->h_aliases != NULL) +if (hosts->h_aliases) { int count = 1; - uschar **aliases, **ptr; - for (aliases = USS hosts->h_aliases; *aliases != NULL; aliases++) count++; + uschar **ptr; + for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++) count++; ptr = sender_host_aliases = store_get_perm(count * sizeof(uschar *)); - for (aliases = USS hosts->h_aliases; *aliases != NULL; aliases++) + for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++) { uschar *s = *aliases; int len = Ustrlen(s) + 1; @@ -1656,12 +1642,11 @@ host_name_lookup(void) { int old_pool, rc; int sep = 0; -uschar *hname, *save_hostname; +uschar *save_hostname; uschar **aliases; uschar buffer[256]; uschar *ordername; const uschar *list = host_lookup_order; -dns_record *rr; dns_answer dnsa; dns_scan dnss; @@ -1673,7 +1658,7 @@ HDEBUG(D_host_lookup) /* For testing the case when a lookup does not complete, we have a special reserved IP address. */ -if (running_in_test_harness && +if (f.running_in_test_harness && Ustrcmp(sender_host_address, "99.99.99.99") == 0) { HDEBUG(D_host_lookup) @@ -1713,11 +1698,10 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) store_pool = POOL_PERM; /* Save names in permanent storage */ - for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) - if (rr->type == T_PTR) - count++; + rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR) + count++; /* Get store for the list of aliases. For compatibility with gethostbyaddr, we make an empty list if there are none. */ @@ -1726,13 +1710,11 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) /* Re-scan and extract the names */ - for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR) { - uschar *s = NULL; - if (rr->type != T_PTR) continue; - s = store_get(ssize); + uschar * s = store_get(ssize); /* If an overlong response was received, the data will have been truncated and dn_expand may fail. */ @@ -1795,9 +1777,9 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) /* If we have failed to find a name, return FAIL and log when required. NB host_lookup_msg must be in permanent store. */ -if (sender_host_name == NULL) +if (!sender_host_name) { - if (host_checking || !log_testing_mode) + if (host_checking || !f.log_testing_mode) 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)"; @@ -1827,26 +1809,19 @@ the names, and accepts only those that have the correct IP address. */ save_hostname = sender_host_name; /* Save for error messages */ aliases = sender_host_aliases; -for (hname = sender_host_name; hname; hname = *aliases++) +for (uschar * hname = sender_host_name; hname; hname = *aliases++) { int rc; BOOL ok = FALSE; - host_item h; - dnssec_domains d; + host_item h = { .next = NULL, .name = hname, .mx = MX_NONE, .address = NULL }; + dnssec_domains d = + { .request = sender_host_dnssec ? US"*" : NULL, .require = NULL }; - h.next = NULL; - h.name = hname; - h.mx = MX_NONE; - h.address = NULL; - d.request = sender_host_dnssec ? US"*" : NULL;; - d.require = NULL; - - if ( (rc = host_find_bydns(&h, NULL, HOST_FIND_BY_A, + if ( (rc = host_find_bydns(&h, NULL, HOST_FIND_BY_A | HOST_FIND_BY_AAAA, NULL, NULL, NULL, &d, NULL, NULL)) == HOST_FOUND || rc == HOST_FOUND_LOCAL ) { - host_item *hh; HDEBUG(D_host_lookup) debug_printf("checking addresses for %s\n", hname); /* If the forward lookup was not secure we cancel the is-secure variable */ @@ -1855,7 +1830,7 @@ for (hname = sender_host_name; hname; hname = *aliases++) h.dnssec == DS_YES ? "DNSSEC verified (AD)" : "unverified"); if (h.dnssec != DS_YES) sender_host_dnssec = FALSE; - for (hh = &h; hh; hh = hh->next) + for (host_item * hh = &h; hh; hh = hh->next) if (host_is_in_net(hh->address, sender_host_address, 0)) { HDEBUG(D_host_lookup) debug_printf(" %s OK\n", hh->address); @@ -1966,8 +1941,7 @@ int host_find_byname(host_item *host, const uschar *ignore_target_hosts, int flags, const uschar **fully_qualified_name, BOOL local_host_check) { -int i, yield, times; -uschar **addrlist; +int yield, times; host_item *last = NULL; BOOL temp_error = FALSE; #if HAVE_IPV6 @@ -2010,11 +1984,11 @@ lookups here (except when testing standalone). */ /* Initialize the flag that gets set for DNS syntax check errors, so that the interface to this function can be similar to host_find_bydns. */ -host_find_failed_syntax = FALSE; +f.host_find_failed_syntax = FALSE; /* Loop to look up both kinds of address in an IPv6 world */ -for (i = 1; i <= times; +for (int i = 1; i <= times; #if HAVE_IPV6 af = AF_INET, /* If 2 passes, IPv4 on the second */ #endif @@ -2032,7 +2006,7 @@ for (i = 1; i <= times; if (slow_lookup_log) time_msec = get_time_in_ms(); #if HAVE_IPV6 - if (running_in_test_harness) + if (f.running_in_test_harness) hostdata = host_fake_gethostbyname(host->name, af, &error_num); else { @@ -2045,7 +2019,7 @@ for (i = 1; i <= times; } #else /* not HAVE_IPV6 */ - if (running_in_test_harness) + if (f.running_in_test_harness) hostdata = host_fake_gethostbyname(host->name, AF_INET, &error_num); else { @@ -2104,7 +2078,7 @@ for (i = 1; i <= times; ipv4_addr = hostdata->h_length == sizeof(struct in_addr); - for (addrlist = USS hostdata->h_addr_list; *addrlist != NULL; addrlist++) + for (uschar ** addrlist = USS hostdata->h_addr_list; *addrlist; addrlist++) { uschar *text_address = host_ntoa(ipv4_addr? AF_INET:AF_INET6, *addrlist, NULL, NULL); @@ -2170,7 +2144,7 @@ if (host->address == NULL) HDEBUG(D_host_lookup) debug_printf("%s\n", msg); if (temp_error) goto RETURN_AGAIN; - if (host_checking || !log_testing_mode) + if (host_checking || !f.log_testing_mode) log_write(L_host_lookup_failed, LOG_MAIN, "%s", msg); return HOST_FIND_FAILED; } @@ -2184,8 +2158,7 @@ yield = local_host_check? HDEBUG(D_host_lookup) { - const host_item *h; - if (fully_qualified_name != NULL) + if (fully_qualified_name) debug_printf("fully qualified name = %s\n", *fully_qualified_name); debug_printf("%s looked up these IP addresses:\n", #if HAVE_IPV6 @@ -2198,9 +2171,9 @@ HDEBUG(D_host_lookup) "gethostbyname" #endif ); - for (h = host; h != last->next; h = h->next) + for (const host_item * h = host; h != last->next; h = h->next) debug_printf(" name=%s address=%s\n", h->name, - (h->address == NULL)? US"" : h->address); + h->address ? h->address : US""); } /* Return the found status. */ @@ -2241,9 +2214,7 @@ field set to NULL, fill in its IP address from the DNS. If it is multi-homed, create additional host items for the additional addresses, copying all the other fields, and randomizing the order. -On IPv6 systems, A6 records are sought first (but only if support for A6 is -configured - they may never become mainstream), then AAAA records are sought, -and finally A records are sought as well. +On IPv6 systems, AAAA records are sought first, then A records. The host name may be changed if the DNS returns a different name - e.g. fully qualified or changed via CNAME. If fully_qualified_name is not NULL, dns_lookup @@ -2266,6 +2237,7 @@ Arguments: to something) dnssec_request if TRUE request the AD bit dnssec_require if TRUE require the AD bit + whichrrs select ipv4, ipv6 results Returns: HOST_FIND_FAILED couldn't find A record HOST_FIND_AGAIN try again later @@ -2278,9 +2250,8 @@ static int set_address_from_dns(host_item *host, host_item **lastptr, const uschar *ignore_target_hosts, BOOL allow_ip, const uschar **fully_qualified_name, - BOOL dnssec_request, BOOL dnssec_require) + BOOL dnssec_request, BOOL dnssec_require, int whichrrs) { -dns_record *rr; host_item *thishostlast = NULL; /* Indicates not yet filled in anything */ BOOL v6_find_again = FALSE; BOOL dnssec_fail = FALSE; @@ -2293,8 +2264,8 @@ those sites that feel they have to flaunt the RFC rules. */ if (allow_ip && string_is_ip_address(host->name, NULL) != 0) { #ifndef STAND_ALONE - if (ignore_target_hosts != NULL && - verify_check_this_host(&ignore_target_hosts, NULL, host->name, + if ( ignore_target_hosts + && verify_check_this_host(&ignore_target_hosts, NULL, host->name, host->name, NULL) == OK) return HOST_IGNORED; #endif @@ -2304,16 +2275,18 @@ if (allow_ip && string_is_ip_address(host->name, NULL) != 0) } /* On an IPv6 system, unless IPv6 is disabled, go round the loop up to twice, -looking for AAAA records the first time. However, unless -doing standalone testing, we force an IPv4 lookup if the domain matches -dns_ipv4_lookup is set. On an IPv4 system, go round the -loop once only, looking only for A records. */ +looking for AAAA records the first time. However, unless doing standalone +testing, we force an IPv4 lookup if the domain matches dns_ipv4_lookup global. +On an IPv4 system, go round the loop once only, looking only for A records. */ #if HAVE_IPV6 #ifndef STAND_ALONE - if (disable_ipv6 || (dns_ipv4_lookup != NULL && - match_isinlist(host->name, CUSS &dns_ipv4_lookup, 0, NULL, NULL, - MCL_DOMAIN, TRUE, NULL) == OK)) + if ( disable_ipv6 + || !(whichrrs & HOST_FIND_BY_AAAA) + || (dns_ipv4_lookup + && match_isinlist(host->name, CUSS &dns_ipv4_lookup, 0, NULL, NULL, + MCL_DOMAIN, TRUE, NULL) == OK) + ) i = 0; /* look up A records only */ else #endif /* STAND_ALONE */ @@ -2330,7 +2303,8 @@ for (; i >= 0; i--) { static int types[] = { T_A, T_AAAA }; int type = types[i]; - int randoffset = (i == 0)? 500 : 0; /* Ensures v6 sorts before v4 */ + int randoffset = i == (whichrrs & HOST_FIND_IPV4_FIRST ? 1 : 0) + ? 500 : 0; /* Ensures v6/4 sort order */ dns_answer dnsa; dns_scan dnss; @@ -2400,104 +2374,101 @@ for (; i >= 0; i--) fully_qualified_name = NULL; - for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); + for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; - rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) + rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == type) { - if (rr->type == type) - { - dns_address *da = dns_address_from_rr(&dnsa, rr); + dns_address * da = dns_address_from_rr(&dnsa, rr); - DEBUG(D_host_lookup) - if (!da) debug_printf("no addresses extracted from A6 RR for %s\n", - host->name); + DEBUG(D_host_lookup) + if (!da) debug_printf("no addresses extracted from A6 RR for %s\n", + host->name); - /* This loop runs only once for A and AAAA records, but may run - several times for an A6 record that generated multiple addresses. */ + /* This loop runs only once for A and AAAA records, but may run + several times for an A6 record that generated multiple addresses. */ - for (; da; da = da->next) - { - #ifndef STAND_ALONE - if (ignore_target_hosts != NULL && - verify_check_this_host(&ignore_target_hosts, NULL, - host->name, da->address, NULL) == OK) - { - DEBUG(D_host_lookup) - debug_printf("ignored host %s [%s]\n", host->name, da->address); - continue; - } - #endif + for (; da; da = da->next) + { + #ifndef STAND_ALONE + if (ignore_target_hosts != NULL && + verify_check_this_host(&ignore_target_hosts, NULL, + host->name, da->address, NULL) == OK) + { + DEBUG(D_host_lookup) + debug_printf("ignored host %s [%s]\n", host->name, da->address); + continue; + } + #endif - /* If this is the first address, stick it in the given host block, - and change the name if the returned RR has a different name. */ + /* If this is the first address, stick it in the given host block, + and change the name if the returned RR has a different name. */ - if (thishostlast == NULL) - { - if (strcmpic(host->name, rr->name) != 0) - host->name = string_copy_dnsdomain(rr->name); - host->address = da->address; - host->sort_key = host->mx * 1000 + random_number(500) + randoffset; - host->status = hstatus_unknown; - host->why = hwhy_unknown; - thishostlast = host; - } + if (thishostlast == NULL) + { + if (strcmpic(host->name, rr->name) != 0) + host->name = string_copy_dnsdomain(rr->name); + host->address = da->address; + host->sort_key = host->mx * 1000 + random_number(500) + randoffset; + host->status = hstatus_unknown; + host->why = hwhy_unknown; + thishostlast = host; + } - /* Not the first address. Check for, and ignore, duplicates. Then - insert in the chain at a random point. */ + /* Not the first address. Check for, and ignore, duplicates. Then + insert in the chain at a random point. */ - else - { - int new_sort_key; - host_item *next; - - /* End of our local chain is specified by "thishostlast". */ - - for (next = host;; next = next->next) - { - if (Ustrcmp(CS da->address, next->address) == 0) break; - if (next == thishostlast) { next = NULL; break; } - } - if (next != NULL) continue; /* With loop for next address */ - - /* Not a duplicate */ - - new_sort_key = host->mx * 1000 + random_number(500) + randoffset; - next = store_get(sizeof(host_item)); - - /* New address goes first: insert the new block after the first one - (so as not to disturb the original pointer) but put the new address - in the original block. */ - - if (new_sort_key < host->sort_key) - { - *next = *host; /* Copies port */ - host->next = next; - host->address = da->address; - host->sort_key = new_sort_key; - if (thishostlast == host) thishostlast = next; /* Local last */ - if (*lastptr == host) *lastptr = next; /* Global last */ - } - - /* Otherwise scan down the addresses for this host to find the - one to insert after. */ - - else - { - host_item *h = host; - while (h != thishostlast) - { - if (new_sort_key < h->next->sort_key) break; - h = h->next; - } - *next = *h; /* Copies port */ - h->next = next; - next->address = da->address; - next->sort_key = new_sort_key; - if (h == thishostlast) thishostlast = next; /* Local last */ - if (h == *lastptr) *lastptr = next; /* Global last */ - } - } - } + else + { + int new_sort_key; + host_item *next; + + /* End of our local chain is specified by "thishostlast". */ + + for (next = host;; next = next->next) + { + if (Ustrcmp(CS da->address, next->address) == 0) break; + if (next == thishostlast) { next = NULL; break; } + } + if (next != NULL) continue; /* With loop for next address */ + + /* Not a duplicate */ + + new_sort_key = host->mx * 1000 + random_number(500) + randoffset; + next = store_get(sizeof(host_item)); + + /* New address goes first: insert the new block after the first one + (so as not to disturb the original pointer) but put the new address + in the original block. */ + + if (new_sort_key < host->sort_key) + { + *next = *host; /* Copies port */ + host->next = next; + host->address = da->address; + host->sort_key = new_sort_key; + if (thishostlast == host) thishostlast = next; /* Local last */ + if (*lastptr == host) *lastptr = next; /* Global last */ + } + + /* Otherwise scan down the addresses for this host to find the + one to insert after. */ + + else + { + host_item *h = host; + while (h != thishostlast) + { + if (new_sort_key < h->next->sort_key) break; + h = h->next; + } + *next = *h; /* Copies port */ + h->next = next; + next->address = da->address; + next->sort_key = new_sort_key; + if (h == thishostlast) thishostlast = next; /* Local last */ + if (h == *lastptr) *lastptr = next; /* Global last */ + } + } } } } @@ -2532,10 +2503,13 @@ Arguments: whichrrs flags indicating which RRs to look for: HOST_FIND_BY_SRV => look for SRV HOST_FIND_BY_MX => look for MX - HOST_FIND_BY_A => look for A or AAAA + HOST_FIND_BY_A => look for A + HOST_FIND_BY_AAAA => look for AAAA also flags indicating how the lookup is done HOST_FIND_QUALIFY_SINGLE ) passed to the HOST_FIND_SEARCH_PARENTS ) resolver + HOST_FIND_IPV4_FIRST => reverse usual result ordering + HOST_FIND_IPV4_ONLY => MX results elide ipv6 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 @@ -2563,7 +2537,6 @@ host_find_bydns(host_item *host, const uschar *ignore_target_hosts, int whichrrs const uschar **fully_qualified_name, BOOL *removed) { host_item *h, *last; -dns_record *rr; int rc = DNS_FAIL; int ind_type = 0; int yield; @@ -2586,20 +2559,21 @@ if (fully_qualified_name != NULL) *fully_qualified_name = host->name; dns_init((whichrrs & HOST_FIND_QUALIFY_SINGLE) != 0, (whichrrs & HOST_FIND_SEARCH_PARENTS) != 0, dnssec_request); -host_find_failed_syntax = FALSE; +f.host_find_failed_syntax = FALSE; /* First, if requested, look for SRV records. The service name is given; we assume TCP protocol. DNS domain names are constrained to a maximum of 256 characters, so the code below should be safe. */ -if ((whichrrs & HOST_FIND_BY_SRV) != 0) +if (whichrrs & HOST_FIND_BY_SRV) { - uschar buffer[300]; - uschar *temp_fully_qualified_name = buffer; + gstring * g; + uschar * temp_fully_qualified_name; int prefix_length; - (void)sprintf(CS buffer, "_%s._tcp.%n%.256s", srv_service, &prefix_length, - host->name); + g = string_fmt_append(NULL, "_%s._tcp.%n%.256s", + srv_service, &prefix_length, host->name); + temp_fully_qualified_name = string_from_gstring(g); ind_type = T_SRV; /* Search for SRV records. If the fully qualified name is different to @@ -2608,7 +2582,8 @@ if ((whichrrs & HOST_FIND_BY_SRV) != 0) dnssec = DS_UNK; lookup_dnssec_authenticated = NULL; - rc = dns_lookup_timerwrap(&dnsa, buffer, ind_type, CUSS &temp_fully_qualified_name); + rc = dns_lookup_timerwrap(&dnsa, temp_fully_qualified_name, ind_type, + CUSS &temp_fully_qualified_name); DEBUG(D_dns) if ((dnssec_request || dnssec_require) @@ -2624,7 +2599,7 @@ if ((whichrrs & HOST_FIND_BY_SRV) != 0) { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } } - if (temp_fully_qualified_name != buffer && fully_qualified_name != NULL) + if (temp_fully_qualified_name != g->s && 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 @@ -2716,7 +2691,7 @@ host. */ if (rc != DNS_SUCCEED) { - if ((whichrrs & HOST_FIND_BY_A) == 0) + if (!(whichrrs & (HOST_FIND_BY_A | HOST_FIND_BY_AAAA))) { DEBUG(D_host_lookup) debug_printf("Address records are not being sought\n"); yield = HOST_FIND_FAILED; @@ -2729,7 +2704,7 @@ if (rc != DNS_SUCCEED) host->dnssec = DS_UNK; lookup_dnssec_authenticated = NULL; rc = set_address_from_dns(host, &last, ignore_target_hosts, FALSE, - fully_qualified_name, dnssec_request, dnssec_require); + fully_qualified_name, dnssec_request, dnssec_require, whichrrs); /* 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 @@ -2743,18 +2718,15 @@ if (rc != DNS_SUCCEED) if (rc == HOST_IGNORED) rc = HOST_FIND_FAILED; /* No special action */ DEBUG(D_host_lookup) - { - host_item *h; - if (host->address != NULL) + if (host->address) { - if (fully_qualified_name != NULL) + if (fully_qualified_name) debug_printf("fully qualified name = %s\n", *fully_qualified_name); - for (h = host; h != last->next; h = h->next) + for (host_item * h = host; h != last->next; h = h->next) debug_printf("%s %s mx=%d sort=%d %s\n", h->name, - (h->address == NULL)? US"" : h->address, h->mx, h->sort_key, - (h->status >= hstatus_unusable)? US"*" : US""); + h->address ? h->address : US"", h->mx, h->sort_key, + h->status >= hstatus_unusable ? US"*" : US""); } - } yield = rc; goto out; @@ -2782,12 +2754,11 @@ host which is not the primary hostname. */ last = NULL; /* Indicates that not even the first item is filled yet */ -for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); +for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); rr; rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == ind_type) { - int precedence; - int weight = 0; /* For SRV records */ + int precedence, weight; int port = PORT_NONE; const uschar * s = rr->data; /* MUST be unsigned for GETSHORT */ uschar data[256]; @@ -2799,13 +2770,11 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); 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 - records of equal priority (precedence). */ - else { + /* 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 + records of equal priority (precedence). */ GETSHORT(weight, s); GETSHORT(port, s); } @@ -2820,17 +2789,16 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); never know what junk might get into the DNS (and this case has been seen on more than one occasion). */ - if (last != NULL) /* This is not the first record */ + if (last) /* This is not the first record */ { host_item *prev = NULL; for (h = host; h != last->next; prev = h, h = h->next) - { if (strcmpic(h->name, data) == 0) { DEBUG(D_host_lookup) debug_printf("discarded duplicate host %s (MX=%d)\n", data, - (precedence > h->mx)? precedence : h->mx); + precedence > h->mx ? precedence : h->mx); if (precedence >= h->mx) goto NEXT_MX_RR; /* Skip greater precedence */ if (h == host) /* Override first item */ { @@ -2846,14 +2814,13 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); if (h == last) last = prev; break; } - } } /* If this is the first MX or SRV record, put the data into the existing host block. Otherwise, add a new block in the correct place; if it has to be before the first block, copy the first block's data to a new second block. */ - if (last == NULL) + if (!last) { host->name = string_copy_dnsdomain(data); host->address = NULL; @@ -2865,10 +2832,9 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); host->dnssec = dnssec; last = host; } + else /* Make a new host item and seek the correct insertion place */ - - else { int sort_key = precedence * 1000 + weight; host_item *next = store_get(sizeof(host_item)); @@ -2893,21 +2859,18 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); host->next = next; if (last == host) last = next; } + else /* Else scan down the items we have inserted as part of this exercise; don't go further. */ - - else { for (h = host; h != last; h = h->next) - { if (sort_key < h->next->sort_key) { next->next = h->next; h->next = next; break; } - } /* Join on after the last host item that's part of this processing if we haven't stopped sooner. */ @@ -2940,7 +2903,7 @@ remaining in the same priority group. */ if (ind_type == T_SRV) { - host_item **pptr; + host_item ** pptr; if (host == last && host->name[0] == 0) { @@ -2984,10 +2947,9 @@ if (ind_type == T_SRV) for (ppptr = pptr, hhh = h; hhh != hh; - ppptr = &(hhh->next), hhh = hhh->next) - { - if (hhh->sort_key >= randomizer) break; - } + ppptr = &hhh->next, hhh = hhh->next) + if (hhh->sort_key >= randomizer) + break; /* hhh now points to the host that should go first; ppptr points to the place that points to it. Unfortunately, if the start of the minilist is @@ -3012,7 +2974,6 @@ if (ind_type == T_SRV) hhh->next = temp.next; h->next = hhh; } - else { hhh->next = h; /* The rest of the chain follows it */ @@ -3064,20 +3025,18 @@ for (h = host; h != last->next; h = h->next) if (h->address) continue; /* Inserted by a multihomed host */ rc = set_address_from_dns(h, &last, ignore_target_hosts, allow_mx_to_ip, - NULL, dnssec_request, dnssec_require); + NULL, dnssec_request, dnssec_require, + whichrrs & HOST_FIND_IPV4_ONLY + ? HOST_FIND_BY_A : HOST_FIND_BY_A | HOST_FIND_BY_AAAA); if (rc != HOST_FOUND) { h->status = hstatus_unusable; switch (rc) { - case HOST_FIND_AGAIN: - yield = rc; h->why = hwhy_deferred; break; - case HOST_FIND_SECURITY: - yield = rc; h->why = hwhy_insecure; break; - case HOST_IGNORED: - h->why = hwhy_ignored; break; - default: - h->why = hwhy_failed; break; + case HOST_FIND_AGAIN: yield = rc; h->why = hwhy_deferred; break; + case HOST_FIND_SECURITY: yield = rc; h->why = hwhy_insecure; break; + case HOST_IGNORED: h->why = hwhy_ignored; break; + default: h->why = hwhy_failed; break; } } } @@ -3128,12 +3087,22 @@ 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 */ - 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 */ + if ( h->mx != next->mx /* If next is different MX */ + || !h->address /* OR this one is unset */ + ) + continue; /* move on to next */ + + if ( whichrrs & HOST_FIND_IPV4_FIRST + ? !Ustrchr(h->address, ':') /* OR this one is IPv4 */ + || next->address + && Ustrchr(next->address, ':') /* OR next is IPv6 */ + + : Ustrchr(h->address, ':') /* OR this one is IPv6 */ + || next->address + && !Ustrchr(next->address, ':') /* OR next is IPv4 */ + ) continue; /* move on to next */ + temp = *h; /* otherwise, swap */ temp.next = next->next; *h = *next; @@ -3157,14 +3126,14 @@ if (rc != HOST_FIND_FAILED) yield = rc; DEBUG(D_host_lookup) { - if (fully_qualified_name != NULL) + if (fully_qualified_name) debug_printf("fully qualified name = %s\n", *fully_qualified_name); debug_printf("host_find_bydns yield = %s (%d); returned hosts:\n", - (yield == HOST_FOUND)? "HOST_FOUND" : - (yield == HOST_FOUND_LOCAL)? "HOST_FOUND_LOCAL" : - (yield == HOST_FIND_SECURITY)? "HOST_FIND_SECURITY" : - (yield == HOST_FIND_AGAIN)? "HOST_FIND_AGAIN" : - (yield == HOST_FIND_FAILED)? "HOST_FIND_FAILED" : "?", + yield == HOST_FOUND ? "HOST_FOUND" : + yield == HOST_FOUND_LOCAL ? "HOST_FOUND_LOCAL" : + yield == HOST_FIND_SECURITY ? "HOST_FIND_SECURITY" : + yield == HOST_FIND_AGAIN ? "HOST_FIND_AGAIN" : + yield == HOST_FIND_FAILED ? "HOST_FIND_FAILED" : "?", yield); for (h = host; h != last->next; h = h->next) { @@ -3194,7 +3163,7 @@ return yield; int main(int argc, char **cargv) { host_item h; -int whichrrs = HOST_FIND_BY_MX | HOST_FIND_BY_A; +int whichrrs = HOST_FIND_BY_MX | HOST_FIND_BY_A | HOST_FIND_BY_AAAA; BOOL byname = FALSE; BOOL qualify_single = TRUE; BOOL search_parents = FALSE; @@ -3236,15 +3205,15 @@ while (Ufgets(buffer, 256, stdin) != NULL) if (Ustrcmp(buffer, "byname") == 0) byname = TRUE; else if (Ustrcmp(buffer, "no_byname") == 0) byname = FALSE; - else if (Ustrcmp(buffer, "a_only") == 0) whichrrs = HOST_FIND_BY_A; + else if (Ustrcmp(buffer, "a_only") == 0) whichrrs = HOST_FIND_BY_A | HOST_FIND_BY_AAAA; else if (Ustrcmp(buffer, "mx_only") == 0) whichrrs = HOST_FIND_BY_MX; else if (Ustrcmp(buffer, "srv_only") == 0) whichrrs = HOST_FIND_BY_SRV; else if (Ustrcmp(buffer, "srv+a") == 0) - whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_A; + whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_A | HOST_FIND_BY_AAAA; else if (Ustrcmp(buffer, "srv+mx") == 0) 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; + whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_MX | HOST_FIND_BY_A | HOST_FIND_BY_AAAA; 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; @@ -3254,7 +3223,7 @@ while (Ufgets(buffer, 256, stdin) != NULL) else if (Ustrcmp(buffer, "require_dnssec") == 0) require_dnssec = TRUE; else if (Ustrcmp(buffer, "no_require_dnssec") == 0) require_dnssec = FALSE; else if (Ustrcmp(buffer, "test_harness") == 0) - running_in_test_harness = !running_in_test_harness; + f.running_in_test_harness = !f.running_in_test_harness; else if (Ustrcmp(buffer, "ipv6") == 0) disable_ipv6 = !disable_ipv6; else if (Ustrcmp(buffer, "res_debug") == 0) { @@ -3310,7 +3279,6 @@ printf("Testing host_aton\n"); printf("> "); while (Ufgets(buffer, 256, stdin) != NULL) { - int i; int x[4]; int len = Ustrlen(buffer); @@ -3321,7 +3289,7 @@ while (Ufgets(buffer, 256, stdin) != NULL) len = host_aton(buffer, x); printf("length = %d ", len); - for (i = 0; i < len; i++) + for (int i = 0; i < len; i++) { printf("%04x ", (x[i] >> 16) & 0xffff); printf("%04x ", x[i] & 0xffff);