From d977eae211fd9f5e255d01a0676814af35f1903c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= Date: Thu, 22 Sep 2022 14:03:17 +0200 Subject: [PATCH] Mark required glue during glue cache processing If an NS RRset at the parent side of a delegation point only contains in-bailiwick NS records, at least one glue record should be included in every referral response sent for such a delegation point or else clients will need to send follow-up queries in order to determine name server addresses. In certain edge cases (when the total size of a referral response without glue records was just below to the UDP packet size limit), named failed to adhere to that rule by sending non-truncated, glueless referral responses. Fix the problem by marking all in-bailiwick NS records processed by glue_nsdname_cb() (the dns_rdataset_additionaldata() callback used by RBTDB code while iterating over an NS RRset when dns_rdataset_addglue() is called) with the DNS_RDATASETATTR_REQUIRED flag. Note that for simplicity, glue RRsets for all in-bailiwick NS records are marked this way, even though dns_message_rendersection() only checks the attributes for the first rdataset associated with the first name added to the ADDITIONAL section. --- lib/dns/rbtdb.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lib/dns/rbtdb.c b/lib/dns/rbtdb.c index f6e8444e17..38d485dbc3 100644 --- a/lib/dns/rbtdb.c +++ b/lib/dns/rbtdb.c @@ -9407,6 +9407,7 @@ typedef struct { rbtdb_glue_t *glue_list; dns_rbtdb_t *rbtdb; rbtdb_version_t *rbtversion; + dns_name_t *nodename; } rbtdb_glue_additionaldata_ctx_t; static void @@ -9629,6 +9630,25 @@ glue_nsdname_cb(void *arg, const dns_name_t *name, dns_rdatatype_t qtype, } } + /* + * If the currently processed NS record is in-bailiwick, mark any glue + * RRsets found for it with DNS_RDATASETATTR_REQUIRED. Note that for + * simplicity, glue RRsets for all in-bailiwick NS records are marked + * this way, even though dns_message_rendersection() only checks the + * attributes for the first rdataset associated with the first name + * added to the ADDITIONAL section. + */ + if (glue != NULL && dns_name_issubdomain(name, ctx->nodename)) { + if (dns_rdataset_isassociated(&glue->rdataset_a)) { + glue->rdataset_a.attributes |= + DNS_RDATASETATTR_REQUIRED; + } + if (dns_rdataset_isassociated(&glue->rdataset_aaaa)) { + glue->rdataset_aaaa.attributes |= + DNS_RDATASETATTR_REQUIRED; + } + } + if (glue != NULL) { glue->next = ctx->glue_list; ctx->glue_list = glue; @@ -9666,6 +9686,7 @@ rdataset_addglue(dns_rdataset_t *rdataset, dns_dbversion_t *version, dns_rbtdb_t *rbtdb = rdataset->private1; dns_rbtnode_t *node = rdataset->private2; rbtdb_version_t *rbtversion = version; + dns_fixedname_t nodename; uint32_t idx; rbtdb_glue_table_node_t *cur; bool found = false; @@ -9811,6 +9832,14 @@ no_glue: ctx.rbtdb = rbtdb; ctx.rbtversion = rbtversion; + /* + * Get the owner name of the NS RRset - it will be necessary for + * identifying required glue in glue_nsdname_cb() (by determining which + * NS records in the delegation are in-bailiwick). + */ + ctx.nodename = dns_fixedname_initname(&nodename); + nodefullname((dns_db_t *)rbtdb, node, ctx.nodename); + RWLOCK(&rbtversion->glue_rwlock, isc_rwlocktype_write); maybe_rehash_gluetable(rbtversion);