mirror of
https://github.com/isc-projects/bind9.git
synced 2026-06-09 04:32:04 -04:00
Funnel the validator's DS fetches through a single helper
The validator starts a DS fetch from three places while building or proving a trust chain. Only validate_dnskey() handed the resolver the parent zone cut as a delegation hint; the other two started the fetch with no hint at all. Factor the shared setup into create_ds_fetch() and route all three through it, so every validator DS fetch is created identically and carries the parent zone cut. DS is an at-parent type, so the resolver already anchors such a query at the parent on its own; supplying the zone cut explicitly also lets the resolver's fetch loop detection match the fetch by domain, which it cannot do for a fetch with no hint. Assisted-by: Claude:claude-opus-4-8
This commit is contained in:
parent
ed3a16bea8
commit
dc3e15d7a6
1 changed files with 58 additions and 51 deletions
|
|
@ -168,6 +168,10 @@ create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
|
|||
const dns_name_t *domain, dns_delegset_t *delegset,
|
||||
isc_job_cb callback, const char *caller);
|
||||
|
||||
static isc_result_t
|
||||
create_ds_fetch(dns_validator_t *val, dns_name_t *name, isc_job_cb callback,
|
||||
const char *caller);
|
||||
|
||||
/*%
|
||||
* Ensure the validator's rdatasets are marked as expired.
|
||||
*/
|
||||
|
|
@ -759,9 +763,9 @@ validator_callback_ds(void *arg) {
|
|||
isc_result_totext(result));
|
||||
if (result != DNS_R_BROKENCHAIN) {
|
||||
expire_rdatasets(val);
|
||||
result = create_fetch(val, val->name, dns_rdatatype_ds,
|
||||
NULL, NULL, fetch_callback_ds,
|
||||
"validator_callback_ds");
|
||||
result = create_ds_fetch(val, val->name,
|
||||
fetch_callback_ds,
|
||||
"validator_callback_ds");
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
result = DNS_R_WAIT;
|
||||
}
|
||||
|
|
@ -1060,6 +1064,52 @@ create_fetch(dns_validator_t *val, dns_name_t *name, dns_rdatatype_t type,
|
|||
return result;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Start a fetch for the DS RRset at 'name', which lives in the parent zone.
|
||||
*
|
||||
* If the delegation database already has a usable delegation for that parent,
|
||||
* pass it to the resolver as a hint so the fetch is anchored at the parent
|
||||
* zone cut. DS is an at-parent type, so the resolver derives the same cut on
|
||||
* its own for a hintless query; supplying it explicitly additionally gives the
|
||||
* resolver's fetch loop detection a zone cut to match on, which it does not
|
||||
* have for a fetch started without a hint. The lookup fails harmlessly if the
|
||||
* parent delegation is expired or does not line up with the labels in 'name',
|
||||
* leaving a hintless DS fetch.
|
||||
*/
|
||||
static isc_result_t
|
||||
create_ds_fetch(dns_validator_t *val, dns_name_t *name, isc_job_cb callback,
|
||||
const char *caller) {
|
||||
isc_result_t result;
|
||||
dns_fixedname_t pfixed, fixed;
|
||||
dns_name_t *pname = NULL, *fname = NULL;
|
||||
dns_delegset_t *delegset = NULL;
|
||||
const dns_name_t *parent = NULL;
|
||||
unsigned int n;
|
||||
|
||||
n = dns_name_countlabels(name);
|
||||
if (n > 1) {
|
||||
pname = dns_fixedname_initname(&pfixed);
|
||||
dns_name_getlabelsequence(name, 1, n - 1, pname);
|
||||
|
||||
fname = dns_fixedname_initname(&fixed);
|
||||
result = dns_view_bestzonecut(val->view, pname, fname, NULL, 0,
|
||||
0, true, true, &delegset);
|
||||
if (result == ISC_R_SUCCESS && delegset != NULL) {
|
||||
parent = fname;
|
||||
} else if (delegset != NULL) {
|
||||
dns_delegset_detach(&delegset);
|
||||
}
|
||||
}
|
||||
|
||||
result = create_fetch(val, name, dns_rdatatype_ds, parent, delegset,
|
||||
callback, caller);
|
||||
if (delegset != NULL) {
|
||||
dns_delegset_detach(&delegset);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*%
|
||||
* Start a subvalidation process.
|
||||
*/
|
||||
|
|
@ -2023,60 +2073,17 @@ get_dsset(dns_validator_t *val, dns_name_t *tname, isc_result_t *resp) {
|
|||
}
|
||||
break;
|
||||
|
||||
case ISC_R_NOTFOUND: {
|
||||
dns_fixedname_t pfixed, fixed;
|
||||
dns_name_t *pname = NULL, *fname = NULL;
|
||||
dns_delegset_t *delegset = NULL;
|
||||
const dns_name_t *parent = NULL;
|
||||
unsigned int n;
|
||||
|
||||
/*
|
||||
* Before kicking off a fetch, see whether the delegation
|
||||
* database already knows a usable delegation for tname's
|
||||
* parent zone. When it does, pass that delegation to the
|
||||
* resolver as a hint so the DS query is sent directly to
|
||||
* the parent's nameservers without going through the
|
||||
* "chase DS servers" recovery path.
|
||||
*
|
||||
* This lookup will succeed in the common case, but will fails
|
||||
* in the parent delegation is expired or if the zonecut doesn't
|
||||
* match the labels in the name. Without this hint, the resolver
|
||||
* may fall back to a delegation at tname itself (the child
|
||||
* side), send the DS query there, get NODATA from the apex of
|
||||
* the zone and spend two extra round trips recovering from a
|
||||
* delegation we already had cached.
|
||||
*/
|
||||
n = dns_name_countlabels(tname);
|
||||
if (n > 1) {
|
||||
pname = dns_fixedname_initname(&pfixed);
|
||||
dns_name_getlabelsequence(tname, 1, n - 1, pname);
|
||||
|
||||
fname = dns_fixedname_initname(&fixed);
|
||||
result = dns_view_bestzonecut(val->view, pname, fname,
|
||||
NULL, 0, 0, true, true,
|
||||
&delegset);
|
||||
if (result == ISC_R_SUCCESS && delegset != NULL) {
|
||||
parent = fname;
|
||||
} else if (delegset != NULL) {
|
||||
dns_delegset_detach(&delegset);
|
||||
}
|
||||
}
|
||||
|
||||
case ISC_R_NOTFOUND:
|
||||
/*
|
||||
* We don't have the DS. Find it.
|
||||
*/
|
||||
result = create_fetch(val, tname, dns_rdatatype_ds, parent,
|
||||
delegset, fetch_callback_ds,
|
||||
"validate_dnskey");
|
||||
if (delegset != NULL) {
|
||||
dns_delegset_detach(&delegset);
|
||||
}
|
||||
result = create_ds_fetch(val, tname, fetch_callback_ds,
|
||||
"validate_dnskey");
|
||||
*resp = DNS_R_WAIT;
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
*resp = result;
|
||||
}
|
||||
return ISC_R_COMPLETE;
|
||||
}
|
||||
|
||||
case DNS_R_NCACHENXDOMAIN:
|
||||
case DNS_R_NCACHENXRRSET:
|
||||
|
|
@ -3329,8 +3336,8 @@ seek_ds(dns_validator_t *val, isc_result_t *resp) {
|
|||
* We don't know anything about the DS. Find it.
|
||||
*/
|
||||
*resp = DNS_R_WAIT;
|
||||
result = create_fetch(val, tname, dns_rdatatype_ds, NULL, NULL,
|
||||
fetch_callback_ds, "seek_ds");
|
||||
result = create_ds_fetch(val, tname, fetch_callback_ds,
|
||||
"seek_ds");
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
*resp = result;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue