resolved: gracefully handle with packets with too large RR count

Apparently, there are plenty routers in place that report an incorrect
RR count in the packets: they declare more RRs than are actually
included.

Let's accept these responses, but let's downgrade them to baseline, i.e.
let's suppress OPT in this case: if they don't even get the RR count
right, let's operate on the absolute baseline, and not bother with
anything fancier such as EDNS.

Prompted-by: https://github.com/systemd/systemd/issues/12841#issuecomment-724063973

Fixes: #3980
Most likely fixes: #12841
This commit is contained in:
Lennart Poettering
2021-02-14 23:05:28 +01:00
parent 8c9c68b593
commit 18674159eb
+15 -1
View File
@@ -2253,6 +2253,18 @@ static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) {
bool cache_flush = false;
size_t start;
if (p->rindex == p->size) {
/* If we reached the end of the packet already, but there are still more RRs
* declared, then that's a corrupt packet. Let's accept the packet anyway, since it's
* apparently a common bug in routers. Let's however suppress OPT support in this
* case, so that we force the rest of the logic into lowest DNS baseline support. Or
* to say this differently: if the DNS server doesn't even get the RR counts right,
* it's highly unlikely it gets EDNS right. */
log_debug("More resource records declared in packet than included, suppressing OPT.");
bad_opt = true;
break;
}
r = dns_packet_read_rr(p, &rr, &cache_flush, &start);
if (r < 0)
return r;
@@ -2352,8 +2364,10 @@ static int dns_packet_extract_answer(DnsPacket *p, DnsAnswer **ret_answer) {
previous = dns_resource_record_ref(rr);
}
if (bad_opt)
if (bad_opt) {
p->opt = dns_resource_record_unref(p->opt);
p->opt_start = p->opt_size = SIZE_MAX;
}
*ret_answer = TAKE_PTR(answer);