]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Make the per-fetch validation quota terminal in sub-validations
authorOndřej Surý <ondrej@isc.org>
Tue, 23 Jun 2026 05:03:43 +0000 (07:03 +0200)
committerMichał Kępień <michal@isc.org>
Fri, 10 Jul 2026 07:26:46 +0000 (09:26 +0200)
Negative-proof validation stops once the per-fetch validation quota is
exhausted, but the DNSKEY, DS and CNAME sub-validator callbacks did
not — they re-fetched the record or relabelled the quota as a broken
chain. Treat ISC_R_QUOTA as terminal in all three, as
validator_callback_nsec already does.

lib/dns/validator.c

index f36b5c89b623b4a5e75fa2eeb4315b105b5ed143..b6e5f2c66a76dc2fa89048c50b5634b9c290f474 100644 (file)
@@ -693,7 +693,14 @@ validator_callback_dnskey(void *arg) {
        }
 
        validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_dnskey");
-       if (result == ISC_R_SUCCESS) {
+       if (result != ISC_R_SUCCESS) {
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "validator_callback_dnskey: got %s",
+                             isc_result_totext(result));
+       }
+
+       switch (result) {
+       case ISC_R_SUCCESS:
                validator_log(val, ISC_LOG_DEBUG(3), "keyset with trust %s",
                              dns_trust_totext(val->frdataset.trust));
                /*
@@ -705,20 +712,26 @@ validator_callback_dnskey(void *arg) {
                } else {
                        result = validate_async_run(val, resume_answer);
                }
-       } else {
-               validator_log(val, ISC_LOG_DEBUG(3),
-                             "validator_callback_dnskey: got %s",
-                             isc_result_totext(result));
-               if (result != DNS_R_BROKENCHAIN) {
-                       expire_rdatasets(val);
-                       result = create_fetch(val, &val->siginfo->signer,
-                                             dns_rdatatype_dnskey, NULL, NULL,
-                                             fetch_callback_dnskey,
-                                             "validator_callback_dnskey");
-                       if (result == ISC_R_SUCCESS) {
-                               result = DNS_R_WAIT;
-                       }
+               break;
+       case ISC_R_CANCELED:     /* Validation was canceled */
+       case ISC_R_SHUTTINGDOWN: /* Server shutting down */
+       case ISC_R_QUOTA:        /* Validation fails quota reached */
+               val->attributes |= subvalidator->attributes &
+                                  (VALATTR_MAXVALIDATIONS |
+                                   VALATTR_MAXVALIDATIONFAILS);
+               break;
+       case DNS_R_BROKENCHAIN:
+               break;
+       default:
+               expire_rdatasets(val);
+               result = create_fetch(val, &val->siginfo->signer,
+                                     dns_rdatatype_dnskey, NULL, NULL,
+                                     fetch_callback_dnskey,
+                                     "validator_callback_dnskey");
+               if (result == ISC_R_SUCCESS) {
+                       result = DNS_R_WAIT;
                }
+               break;
        }
 
 cleanup:
@@ -746,16 +759,21 @@ validator_callback_ds(void *arg) {
        }
 
        validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_ds");
-       if (result == ISC_R_SUCCESS) {
-               bool have_dsset;
-               dns_name_t *name;
+       if (result != ISC_R_SUCCESS) {
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "validator_callback_ds: got %s",
+                             isc_result_totext(result));
+       }
+
+       switch (result) {
+       case ISC_R_SUCCESS:
                validator_log(val, ISC_LOG_DEBUG(3), "%s with trust %s",
                              val->frdataset.type == dns_rdatatype_ds
                                      ? "dsset"
                                      : "ds non-existence",
                              dns_trust_totext(val->frdataset.trust));
-               have_dsset = (val->frdataset.type == dns_rdatatype_ds);
-               name = dns_fixedname_name(&val->fname);
+               bool have_dsset = (val->frdataset.type == dns_rdatatype_ds);
+               dns_name_t *name = dns_fixedname_name(&val->fname);
 
                if ((val->attributes & VALATTR_INSECURITY) != 0 &&
                    val->frdataset.covers == dns_rdatatype_ds &&
@@ -770,19 +788,24 @@ validator_callback_ds(void *arg) {
                } else {
                        result = validate_async_run(val, validate_dnskey);
                }
-       } else {
-               validator_log(val, ISC_LOG_DEBUG(3),
-                             "validator_callback_ds: got %s",
-                             isc_result_totext(result));
-               if (result != DNS_R_BROKENCHAIN) {
-                       expire_rdatasets(val);
-                       result = create_ds_fetch(val, val->name,
-                                                fetch_callback_ds,
-                                                "validator_callback_ds");
-                       if (result == ISC_R_SUCCESS) {
-                               result = DNS_R_WAIT;
-                       }
+               break;
+       case ISC_R_CANCELED:     /* Validation was canceled */
+       case ISC_R_SHUTTINGDOWN: /* Server shutting down */
+       case ISC_R_QUOTA:        /* Validation fails quota reached */
+               val->attributes |= subvalidator->attributes &
+                                  (VALATTR_MAXVALIDATIONS |
+                                   VALATTR_MAXVALIDATIONFAILS);
+               break;
+       case DNS_R_BROKENCHAIN:
+               break;
+       default:
+               expire_rdatasets(val);
+               result = create_ds_fetch(val, val->name, fetch_callback_ds,
+                                        "validator_callback_ds");
+               if (result == ISC_R_SUCCESS) {
+                       result = DNS_R_WAIT;
                }
+               break;
        }
 
 cleanup:
@@ -801,8 +824,7 @@ static void
 validator_callback_cname(void *arg) {
        dns_validator_t *subvalidator = (dns_validator_t *)arg;
        dns_validator_t *val = subvalidator->parent;
-       isc_result_t result;
-       isc_result_t eresult = subvalidator->result;
+       isc_result_t result = subvalidator->result;
 
        INSIST((val->attributes & VALATTR_INSECURITY) != 0);
 
@@ -813,18 +835,30 @@ validator_callback_cname(void *arg) {
        }
 
        validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_cname");
-       if (eresult == ISC_R_SUCCESS) {
+       if (result != ISC_R_SUCCESS) {
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "validator_callback_cname: got %s",
+                             isc_result_totext(result));
+       }
+       switch (result) {
+       case ISC_R_SUCCESS:
                validator_log(val, ISC_LOG_DEBUG(3), "cname with trust %s",
                              dns_trust_totext(val->frdataset.trust));
                result = proveunsecure(val, false, false, true);
-       } else {
-               if (eresult != DNS_R_BROKENCHAIN) {
-                       expire_rdatasets(val);
-               }
-               validator_log(val, ISC_LOG_DEBUG(3),
-                             "validator_callback_cname: got %s",
-                             isc_result_totext(eresult));
+               break;
+       case ISC_R_CANCELED:     /* Validation was canceled */
+       case ISC_R_SHUTTINGDOWN: /* Server shutting down */
+       case ISC_R_QUOTA:        /* Validation fails quota reached */
+               val->attributes |= subvalidator->attributes &
+                                  (VALATTR_MAXVALIDATIONS |
+                                   VALATTR_MAXVALIDATIONFAILS);
+               break;
+       case DNS_R_BROKENCHAIN:
+               break;
+       default:
+               expire_rdatasets(val);
                result = DNS_R_BROKENCHAIN;
+               break;
        }
 
 cleanup:
@@ -846,8 +880,7 @@ validator_callback_nsec(void *arg) {
        dns_validator_t *subvalidator = (dns_validator_t *)arg;
        dns_validator_t *val = subvalidator->parent;
        dns_rdataset_t *rdataset = subvalidator->rdataset;
-       isc_result_t result;
-       isc_result_t eresult = subvalidator->result;
+       isc_result_t result = subvalidator->result;
        bool exists, data;
 
        val->subvalidator = NULL;
@@ -857,7 +890,13 @@ validator_callback_nsec(void *arg) {
        }
 
        validator_log(val, ISC_LOG_DEBUG(3), "in validator_callback_nsec");
-       if (eresult == ISC_R_SUCCESS) {
+       if (result != ISC_R_SUCCESS) {
+               validator_log(val, ISC_LOG_DEBUG(3),
+                             "validator_callback_nsec: got %s",
+                             isc_result_totext(result));
+       }
+       switch (result) {
+       case ISC_R_SUCCESS: {
                dns_name_t **proofs = val->proofs;
                dns_name_t *wild = dns_fixedname_name(&val->wild);
 
@@ -911,29 +950,24 @@ validator_callback_nsec(void *arg) {
                }
 
                result = validate_nx(val, true);
-       } else {
-               validator_log(val, ISC_LOG_DEBUG(3),
-                             "validator_callback_nsec: got %s",
-                             isc_result_totext(eresult));
-               switch (eresult) {
-               case ISC_R_CANCELED:
-               case ISC_R_SHUTTINGDOWN:
-               case ISC_R_QUOTA:
-                       val->attributes |= subvalidator->attributes &
-                                          (VALATTR_MAXVALIDATIONS |
-                                           VALATTR_MAXVALIDATIONFAILS);
-                       result = eresult;
-                       break;
-               case DNS_R_BROKENCHAIN:
-                       val->authfail++;
-                       FALLTHROUGH;
-               default:
-                       if (val->nxset != NULL) {
-                               val->nxset->attributes.ncache = false;
-                       }
-                       result = validate_nx(val, true);
-                       break;
+               break;
+       }
+       case ISC_R_CANCELED:     /* Validation was canceled */
+       case ISC_R_SHUTTINGDOWN: /* Server shutting down */
+       case ISC_R_QUOTA:        /* Validation fails quota reached */
+               val->attributes |= subvalidator->attributes &
+                                  (VALATTR_MAXVALIDATIONS |
+                                   VALATTR_MAXVALIDATIONFAILS);
+               break;
+       case DNS_R_BROKENCHAIN:
+               val->authfail++;
+               FALLTHROUGH;
+       default:
+               if (val->nxset != NULL) {
+                       val->nxset->attributes.ncache = false;
                }
+               result = validate_nx(val, true);
+               break;
        }
 
 cleanup: