]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Ensure required cached glue is rendered
authorMichał Kępień <michal@isc.org>
Thu, 22 Sep 2022 12:03:17 +0000 (14:03 +0200)
committerMichał Kępień <michal@isc.org>
Thu, 22 Sep 2022 12:03:17 +0000 (14:03 +0200)
When looking for required glue, dns_message_rendersection() only
processes the first rdataset associated with the first name added to the
ADDITIONAL section.  If the DNS_RDATASETATTR_REQUIRED attribute is set
for an rdataset which is located somewhere else (i.e. the name it is
associated with is preceded by another name in the ADDITIONAL section),
it will not be honored, i.e. the TC bit will not be set even if the
rdataset does not fit into the response.

Check the attributes of each processed rdataset while appending names to
a referral response based on a glue cache entry.  If a given rdataset is
marked with DNS_RDATASETATTR_REQUIRED, make sure the name it is
associated with is added to the response at the beginning of the
ADDITIONAL section, not its end.

Note that using ISC_LIST_PREPEND() instead of ISC_LIST_APPEND() is not
necessary when associating the rdataset with its owner name because the
dns_name_t structures are initialized just before the glue rdatasets are
associated with them and therefore they are empty at that point, which
means no other (non-required) rdataset can precede the glue rdatasets
within the dns_name_t structure owning them.

lib/dns/rbtdb.c

index 38d485dbc323c0c8a689046b423be21c6af98d6f..53fbb2822fec631ad4cef0dd848fdf9b7d708470 100644 (file)
@@ -9680,6 +9680,8 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype,
        return (result);
 }
 
+#define IS_REQUIRED_GLUE(r) (((r)->attributes & DNS_RDATASETATTR_REQUIRED) != 0)
+
 static isc_result_t
 rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version,
                 dns_message_t *msg) {
@@ -9764,6 +9766,7 @@ restart:
                dns_rdataset_t *rdataset_aaaa = NULL;
                dns_rdataset_t *sigrdataset_aaaa = NULL;
                dns_name_t *gluename = dns_fixedname_name(&ge->fixedname);
+               bool prepend_name = false;
 
                dns_message_gettempname(msg, &name);
 
@@ -9788,6 +9791,9 @@ restart:
                if (rdataset_a != NULL) {
                        dns_rdataset_clone(&ge->rdataset_a, rdataset_a);
                        ISC_LIST_APPEND(name->list, rdataset_a, link);
+                       if (IS_REQUIRED_GLUE(rdataset_a)) {
+                               prepend_name = true;
+                       }
                }
 
                if (sigrdataset_a != NULL) {
@@ -9798,6 +9804,9 @@ restart:
                if (rdataset_aaaa != NULL) {
                        dns_rdataset_clone(&ge->rdataset_aaaa, rdataset_aaaa);
                        ISC_LIST_APPEND(name->list, rdataset_aaaa, link);
+                       if (IS_REQUIRED_GLUE(rdataset_aaaa)) {
+                               prepend_name = true;
+                       }
                }
                if (sigrdataset_aaaa != NULL) {
                        dns_rdataset_clone(&ge->sigrdataset_aaaa,
@@ -9806,6 +9815,23 @@ restart:
                }
 
                dns_message_addname(msg, name, DNS_SECTION_ADDITIONAL);
+
+               /*
+                * When looking for required glue, dns_message_rendersection()
+                * only processes the first rdataset associated with the first
+                * name added to the ADDITIONAL section.  dns_message_addname()
+                * performs an append on the list of names in a given section,
+                * so if any glue record was marked as required, we need to
+                * move the name it is associated with to the beginning of the
+                * list for the ADDITIONAL section or else required glue might
+                * not be rendered.
+                */
+               if (prepend_name) {
+                       ISC_LIST_UNLINK(msg->sections[DNS_SECTION_ADDITIONAL],
+                                       name, link);
+                       ISC_LIST_PREPEND(msg->sections[DNS_SECTION_ADDITIONAL],
+                                        name, link);
+               }
        }
 
 no_glue: