resolved: when we find a DNAME RR, don't insist in a signed CNAME RR

If we have a signed DNAME RR response, there's no need to insist on a signature for a CNAME RR response, after all it
is unlikely to be signed, given the implicit synthethis of CNAME through DNAME RRs.
This commit is contained in:
Lennart Poettering 2016-01-17 21:50:10 +01:00
parent cde3d68750
commit 43e6779ac2
3 changed files with 67 additions and 9 deletions

View File

@ -821,3 +821,40 @@ void dns_answer_dump(DnsAnswer *answer, FILE *f) {
fputc('\n', f);
}
}
bool dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname) {
DnsResourceRecord *rr;
int r;
assert(cname);
/* Checks whether the answer contains a DNAME record that indicates that the specified CNAME record is
* synthesized from it */
if (cname->key->type != DNS_TYPE_CNAME)
return 0;
DNS_ANSWER_FOREACH(rr, a) {
_cleanup_free_ char *n = NULL;
if (rr->key->type != DNS_TYPE_DNAME)
continue;
if (rr->key->class != cname->key->class)
continue;
r = dns_name_change_suffix(cname->cname.name, rr->dname.name, DNS_RESOURCE_KEY_NAME(rr->key), &n);
if (r < 0)
return r;
if (r == 0)
continue;
r = dns_name_equal(n, DNS_RESOURCE_KEY_NAME(cname->key));
if (r < 0)
return r;
if (r > 0)
return 1;
}
return 0;
}

View File

@ -83,6 +83,8 @@ int dns_answer_remove_by_rr(DnsAnswer **a, DnsResourceRecord *rr);
int dns_answer_copy_by_key(DnsAnswer **a, DnsAnswer *source, const DnsResourceKey *key, DnsAnswerFlags or_flags);
int dns_answer_move_by_key(DnsAnswer **to, DnsAnswer **from, const DnsResourceKey *key, DnsAnswerFlags or_flags);
bool dns_answer_has_dname_for_cname(DnsAnswer *a, DnsResourceRecord *cname);
static inline unsigned dns_answer_size(DnsAnswer *a) {
return a ? a->n_rrs : 0;
}

View File

@ -1827,6 +1827,12 @@ int dns_transaction_request_dnssec_keys(DnsTransaction *t) {
if (r > 0)
continue;
r = dns_answer_has_dname_for_cname(t->answer, rr);
if (r < 0)
return r;
if (r > 0)
continue;
name = DNS_RESOURCE_KEY_NAME(rr->key);
r = dns_name_parent(&name);
if (r < 0)
@ -2719,17 +2725,30 @@ int dns_transaction_validate_dnssec(DnsTransaction *t) {
if (r < 0)
return r;
if (r > 0) {
/* This is a primary response
* to our question, and it
* failed validation. That's
* fatal. */
t->answer_dnssec_result = result;
return 0;
/* Look for a matching DNAME for this CNAME */
r = dns_answer_has_dname_for_cname(t->answer, rr);
if (r < 0)
return r;
if (r == 0) {
/* Also look among the stuff we already validated */
r = dns_answer_has_dname_for_cname(validated, rr);
if (r < 0)
return r;
}
if (r == 0) {
/* This is a primary response to our question, and it failed validation. That's
* fatal. */
t->answer_dnssec_result = result;
return 0;
}
/* This is a primary response, but we do have a DNAME RR in the RR that can replay this
* CNAME, hence rely on that, and we can remove the CNAME in favour of it. */
}
/* This is just some auxiliary
* data. Just remove the RRset and
* continue. */
/* This is just some auxiliary data. Just remove the RRset and continue. */
r = dns_answer_remove_by_key(&t->answer, rr->key);
if (r < 0)
return r;