X-Git-Url: https://git.exim.org/users/jgh/exim.git/blobdiff_plain/8c513105fde2b8be3397216a0153f9b266fc7dfb..d22c942c4ba0a4e5ace2dfb856a43a19f8ed8b6d:/src/src/host.c diff --git a/src/src/host.c b/src/src/host.c index 06cfe338c..3361d5912 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -138,7 +138,7 @@ if (!slow_lookup_log) time_msec = get_time_in_ms(); retval = dns_lookup(dnsa, name, type, fully_qualified_name); if ((time_msec = get_time_in_ms() - time_msec) > slow_lookup_log) - log_long_lookup(US"name", name, time_msec); + log_long_lookup(dns_text_type(type), name, time_msec); return retval; } @@ -177,9 +177,8 @@ const uschar *lname = name; uschar *adds; uschar **alist; struct hostent *yield; -dns_answer dnsa; +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; -dns_record *rr; DEBUG(D_host_lookup) debug_printf("using host_fake_gethostbyname for %s (%s)\n", name, @@ -192,25 +191,22 @@ 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 *)); - adds = store_get(alen); + yield = store_get(sizeof(struct hostent), FALSE); + alist = store_get(2 * sizeof(char *), FALSE); + adds = store_get(alen, FALSE); 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++) + for (int n = host_aton(lname, x), i = 0; i < n; i++) { int y = x[i]; *adds++ = (y >> 24) & 255; @@ -235,7 +231,7 @@ if (ipa != 0) else { int type = (af == AF_INET)? T_A:T_AAAA; - int rc = dns_lookup_timerwrap(&dnsa, lname, type, NULL); + int rc = dns_lookup_timerwrap(dnsa, lname, type, NULL); int count = 0; lookup_dnssec_authenticated = NULL; @@ -250,15 +246,14 @@ 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 *)); - adds = store_get(count *alen); + yield = store_get(sizeof(struct hostent), FALSE); + alist = store_get((count + 1) * sizeof(char *), FALSE); + adds = store_get(count *alen, FALSE); yield->h_name = CS name; yield->h_aliases = NULL; @@ -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; + 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; @@ -333,7 +325,7 @@ while ((name = string_nextinlist(&list, &sep, NULL, 0)) != NULL) continue; } - h = store_get(sizeof(host_item)); + h = store_get(sizeof(host_item), FALSE); h->name = name; h->address = NULL; h->port = PORT_NONE; @@ -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; @@ -532,12 +524,13 @@ void host_build_sender_fullhost(void) { BOOL show_helo = TRUE; -uschar * address, * fullhost, * rcvhost, * reset_point; +uschar * address, * fullhost, * rcvhost; +rmark reset_point; int len; if (!sender_host_address) return; -reset_point = store_get(0); +reset_point = store_mark(); /* 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 @@ -651,10 +644,8 @@ else } } -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); +sender_fullhost = string_copy_perm(fullhost, TRUE); +sender_rcvhost = string_copy_perm(rcvhost, TRUE); store_reset(reset_point); @@ -676,6 +667,8 @@ return depends on whether sender_fullhost and sender_ident are set or not: ident set, no host => U=ident ident set, host set => H=sender_fullhost U=ident +Use taint-unchecked routines on the assumption we'll never expand the results. + Arguments: useflag TRUE if first item to be flagged (H= or U=); if there are two items, the second is always flagged @@ -686,23 +679,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) + string_format_nt(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 - (void)string_format(big_buffer, big_buffer_size, "%s%s%s U=%s", + if (sender_ident) + string_format_nt(big_buffer, big_buffer_size, "%s%s%s U=%s", flag, sender_fullhost, iface, sender_ident); + else + string_format_nt(big_buffer, big_buffer_size, "%s%s%s", + flag, sender_fullhost, iface); } return big_buffer; } @@ -756,11 +747,12 @@ while ((s = string_nextinlist(&list, &sep, NULL, 0))) address above. The field in the ip_address_item is large enough to hold an IPv6 address. */ - next = store_get(sizeof(ip_address_item)); + next = store_get(sizeof(ip_address_item), FALSE); next->next = NULL; Ustrcpy(next->address, s); next->port = port; next->v6_include_v4 = FALSE; + next->log = NULL; if (!yield) yield = last = next; @@ -807,9 +799,9 @@ 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 = store_get_perm(sizeof(ip_address_item), FALSE); *ipa2 = *ipa; ipa2->next = list; return ipa2; @@ -825,34 +817,32 @@ ip_address_item *running_interfaces = NULL; if (local_interface_data == NULL) { - void *reset_item = store_get(0); + void *reset_item = store_mark(); ip_address_item *dlist = host_build_ifacelist(CUS local_interfaces, US"local_interfaces"); ip_address_item *xlist = host_build_ifacelist(CUS extra_local_interfaces, 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 { @@ -955,13 +945,15 @@ else /* If there is no buffer, put the string into some new store. */ -if (buffer == NULL) return string_copy(yield); +if (!buffer) buffer = store_get(46, FALSE); /* Callers of this function with a non-NULL buffer must ensure that it is large enough to hold an IPv6 address, namely, at least 46 bytes. That's what -makes this use of strcpy() OK. */ +makes this use of strcpy() OK. +If the library returned apparently an apparently tainted string, clean it; +we trust IP addresses. */ -Ustrcpy(buffer, yield); +string_format_nt(buffer, 46, "%s", yield); return buffer; } @@ -1090,9 +1082,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; @@ -1139,17 +1130,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); @@ -1279,7 +1270,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; @@ -1312,7 +1302,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; @@ -1407,9 +1397,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 */ } @@ -1514,9 +1503,7 @@ Returns: OK, DEFER, FAIL static int host_name_lookup_byaddr(void) { -int len; -uschar *s, *t; -struct hostent *hosts; +struct hostent * hosts; struct in_addr addr; unsigned long time_msec = 0; /* init to quieten dumb static analysis */ @@ -1559,11 +1546,11 @@ hosts = gethostbyaddr(CS(&addr), sizeof(addr), AF_INET); if ( slow_lookup_log && (time_msec = get_time_in_ms() - time_msec) > slow_lookup_log ) - log_long_lookup(US"name", sender_host_address, time_msec); + log_long_lookup(US"gethostbyaddr", sender_host_address, time_msec); /* Failed to look up the host. */ -if (hosts == NULL) +if (!hosts) { HDEBUG(D_host_lookup) debug_printf("IP address lookup failed: h_errno=%d\n", h_errno); @@ -1574,7 +1561,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 == NULL || hosts->h_name[0] == 0 || hosts->h_name[0] == '.') +if (!hosts->h_name || !hosts->h_name[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"); @@ -1584,29 +1571,29 @@ if (hosts->h_name == NULL || hosts->h_name[0] == 0 || hosts->h_name[0] == '.') /* Copy and lowercase the name, which is in static storage in many systems. Put it in permanent memory. */ -s = US hosts->h_name; -len = Ustrlen(s) + 1; -t = sender_host_name = store_get_perm(len); -while (*s != 0) *t++ = tolower(*s++); -*t = 0; + { + int old_pool = store_pool; + store_pool = POOL_TAINT_PERM; /* names are tainted */ -/* If the host has aliases, build a copy of the alias list */ + sender_host_name = string_copylc(US hosts->h_name); -if (hosts->h_aliases != NULL) - { - int count = 1; - uschar **aliases, **ptr; - for (aliases = USS hosts->h_aliases; *aliases != NULL; aliases++) count++; - ptr = sender_host_aliases = store_get_perm(count * sizeof(uschar *)); - for (aliases = USS hosts->h_aliases; *aliases != NULL; aliases++) - { - uschar *s = *aliases; - int len = Ustrlen(s) + 1; - uschar *t = *ptr++ = store_get_perm(len); - while (*s != 0) *t++ = tolower(*s++); - *t = 0; - } - *ptr = NULL; + /* If the host has aliases, build a copy of the alias list */ + + if (hosts->h_aliases) + { + int count = 1; + uschar **ptr; + + for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++) count++; + store_pool = POOL_PERM; + ptr = sender_host_aliases = store_get(count * sizeof(uschar *), FALSE); + store_pool = POOL_TAINT_PERM; + + for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++) + *ptr++ = string_copylc(*aliases); + *ptr = NULL; + } + store_pool = old_pool; } return OK; @@ -1657,13 +1644,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_answer * dnsa = store_get_dns_answer(); dns_scan dnss; sender_host_dnssec = host_lookup_deferred = host_lookup_failed = FALSE; @@ -1686,13 +1671,14 @@ if (f.running_in_test_harness && /* Do lookups directly in the DNS or via gethostbyaddr() (or equivalent), in the order specified by the host_lookup_order option. */ -while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) +while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) { if (strcmpic(ordername, US"bydns") == 0) { + uschar * name = dns_build_reverse(sender_host_address); + dns_init(FALSE, FALSE, FALSE); /* dnssec ctrl by dns_dnssec_ok glbl */ - dns_build_reverse(sender_host_address, buffer); - rc = dns_lookup_timerwrap(&dnsa, buffer, T_PTR, NULL); + rc = dns_lookup_timerwrap(dnsa, name, T_PTR, NULL); /* The first record we come across is used for the name; others are considered to be aliases. We have to scan twice, in order to find out the @@ -1707,38 +1693,35 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) int count = 0; int old_pool = store_pool; - sender_host_dnssec = dns_is_secure(&dnsa); + 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); + 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. */ - aptr = sender_host_aliases = store_get(count * sizeof(uschar *)); + aptr = sender_host_aliases = store_get(count * sizeof(uschar *), FALSE); /* 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, TRUE); /* names are tainted */ /* If an overlong response was received, the data will have been truncated and dn_expand may fail. */ - if (dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, + if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, US (rr->data), (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0) { log_write(0, LOG_MAIN, "host name alias list truncated for %s", @@ -1746,8 +1729,8 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) break; } - store_reset(s + Ustrlen(s) + 1); - if (s[0] == 0) + store_release_above(s + Ustrlen(s) + 1); + if (!s[0]) { HDEBUG(D_host_lookup) debug_printf("IP address lookup yielded an " "empty name: treated as non-existent host name\n"); @@ -1755,15 +1738,15 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) } if (!sender_host_name) sender_host_name = s; else *aptr++ = s; - while (*s != 0) { *s = tolower(*s); s++; } + while (*s) { *s = tolower(*s); s++; } } *aptr = NULL; /* End of alias list */ store_pool = old_pool; /* Reset store pool */ - /* If we've found a names, break out of the "order" loop */ + /* If we've found a name, break out of the "order" loop */ - if (sender_host_name != NULL) break; + if (sender_host_name) break; } /* If the DNS lookup deferred, we must also defer. */ @@ -1828,7 +1811,7 @@ 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; @@ -1841,7 +1824,6 @@ for (hname = sender_host_name; hname; hname = *aliases++) || 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 */ @@ -1850,7 +1832,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); @@ -1961,8 +1943,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 @@ -2009,7 +1990,7 @@ 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 @@ -2051,7 +2032,7 @@ for (i = 1; i <= times; if ( slow_lookup_log && (time_msec = get_time_in_ms() - time_msec) > slow_lookup_log) - log_long_lookup(US"name", host->name, time_msec); + log_long_lookup(US"gethostbyname", host->name, time_msec); if (hostdata == NULL) { @@ -2099,7 +2080,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); @@ -2133,7 +2114,7 @@ for (i = 1; i <= times; else { - host_item *next = store_get(sizeof(host_item)); + host_item *next = store_get(sizeof(host_item), FALSE); next->name = host->name; next->mx = host->mx; next->address = text_address; @@ -2179,8 +2160,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 @@ -2193,9 +2173,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. */ @@ -2274,7 +2254,6 @@ set_address_from_dns(host_item *host, host_item **lastptr, const uschar **fully_qualified_name, 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; @@ -2328,17 +2307,17 @@ for (; i >= 0; i--) int type = types[i]; int randoffset = i == (whichrrs & HOST_FIND_IPV4_FIRST ? 1 : 0) ? 500 : 0; /* Ensures v6/4 sort order */ - dns_answer dnsa; + dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; - int rc = dns_lookup_timerwrap(&dnsa, host->name, type, fully_qualified_name); + int rc = dns_lookup_timerwrap(dnsa, host->name, type, fully_qualified_name); lookup_dnssec_authenticated = !dnssec_request ? NULL - : dns_is_secure(&dnsa) ? US"yes" : US"no"; + : dns_is_secure(dnsa) ? US"yes" : US"no"; DEBUG(D_dns) if ( (dnssec_request || dnssec_require) - && !dns_is_secure(&dnsa) - && dns_is_aa(&dnsa) + && !dns_is_secure(dnsa) + && dns_is_aa(dnsa) ) debug_printf("DNS lookup of %.256s (A/AAAA) requested AD, but got AA\n", host->name); @@ -2366,7 +2345,7 @@ for (; i >= 0; i--) if (dnssec_request) { - if (dns_is_secure(&dnsa)) + if (dns_is_secure(dnsa)) { DEBUG(D_host_lookup) debug_printf("%s A DNSSEC\n", host->name); if (host->dnssec == DS_UNK) /* set in host_find_bydns() */ @@ -2397,104 +2376,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), FALSE); + + /* 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 */ + } + } } } } @@ -2563,11 +2539,10 @@ 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; -dns_answer dnsa; +dns_answer * dnsa = store_get_dns_answer(); dns_scan dnss; BOOL dnssec_require = dnssec_d && match_isinlist(host->name, CUSS &dnssec_d->require, @@ -2609,18 +2584,18 @@ if (whichrrs & HOST_FIND_BY_SRV) dnssec = DS_UNK; lookup_dnssec_authenticated = NULL; - rc = dns_lookup_timerwrap(&dnsa, temp_fully_qualified_name, ind_type, + rc = dns_lookup_timerwrap(dnsa, temp_fully_qualified_name, ind_type, CUSS &temp_fully_qualified_name); DEBUG(D_dns) if ((dnssec_request || dnssec_require) - && !dns_is_secure(&dnsa) - && dns_is_aa(&dnsa)) + && !dns_is_secure(dnsa) + && dns_is_aa(dnsa)) debug_printf("DNS lookup of %.256s (SRV) requested AD, but got AA\n", host->name); if (dnssec_request) { - if (dns_is_secure(&dnsa)) + if (dns_is_secure(dnsa)) { dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } else { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } @@ -2632,7 +2607,7 @@ if (whichrrs & HOST_FIND_BY_SRV) /* 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)) + 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); @@ -2662,18 +2637,18 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) ind_type = T_MX; dnssec = DS_UNK; lookup_dnssec_authenticated = NULL; - rc = dns_lookup_timerwrap(&dnsa, host->name, ind_type, fully_qualified_name); + rc = dns_lookup_timerwrap(dnsa, host->name, ind_type, fully_qualified_name); DEBUG(D_dns) if ( (dnssec_request || dnssec_require) - && !dns_is_secure(&dnsa) - && dns_is_aa(&dnsa)) + && !dns_is_secure(dnsa) + && dns_is_aa(dnsa)) debug_printf("DNS lookup of %.256s (MX) requested AD, but got AA\n", host->name); if (dnssec_request) - if (dns_is_secure(&dnsa)) + if (dns_is_secure(dnsa)) { - DEBUG(D_host_lookup) debug_printf("%s MX DNSSEC\n", host->name); + DEBUG(D_host_lookup) debug_printf("%s (MX resp) DNSSEC\n", host->name); dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } else @@ -2687,7 +2662,7 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) yield = HOST_FIND_FAILED; goto out; case DNS_SUCCEED: - if (!dnssec_require || dns_is_secure(&dnsa)) + if (!dnssec_require || dns_is_secure(dnsa)) break; DEBUG(D_host_lookup) debug_printf("dnssec fail on MX for %.256s", host->name); @@ -2745,18 +2720,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; @@ -2784,9 +2756,9 @@ 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) + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) if (rr->type == ind_type) { int precedence, weight; int port = PORT_NONE; @@ -2811,7 +2783,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); /* Get the name of the host pointed to. */ - (void)dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen, s, + (void)dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, s, (DN_EXPAND_ARG4_TYPE)data, sizeof(data)); /* Check that we haven't already got this host on the chain; if we have, @@ -2867,7 +2839,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); /* Make a new host item and seek the correct insertion place */ { int sort_key = precedence * 1000 + weight; - host_item *next = store_get(sizeof(host_item)); + host_item *next = store_get(sizeof(host_item), FALSE); next->name = string_copy_dnsdomain(data); next->address = NULL; next->port = port; @@ -2933,7 +2905,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) { @@ -3156,14 +3128,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) { @@ -3182,6 +3154,79 @@ dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ return yield; } + + + +#ifdef SUPPORT_DANE +/* Lookup TLSA record for host/port. +Return: OK success with dnssec; DANE mode + DEFER Do not use this host now, may retry later + FAIL_FORCED No TLSA record; DANE not usable + FAIL Do not use this connection +*/ + +int +tlsa_lookup(const host_item * host, dns_answer * dnsa, BOOL dane_required) +{ +uschar buffer[300]; +const uschar * fullname = buffer; +int rc; +BOOL sec; + +/* TLSA lookup string */ +(void)sprintf(CS buffer, "_%d._tcp.%.256s", host->port, host->name); + +rc = dns_lookup_timerwrap(dnsa, buffer, T_TLSA, &fullname); +sec = dns_is_secure(dnsa); +DEBUG(D_transport) + debug_printf("TLSA lookup ret %d %sDNSSEC\n", rc, sec ? "" : "not "); + +switch (rc) + { + case DNS_AGAIN: + return DEFER; /* just defer this TLS'd conn */ + + case DNS_SUCCEED: + if (sec) + { + DEBUG(D_transport) + { + dns_scan dnss; + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) + if (rr->type == T_TLSA && rr->size > 3) + { + uint16_t payload_length = rr->size - 3; + uschar s[MAX_TLSA_EXPANDED_SIZE], * sp = s, * p = US rr->data; + + sp += sprintf(CS sp, "%d ", *p++); /* usage */ + sp += sprintf(CS sp, "%d ", *p++); /* selector */ + sp += sprintf(CS sp, "%d ", *p++); /* matchtype */ + while (payload_length-- > 0 && sp-s < (MAX_TLSA_EXPANDED_SIZE - 4)) + sp += sprintf(CS sp, "%02x", *p++); + + debug_printf(" %s\n", s); + } + } + return OK; + } + log_write(0, LOG_MAIN, + "DANE error: TLSA lookup for %s not DNSSEC", host->name); + /*FALLTRHOUGH*/ + + case DNS_NODATA: /* no TLSA RR for this lookup */ + case DNS_NOMATCH: /* no records at all for this lookup */ + return dane_required ? FAIL : FAIL_FORCED; + + default: + case DNS_FAIL: + return dane_required ? FAIL : DEFER; + } +} +#endif /*SUPPORT_DANE*/ + + + /************************************************* ************************************************** * Stand-alone test program * @@ -3309,7 +3354,6 @@ printf("Testing host_aton\n"); printf("> "); while (Ufgets(buffer, 256, stdin) != NULL) { - int i; int x[4]; int len = Ustrlen(buffer); @@ -3320,7 +3364,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);