]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: gracefully handle with packets with too large RR count
authorLennart Poettering <lennart@poettering.net>
Tue, 10 Nov 2020 13:48:13 +0000 (14:48 +0100)
committerLennart Poettering <lennart@poettering.net>
Sun, 14 Feb 2021 22:05:28 +0000 (23:05 +0100)
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

src/resolve/resolved-dns-packet.c

index 59be55a0eb027747f0cc487439c9d17f03d750c8..953d5fa337d679f54f8154640c997cf1f793ff1f 100644 (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);