diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index f90ca670194..c2fd0c078f4 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -22,6 +22,10 @@ typedef enum DnsAnswerFlags { DNS_ANSWER_SECTION_ANSWER = 1 << 5, /* When parsing: RR originates from answer section */ DNS_ANSWER_SECTION_AUTHORITY = 1 << 6, /* When parsing: RR originates from authority section */ DNS_ANSWER_SECTION_ADDITIONAL = 1 << 7, /* When parsing: RR originates from additional section */ + + DNS_ANSWER_MASK_SECTIONS = DNS_ANSWER_SECTION_ANSWER| + DNS_ANSWER_SECTION_AUTHORITY| + DNS_ANSWER_SECTION_ADDITIONAL, } DnsAnswerFlags; struct DnsAnswerItem { diff --git a/src/resolve/resolved-dns-stub.c b/src/resolve/resolved-dns-stub.c index 4f2088bb769..78f7cb854f4 100644 --- a/src/resolve/resolved-dns-stub.c +++ b/src/resolve/resolved-dns-stub.c @@ -139,12 +139,38 @@ static int stub_packet_compare_func(const DnsPacket *x, const DnsPacket *y) { DEFINE_HASH_OPS(stub_packet_hash_ops, DnsPacket, stub_packet_hash_func, stub_packet_compare_func); +static int reply_add_with_rrsig( + DnsAnswer **reply, + DnsResourceRecord *rr, + int ifindex, + DnsAnswerFlags flags, + DnsResourceRecord *rrsig, + bool with_rrsig) { + int r; + + assert(reply); + assert(rr); + + r = dns_answer_add_extend(reply, rr, ifindex, flags, rrsig); + if (r < 0) + return r; + + if (with_rrsig && rrsig) { + r = dns_answer_add_extend(reply, rrsig, ifindex, flags, NULL); + if (r < 0) + return r; + } + + return 0; +} + static int dns_stub_collect_answer_by_question( DnsAnswer **reply, DnsAnswer *answer, DnsQuestion *question, bool with_rrsig) { /* Add RRSIG RR matching each RR */ + _cleanup_(dns_resource_key_unrefp) DnsResourceKey *redirected_key = NULL; DnsAnswerItem *item; int r; @@ -153,36 +179,71 @@ static int dns_stub_collect_answer_by_question( /* Copies all RRs from 'answer' into 'reply', if they match 'question'. */ DNS_ANSWER_FOREACH_ITEM(item, answer) { - if (question) { - bool match = false; - r = dns_question_matches_rr(question, item->rr, NULL); if (r < 0) return r; - else if (r > 0) - match = true; - else { - r = dns_question_matches_cname_or_dname(question, item->rr, NULL); + if (r == 0) { + _cleanup_free_ char *target = NULL; + + /* OK, so the RR doesn't directly match. Let's see if the RR is a matching + * CNAME or DNAME */ + + r = dns_resource_record_get_cname_target( + question->keys[0], + item->rr, + &target); + if (r == -EUNATCH) + continue; /* Not a CNAME/DNAME or doesn't match */ if (r < 0) return r; - if (r > 0) - match = true; - } - if (!match) - continue; + dns_resource_key_unref(redirected_key); + + /* There can only be one CNAME per name, hence no point in storing more than one here */ + redirected_key = dns_resource_key_new(question->keys[0]->class, question->keys[0]->type, target); + if (!redirected_key) + return -ENOMEM; + } } - r = dns_answer_add_extend(reply, item->rr, item->ifindex, item->flags, item->rrsig); + /* Mask the section info, we want the primary answers to always go without section info, so + * that it is added to the answer section when we synthesize a reply. */ + + r = reply_add_with_rrsig( + reply, + item->rr, + item->ifindex, + item->flags & ~DNS_ANSWER_MASK_SECTIONS, + item->rrsig, + with_rrsig); if (r < 0) return r; + } - if (with_rrsig && item->rrsig) { - r = dns_answer_add_extend(reply, item->rrsig, item->ifindex, item->flags, NULL); - if (r < 0) - return r; - } + if (!redirected_key) + return 0; + + /* This is a CNAME/DNAME answer. In this case also append where the redirections point to to the main + * answer section */ + + DNS_ANSWER_FOREACH_ITEM(item, answer) { + + r = dns_resource_key_match_rr(redirected_key, item->rr, NULL); + if (r < 0) + return r; + if (r == 0) + continue; + + r = reply_add_with_rrsig( + reply, + item->rr, + item->ifindex, + item->flags & ~DNS_ANSWER_MASK_SECTIONS, + item->rrsig, + with_rrsig); + if (r < 0) + return r; } return 0; @@ -197,7 +258,6 @@ static int dns_stub_collect_answer_by_section( bool with_dnssec) { /* Include DNSSEC RRs. RRSIG, NSEC, … */ DnsAnswerItem *item; - unsigned c = 0; int r; assert(reply); @@ -218,22 +278,18 @@ static int dns_stub_collect_answer_by_section( if (((item->flags ^ section) & (DNS_ANSWER_SECTION_ANSWER|DNS_ANSWER_SECTION_AUTHORITY|DNS_ANSWER_SECTION_ADDITIONAL)) != 0) continue; - r = dns_answer_add_extend(reply, item->rr, item->ifindex, item->flags, item->rrsig); + r = reply_add_with_rrsig( + reply, + item->rr, + item->ifindex, + item->flags, + item->rrsig, + with_dnssec); if (r < 0) return r; - - c++; - - if (with_dnssec && item->rrsig) { - r = dns_answer_add_extend(reply, item->rrsig, item->ifindex, item->flags, NULL); - if (r < 0) - return r; - - c++; - } } - return (int) c; + return 0; } static int dns_stub_assign_sections(