resolved: make sure the NSEC proof-of-non-existance check also looks for wildcard domains
This commit is contained in:
parent
b9282bc128
commit
d86c982a34
|
@ -1617,7 +1617,7 @@ found_closest_encloser:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) {
|
||||
static int dnssec_nsec_test_in_path(DnsResourceRecord *rr, const char *name) {
|
||||
const char *nn, *common_suffix;
|
||||
int r;
|
||||
|
||||
|
@ -1653,9 +1653,38 @@ static int dnssec_nsec_in_path(DnsResourceRecord *rr, const char *name) {
|
|||
return dns_name_endswith(name, common_suffix);
|
||||
}
|
||||
|
||||
static int dns_dnssec_test_wildcard_at_closest_encloser(DnsResourceRecord *rr, const char *name) {
|
||||
const char *common_suffix, *wc;
|
||||
int r;
|
||||
|
||||
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...
|
||||
*/
|
||||
|
||||
r = dns_name_common_suffix(DNS_RESOURCE_KEY_NAME(rr->key), rr->nsec.next_domain_name, &common_suffix);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* If the common suffix is not shared by the name we are interested in, it has nothing to say for us. */
|
||||
r = dns_name_endswith(name, common_suffix);
|
||||
if (r <= 0)
|
||||
return r;
|
||||
|
||||
wc = strjoina("*.", common_suffix, NULL);
|
||||
return dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), wc, rr->nsec.next_domain_name);
|
||||
}
|
||||
|
||||
int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *result, bool *authenticated, uint32_t *ttl) {
|
||||
bool have_nsec3 = false;
|
||||
DnsResourceRecord *rr;
|
||||
bool have_nsec3 = false, covering_rr_authenticated = false, wildcard_rr_authenticated = false;
|
||||
DnsResourceRecord *rr, *covering_rr = NULL, *wildcard_rr = NULL;
|
||||
DnsAnswerFlags flags;
|
||||
const char *name;
|
||||
int r;
|
||||
|
@ -1708,9 +1737,13 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* The following three checks only make sense for NSEC RRs that are not expanded from a wildcard */
|
||||
if (rr->n_skip_labels_source != 0)
|
||||
continue;
|
||||
|
||||
/* Check if the name we are looking for is an empty non-terminal within the owner or next name
|
||||
* of the NSEC RR. */
|
||||
r = dnssec_nsec_in_path(rr, name);
|
||||
r = dnssec_nsec_test_in_path(rr, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) {
|
||||
|
@ -1724,18 +1757,25 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Check if this NSEC RR proves the absence of an explicit RR under this name */
|
||||
r = dns_name_between(DNS_RESOURCE_KEY_NAME(rr->key), name, rr->nsec.next_domain_name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
*result = DNSSEC_NSEC_NXDOMAIN;
|
||||
if (r > 0 && (!covering_rr || !covering_rr_authenticated)) {
|
||||
covering_rr = rr;
|
||||
covering_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
|
||||
}
|
||||
|
||||
if (authenticated)
|
||||
*authenticated = flags & DNS_ANSWER_AUTHENTICATED;
|
||||
if (ttl)
|
||||
*ttl = rr->ttl;
|
||||
/* Check if this NSEC RR proves the absence of a wildcard RR under this name */
|
||||
r = dns_dnssec_test_wildcard_at_closest_encloser(rr, name);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0 && (!wildcard_rr || !wildcard_rr_authenticated)) {
|
||||
wildcard_rr = rr;
|
||||
wildcard_rr_authenticated = flags & DNS_ANSWER_AUTHENTICATED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
break;
|
||||
|
||||
case DNS_TYPE_NSEC3:
|
||||
have_nsec3 = true;
|
||||
|
@ -1743,6 +1783,19 @@ int dnssec_nsec_test(DnsAnswer *answer, DnsResourceKey *key, DnssecNsecResult *r
|
|||
}
|
||||
}
|
||||
|
||||
if (covering_rr && wildcard_rr) {
|
||||
/* If we could prove that neither the name itself, nor the wildcard at the closest encloser exists, we
|
||||
* proved the NXDOMAIN case. */
|
||||
*result = DNSSEC_NSEC_NXDOMAIN;
|
||||
|
||||
if (authenticated)
|
||||
*authenticated = covering_rr_authenticated && wildcard_rr_authenticated;
|
||||
if (ttl)
|
||||
*ttl = MIN(covering_rr->ttl, wildcard_rr->ttl);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* OK, this was not sufficient. Let's see if NSEC3 can help. */
|
||||
if (have_nsec3)
|
||||
return dnssec_test_nsec3(answer, key, result, authenticated, ttl);
|
||||
|
|
Loading…
Reference in a new issue