From: Michał Kępień Date: Thu, 22 Sep 2022 12:03:17 +0000 (+0200) Subject: Ensure required cached glue is rendered X-Git-Tag: v9.19.6~44^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=68a004501aa116e8631c924375161ae8fa428828;p=thirdparty%2Fbind9.git Ensure required cached glue is rendered 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. --- diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index 38d485dbc32..53fbb2822fe 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -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: