X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/eb24befc3e9ad0a36ef8f0bc3527a9bc6c923a7b..1d28cc061677bd07d9bed48dd84bd5c590247043:/src/src/dns.c diff --git a/src/src/dns.c b/src/src/dns.c index d036162cb..4e01d8661 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -2,8 +2,10 @@ * Exim - an Internet mail transport agent * *************************************************/ +/* Copyright (c) The Exim Maintainers 2020 - 2022 */ /* Copyright (c) University of Cambridge 1995 - 2018 */ /* See the file NOTICE for conditions of use and distribution. */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* Functions for interfacing with the DNS. */ @@ -257,7 +259,7 @@ else { int v6[4]; - g = string_get_tainted(32, is_tainted(string)); + g = string_get_tainted(32, string); (void)host_aton(string, v6); /* The original specification for IPv6 reverse lookup was to invert each @@ -333,7 +335,6 @@ char * trace = NULL; #ifdef rr_trace # define TRACE DEBUG(D_dns) #else -trace = trace; # define TRACE if (FALSE) #endif @@ -501,6 +502,8 @@ const uschar * auth_name; const uschar * trusted; if (dnsa->answerlen < 0) return FALSE; +/* Beware that newer versions of glibc on Linux will filter out the ad bit +unless their shiny new RES_TRUSTAD bit is set for the resolver. */ if (h->ad) return TRUE; /* If the resolver we ask is authoritative for the domain in question, it may @@ -513,7 +516,7 @@ if ( !h->aa || !(trusted = expand_string(dns_trust_aa)) || !*trusted || !(auth_name = dns_extract_auth_name(dnsa)) - || OK != match_isinlist(auth_name, &trusted, 0, NULL, NULL, + || OK != match_isinlist(auth_name, &trusted, 0, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL) ) return FALSE; @@ -635,7 +638,7 @@ if ((previous = tree_search(tree_dns_fails, node_name))) e = previous->data.ptr; else { - e = store_get_perm(DNS_FAILNODE_SIZE, is_tainted(name)); + e = store_get_perm(DNS_FAILNODE_SIZE, name); new = (void *)(e+1); dns_fail_tag(new->name, name, type); new->data.ptr = e; @@ -669,13 +672,10 @@ e = previous->data.ptr; val = e->data.val; rc = e->expiry && e->expiry <= time(NULL) ? -1 : val; -DEBUG(D_dns) debug_printf("DNS lookup of %.255s-%s: %scached value %s%s\n", +DEBUG(D_dns) debug_printf("DNS lookup of %.255s (%s): %scached value %s%s\n", name, dns_text_type(type), rc == -1 ? "" : "using ", - val == DNS_NOMATCH ? "DNS_NOMATCH" : - val == DNS_NODATA ? "DNS_NODATA" : - val == DNS_AGAIN ? "DNS_AGAIN" : - val == DNS_FAIL ? "DNS_FAIL" : "??", + dns_rc_names[val], rc == -1 ? " past valid time" : ""); return rc; @@ -692,9 +692,11 @@ packet length has been lost inside libresolv, so we have to guess a replacement value. (The only way to fix this properly would be to re-implement res_search() and res_query() so that they don't muddle their success and packet length return values.) For added safety we only reset -the packet length if the packet header looks plausible. */ +the packet length if the packet header looks plausible. -static void +Return TRUE iff it seemed ok */ + +static BOOL fake_dnsa_len_for_fail(dns_answer * dnsa, int type) { const HEADER * h = (const HEADER *)dnsa->answer; @@ -711,7 +713,11 @@ if ( h->qr == 1 /* a response */ DEBUG(D_dns) debug_printf("faking res_search(%s) response length as %d\n", dns_text_type(type), (int)sizeof(dnsa->answer)); dnsa->answerlen = sizeof(dnsa->answer); + return TRUE; } +DEBUG(D_dns) debug_printf("DNS: couldn't fake dnsa len\n"); +/* Maybe we should just do a second lookup for an SOA? */ +return FALSE; } @@ -725,37 +731,37 @@ dns_expire_from_soa(dns_answer * dnsa, int type) { dns_scan dnss; -fake_dnsa_len_for_fail(dnsa, type); +if (fake_dnsa_len_for_fail(dnsa, type)) + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY); + rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT) + ) if (rr->type == T_SOA) + { + const uschar * p = rr->data; + uschar discard_buf[256]; + int len; + unsigned long ttl; + + /* Skip the mname & rname strings */ + + if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, + p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0) + break; + p += len; + if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, + p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0) + break; + p += len; + + /* Skip the SOA serial, refresh, retry & expire. Grab the TTL */ + + if (p > dnsa->answer + dnsa->answerlen - 5 * INT32SZ) + break; + p += 4 * INT32SZ; + GETLONG(ttl, p); + + return time(NULL) + ttl; + } -for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY); - rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT) - ) if (rr->type == T_SOA) - { - const uschar * p = rr->data; - uschar discard_buf[256]; - int len; - unsigned long ttl; - - /* Skip the mname & rname strings */ - - if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, - p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0) - break; - p += len; - if ((len = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, - p, (DN_EXPAND_ARG4_TYPE)discard_buf, 256)) < 0) - break; - p += len; - - /* Skip the SOA serial, refresh, retry & expire. Grab the TTL */ - - if (p > dnsa->answer + dnsa->answerlen - 5 * INT32SZ) - break; - p += 4 * INT32SZ; - GETLONG(ttl, p); - - return time(NULL) + ttl; - } DEBUG(D_dns) debug_printf("DNS: no SOA record found for neg-TTL\n"); return 0; } @@ -845,11 +851,8 @@ more.) */ if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT) { - int ovector[3*(EXPAND_MAXN+1)]; - dns_pattern_init(); - if (pcre_exec(regex_check_dns_names, NULL, CCS name, Ustrlen(name), - 0, PCRE_EOPT, ovector, nelem(ovector)) < 0) + if (!regex_match(regex_check_dns_names, name, -1, NULL)) { DEBUG(D_dns) debug_printf("DNS name syntax check failed: %s (%s)\n", name, @@ -905,8 +908,8 @@ if (dnsa->answerlen < 0) switch (h_errno) #ifndef STAND_ALONE save_domain = deliver_domain; deliver_domain = string_copy(name); /* set $domain */ - rc = match_isinlist(name, (const uschar **)&dns_again_means_nonexist, 0, NULL, NULL, - MCL_DOMAIN, TRUE, NULL); + rc = match_isinlist(name, CUSS &dns_again_means_nonexist, 0, + &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL); deliver_domain = save_domain; if (rc != OK) { @@ -1063,7 +1066,7 @@ for (int i = 0; i <= dns_cname_loops; i++) return DNS_FAIL; /* DNS data comes from the outside, hence tainted */ - data = store_get(256, TRUE); + data = store_get(256, GET_TAINTED); if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen, cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0) return DNS_FAIL; @@ -1146,7 +1149,7 @@ switch (type) case T_CSA: { uschar *srvname, *namesuff, *tld; - int priority, weight, port; + int priority, dummy_weight, port; int limit, rc, i; BOOL ipv6; dns_record *rr; @@ -1200,18 +1203,7 @@ switch (type) If the TLD and the 2LD exist but the explicit CSA record lookup failed, then the AUTHORITY SOA will be the 2LD's or a subdomain thereof. */ - if (rc == DNS_NOMATCH) - { - fake_dnsa_len_for_fail(dnsa, T_CSA); - - for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY); - rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT) - ) - if (rr->type != T_SOA) continue; - else if (strcmpic(rr->name, US"") == 0 || - strcmpic(rr->name, tld) == 0) return DNS_NOMATCH; - else break; - } + if (rc == DNS_NOMATCH) return DNS_NOMATCH; for (i = 0; i < limit; i++) { @@ -1246,7 +1238,7 @@ switch (type) /* Extract the numerical SRV fields (p is incremented) */ GETSHORT(priority, p); - GETSHORT(weight, p); weight = weight; /* compiler quietening */ + GETSHORT(dummy_weight, p); GETSHORT(port, p); /* Check the CSA version number */ @@ -1302,7 +1294,7 @@ if (rr->type == T_A) if (p + 4 <= dnsa_lim) { /* the IP is not regarded as tainted */ - yield = store_get(sizeof(dns_address) + 20, FALSE); + yield = store_get(sizeof(dns_address) + 20, GET_UNTAINTED); (void)sprintf(CS yield->address, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); yield->next = NULL; } @@ -1316,7 +1308,7 @@ else { struct in6_addr in6; for (int i = 0; i < 16; i++) in6.s6_addr[i] = rr->data[i]; - yield = store_get(sizeof(dns_address) + 50, FALSE); + yield = store_get(sizeof(dns_address) + 50, GET_UNTAINTED); inet_ntop(AF_INET6, &in6, CS yield->address, 50); yield->next = NULL; } @@ -1333,7 +1325,7 @@ dns_pattern_init(void) { if (check_dns_names_pattern[0] != 0 && !regex_check_dns_names) regex_check_dns_names = - regex_must_compile(check_dns_names_pattern, FALSE, TRUE); + regex_must_compile(check_dns_names_pattern, MCS_NOFLAGS, TRUE); } /* vi: aw ai sw=2