diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c index 14acc4e77db..3be18de8417 100644 --- a/src/resolve/resolved-dns-dnssec.c +++ b/src/resolve/resolved-dns-dnssec.c @@ -1797,22 +1797,14 @@ static int dnssec_nsec_covers(DnsResourceRecord *rr, const char *name) { return dns_name_between(dns_resource_key_name(rr->key), name, rr->nsec.next_domain_name); } -static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) { - _cleanup_free_ char *wc = NULL; - const char *common_suffix, *signer; - int r; +static int dnssec_nsec_generate_wildcard(DnsResourceRecord *rr, const char *name, char **wc) { + const char *common_suffix1, *common_suffix2, *signer; + int r, labels1, labels2; assert(rr); assert(rr->key->type == DNS_TYPE_NSEC); - /* Checks whether the "Wildcard at the Closest Encloser" is within the space covered by the specified - * RR. Specifically, checks whether 'name' has the common suffix of the NSEC RR's owner and next names as - * suffix, and whether the NSEC covers the name generated by that suffix prepended with an asterisk label. - * - * NSEC bar → waldo.foo.bar: indicates that *.bar and *.foo.bar do not exist - * NSEC waldo.foo.bar → yyy.zzz.xoo.bar: indicates that *.xoo.bar and *.zzz.xoo.bar do not exist (and more ...) - * NSEC yyy.zzz.xoo.bar → bar: indicates that a number of wildcards don#t exist either... - */ + /* Generates "Wildcard at the Closest Encloser" for the given name and NSEC RR. */ r = dns_resource_record_signer(rr, &signer); if (r < 0) @@ -1822,23 +1814,31 @@ static int dnssec_nsec_covers_wildcard(DnsResourceRecord *rr, const char *name) if (r <= 0) return r; - r = dns_name_endswith(name, dns_resource_key_name(rr->key)); - if (r < 0) - return r; - if (r > 0) /* If the name we are interested in is a child of the NSEC RR, then append the asterisk to the NSEC - * RR's name. */ - r = dns_name_concat("*", dns_resource_key_name(rr->key), 0, &wc); - else { - r = dns_name_common_suffix(dns_resource_key_name(rr->key), rr->nsec.next_domain_name, &common_suffix); - if (r < 0) - return r; - - r = dns_name_concat("*", common_suffix, 0, &wc); - } + r = dns_name_common_suffix(name, dns_resource_key_name(rr->key), &common_suffix1); if (r < 0) return r; - return dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name); + r = dns_name_common_suffix(name, rr->nsec.next_domain_name, &common_suffix2); + if (r < 0) + return r; + + labels1 = dns_name_count_labels(common_suffix1); + if (labels1 < 0) + return labels1; + + labels2 = dns_name_count_labels(common_suffix2); + if (labels2 < 0) + return labels2; + + if (labels1 > labels2) + r = dns_name_concat("*", common_suffix1, 0, wc); + else + r = dns_name_concat("*", common_suffix2, 0, wc); + + if (r < 0) + return r; + + return 0; } int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) { @@ -1942,14 +1942,30 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r covering_rr = rr; covering_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED; } + } - /* Check if this NSEC RR proves the absence of a wildcard RR under this name */ - r = dnssec_nsec_covers_wildcard(rr, name); + if (covering_rr) { + _cleanup_free_ char *wc = NULL; + r = dnssec_nsec_generate_wildcard(covering_rr, name, &wc); if (r < 0) return r; - if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) { - wildcard_rr = rr; - wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED; + + DNS_ANSWER_FOREACH_FLAGS(rr, flags, answer) { + + if (rr->key->class != key->class) + continue; + + if (rr->key->type != DNS_TYPE_NSEC) + continue; + + /* Check if this NSEC RR proves the nonexistence of the wildcard */ + r = dnssec_nsec_covers(rr, wc); + if (r < 0) + return r; + if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) { + wildcard_rr = rr; + wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED; + } } }