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)
if (r <= 0)
return r;
- r = dns_name_endswith(name, dns_resource_key_name(rr->key));
+ r = dns_name_common_suffix(name, dns_resource_key_name(rr->key), &common_suffix1);
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, 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 dns_name_between(dns_resource_key_name(rr->key), wc, rr->nsec.next_domain_name);
+ return 0;
}
int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
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;
+ }
}
}