resolved: make sure the NSEC proof-of-non-existance check also looks for wildcard domains

This commit is contained in:
Lennart Poettering 2016-01-14 21:05:57 +01:00
parent b9282bc128
commit d86c982a34
1 changed files with 64 additions and 11 deletions

View File

@ -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);