Do not add glues from different parent in delegdb

When processing a referral, the `cache_delegns()` function was accepting
glues from a different parent. For instance:

```
AUTHORITY
test.example.		NS	ns.test.example.
test.example.		NS	ns.foo.example.
test.example.		NS	ns.bar.

ADDITIONAL
ns.bar.			A	1.2.3.4
ns.foo.example.		A	5.6.7.8
ns.test.example.	A	9.8.7.6
```

In such situation, only the glues for `ns.foo.example.` and
`ns.test.example.` should be used, and the glue from `ns.bar.` should be
ignored as this is not either a sub-domain or a sibling domain, the
parent is different (`bar.` instead of `example.`). This is now fixed.

Sibling glue and cyclic sibling glues are defined in RFC 9471 section
2.2 and section 2.3.
This commit is contained in:
Colin Vidal 2026-04-17 13:09:56 +02:00
parent d1e51f96bf
commit aeee4c1c1d

View file

@ -6689,12 +6689,26 @@ cache_delegns(respctx_t *rctx) {
dns_delegdb_t *delegdb = fctx->res->view->deleg;
dns_delegset_t *delegset = NULL;
dns_ttl_t ttl = rctx->ns_rdataset->ttl;
dns_fixedname_t fparent;
dns_name_t *parent = dns_fixedname_initname(&fparent);
size_t labels;
isc_result_t result;
FCTXTRACE("cache_delegns");
dns_delegset_allocset(delegdb, &delegset);
/*
* The top of the delegated zone is `rctx->ns_name`. So truncating
* the first label gives the common parent domain allowed to get
* glues (this allows in-domain and sibling, but not different
* parents).
*/
labels = dns_name_countlabels(rctx->ns_name);
if (labels > 1) {
dns_name_getlabelsequence(rctx->ns_name, 1, labels - 1, parent);
}
DNS_RDATASET_FOREACH(rctx->ns_rdataset) {
dns_rdataset_t *gluerdataset = NULL;
dns_rdata_t rdata = DNS_RDATA_INIT;
@ -6715,20 +6729,26 @@ cache_delegns(respctx_t *rctx) {
INSIST(rdata.type == dns_rdatatype_ns);
dns_rdata_tostruct(&rdata, &ns, NULL);
result = dns_message_findname(
rctx->query->rmessage, DNS_SECTION_ADDITIONAL, &ns.name,
dns_rdatatype_a, 0, NULL, &gluerdataset);
if (result == ISC_R_SUCCESS) {
cache_delegglue(delegset, deleg, &ttl, gluerdataset);
gluerdataset = NULL;
}
if (labels > 1 && dns_name_issubdomain(&ns.name, parent)) {
result = dns_message_findname(rctx->query->rmessage,
DNS_SECTION_ADDITIONAL,
&ns.name, dns_rdatatype_a,
0, NULL, &gluerdataset);
if (result == ISC_R_SUCCESS) {
cache_delegglue(delegset, deleg, &ttl,
gluerdataset);
gluerdataset = NULL;
}
result = dns_message_findname(
rctx->query->rmessage, DNS_SECTION_ADDITIONAL, &ns.name,
dns_rdatatype_aaaa, 0, NULL, &gluerdataset);
if (result == ISC_R_SUCCESS) {
cache_delegglue6(delegset, deleg, &ttl, gluerdataset);
gluerdataset = NULL;
result = dns_message_findname(
rctx->query->rmessage, DNS_SECTION_ADDITIONAL,
&ns.name, dns_rdatatype_aaaa, 0, NULL,
&gluerdataset);
if (result == ISC_R_SUCCESS) {
cache_delegglue6(delegset, deleg, &ttl,
gluerdataset);
gluerdataset = NULL;
}
}
if (ISC_LIST_EMPTY(deleg->addresses)) {