]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Implement NOTIFY(CDS) logic
authorMatthijs Mekking <matthijs@isc.org>
Thu, 30 Oct 2025 08:48:35 +0000 (09:48 +0100)
committerMatthijs Mekking <matthijs@isc.org>
Fri, 19 Dec 2025 13:08:15 +0000 (14:08 +0100)
When the CDS/CDNSKEY RRset gets updated, schedule a NOTIFY(CDS) to be
sent to the parental agent. The parental agent is published in the
parent zone as a DSYNC RRset, so first we need to figure out the
parent owner name. This is done by finding the zonecut (querying for
NS RRset until we find a postive answer).

In nsfetch_dsync, we then schedule a zone fetch for the DSYNC record
at <child-labels>._dsync.<parent-labels>. Then we queue the notify
for each target in the DSYNC records that matches the NOTIFY scheme
and CDS RRtype.

lib/dns/include/dns/zonefetch.h
lib/dns/zone.c
lib/dns/zonefetch.c
lib/isc/include/isc/result.h
lib/isc/result.c

index 2ea510828145961d9001b8cee7bc6ac5b1338721..0a3a35764479083474ddd325b8b7e5d62bf8647a 100644 (file)
  * the last position of the enum.
  */
 typedef enum {
+       ZONEFETCHTYPE_DSYNC,
        ZONEFETCHTYPE_KEY,
        ZONEFETCHTYPE_NS,
        ZONEFETCHTYPE_COUNT,
 } dns_zonefetch_type_t;
 
-typedef struct dns_keyfetch  dns_keyfetch_t;
-typedef struct dns_nsfetch   dns_nsfetch_t;
-typedef struct dns_zonefetch dns_zonefetch_t;
+typedef struct dns_dsyncfetch dns_dsyncfetch_t;
+typedef struct dns_keyfetch   dns_keyfetch_t;
+typedef struct dns_nsfetch    dns_nsfetch_t;
+typedef struct dns_zonefetch  dns_zonefetch_t;
 
 /*
  * Fetch methods.
  */
 typedef struct dns_zonefetch_methods {
-       void (*start_fetch)(dns_zonefetch_t *fetch);
+       isc_result_t (*start_fetch)(dns_zonefetch_t *fetch);
        void (*continue_fetch)(dns_zonefetch_t *fetch);
        void (*cancel_fetch)(dns_zonefetch_t *fetch);
        void (*cleanup_fetch)(dns_zonefetch_t *fetch);
@@ -55,6 +57,12 @@ typedef struct dns_zonefetch_methods {
 /*
  * Fetch contexts.
  */
+struct dns_dsyncfetch {
+       dns_fixedname_t fname;
+       dns_name_t      pname;
+       dns_name_t      dsyncname;
+};
+
 struct dns_keyfetch {
        dns_rdataset_t keydataset;
        dns_db_t      *db;
@@ -65,8 +73,9 @@ struct dns_nsfetch {
 };
 
 typedef union dns_fetchdata {
-       dns_keyfetch_t keyfetch;
-       dns_nsfetch_t  nsfetch;
+       dns_dsyncfetch_t dsyncfetch;
+       dns_keyfetch_t   keyfetch;
+       dns_nsfetch_t    nsfetch;
 } dns_zonefetch_data_t;
 
 struct dns_zonefetch {
index 71df6192a3164971b652c922ca4f0fff3e168ffa..c4359cf7e16f84f586d0dcf71180f0bf1d2aa2ab 100644 (file)
@@ -53,6 +53,7 @@
 #include <dns/dbiterator.h>
 #include <dns/dlz.h>
 #include <dns/dnssec.h>
+#include <dns/dsync.h>
 #include <dns/journal.h>
 #include <dns/kasp.h>
 #include <dns/keydata.h>
@@ -909,6 +910,8 @@ zone_maintenance(dns_zone_t *zone);
 static void
 zone_notify(dns_zone_t *zone, isc_time_t *now);
 static void
+zone_notifycds(dns_zone_t *zone);
+static void
 dump_done(void *arg, isc_result_t result);
 static isc_result_t
 zone_signwithkey(dns_zone_t *zone, dst_algorithm_t algorithm, uint16_t keyid,
@@ -10484,12 +10487,14 @@ revocable(dns_zonefetch_t *fetch, dns_rdata_keydata_t *keydata) {
 /*
  * Fetch DNSKEY records at the trust anchor name.
  */
-static void
+static isc_result_t
 keyfetch_start(dns_zonefetch_t *fetch) {
        REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_KEY);
 
        fetch->qname = dns_fixedname_name(&fetch->name);
        fetch->qtype = dns_rdatatype_dnskey;
+
+       return ISC_R_SUCCESS;
 }
 
 static void
@@ -10505,12 +10510,12 @@ keyfetch_cancel(dns_zonefetch_t *fetch) {
        dns_zone_t *zone;
 
        REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_KEY);
+       REQUIRE(DNS_ZONE_VALID(fetch->zone));
+       REQUIRE(LOCKED_ZONE(fetch->zone));
 
        kfetch = &fetch->fetchdata.keyfetch;
        zone = fetch->zone;
 
-       INSIST(LOCKED_ZONE(zone));
-
        /*
         * Error during a key fetch; cancel and retry in an hour.
         */
@@ -10583,6 +10588,8 @@ keyfetch_done(dns_zonefetch_t *fetch, isc_result_t eresult) {
 
        REQUIRE(fetch != NULL);
        REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_KEY);
+       REQUIRE(DNS_ZONE_VALID(fetch->zone));
+       REQUIRE(LOCKED_ZONE(fetch->zone));
 
        kfetch = &fetch->fetchdata.keyfetch;
        zone = fetch->zone;
@@ -20858,7 +20865,7 @@ checkds_send(dns_zone_t *zone) {
 /*
  * Fetch NS records from parent zone.
  */
-static void
+static isc_result_t
 nsfetch_start(dns_zonefetch_t *fetch) {
        dns_nsfetch_t *nsfetch;
        unsigned int nlabels = 1;
@@ -20874,6 +20881,8 @@ nsfetch_start(dns_zonefetch_t *fetch) {
 
        fetch->qtype = dns_rdatatype_ns;
        fetch->qname = &nsfetch->pname;
+
+       return ISC_R_SUCCESS;
 }
 
 /*
@@ -20912,11 +20921,11 @@ nsfetch_cancel(dns_zonefetch_t *fetch) {
        dns_zone_t *zone;
 
        REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_NS);
+       REQUIRE(DNS_ZONE_VALID(fetch->zone));
+       REQUIRE(LOCKED_ZONE(fetch->zone));
 
        zone = fetch->zone;
 
-       INSIST(LOCKED_ZONE(zone));
-
        zone->fetchcount[ZONEFETCHTYPE_NS]--;
 }
 
@@ -20931,7 +20940,7 @@ nsfetch_cleanup(dns_zonefetch_t *fetch) {
  * agents.
  */
 static isc_result_t
-nsfetch_done(dns_zonefetch_t *fetch, isc_result_t eresult) {
+nsfetch_checkds(dns_zonefetch_t *fetch, isc_result_t eresult) {
        dns_nsfetch_t *nsfetch;
        isc_result_t result = ISC_R_NOMORE;
        dns_zone_t *zone = NULL;
@@ -20941,6 +20950,8 @@ nsfetch_done(dns_zonefetch_t *fetch, isc_result_t eresult) {
 
        REQUIRE(fetch != NULL);
        REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_NS);
+       REQUIRE(DNS_ZONE_VALID(fetch->zone));
+       REQUIRE(LOCKED_ZONE(fetch->zone));
 
        nsfetch = &fetch->fetchdata.nsfetch;
        zone = fetch->zone;
@@ -20951,7 +20962,7 @@ nsfetch_done(dns_zonefetch_t *fetch, isc_result_t eresult) {
 
        dns_name_format(pname, pnamebuf, sizeof(pnamebuf));
        dnssec_log(zone, ISC_LOG_DEBUG(3),
-                  "Returned from '%s' NS fetch in nsfetch_done(): %s",
+                  "Returned from '%s' NS fetch in nsfetch_checkds(): %s",
                   pnamebuf, isc_result_totext(eresult));
 
        if (eresult == DNS_R_NCACHENXRRSET || eresult == DNS_R_NXRRSET) {
@@ -21092,7 +21103,7 @@ zone_checkds(dns_zone_t *zone) {
                                        .continue_fetch = nsfetch_continue,
                                        .cancel_fetch = nsfetch_cancel,
                                        .cleanup_fetch = nsfetch_cleanup,
-                                       .done_fetch = nsfetch_done,
+                                       .done_fetch = nsfetch_checkds,
                                },
                };
                isc_mem_attach(zone->mctx, &fetch->mctx);
@@ -21117,6 +21128,374 @@ zone_checkds(dns_zone_t *zone) {
 #endif /* ifdef ENABLE_AFL */
 }
 
+static isc_result_t
+dsyncfetch_start(dns_zonefetch_t *fetch) {
+       dns_dsyncfetch_t *dsyncfetch;
+       dns_zone_t *zone;
+       dns_fixedname_t fndl, fnp;
+       dns_name_t *name, *dsyncname, *dsynclabel, *prefix;
+       unsigned int nlabels;
+       isc_result_t result;
+
+       REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_DSYNC);
+       REQUIRE(DNS_ZONE_VALID(fetch->zone));
+
+       dsyncfetch = &fetch->fetchdata.dsyncfetch;
+       zone = fetch->zone;
+
+       /*
+        * The dsync owner name is build up of <prefix>._dsync.<parent-name>.
+        * The prefix is the relative domain name of the child consisting of
+        * the labels under the zonecut.
+        */
+       dsyncname = dns_fixedname_initname(&dsyncfetch->fname);
+       dsynclabel = dns_fixedname_initname(&fndl);
+       dns_name_fromstring(dsynclabel, "_dsync", NULL, 0, fetch->mctx);
+       result = dns_name_concatenate(dsynclabel, &dsyncfetch->pname,
+                                     dsyncname);
+       if (result != ISC_R_SUCCESS) {
+               dnssec_log(zone, ISC_LOG_ERROR,
+                          "dsyncfetch: failed to create parent DSYNC fetch "
+                          "(parent part): %s",
+                          isc_result_totext(result));
+               return result;
+       }
+
+       name = dns_fixedname_name(&fetch->name);
+       nlabels = dns_name_countlabels(&dsyncfetch->pname);
+       prefix = dns_fixedname_initname(&fnp);
+       dns_name_split(name, nlabels, prefix, NULL);
+       result = dns_name_concatenate(prefix, dsyncname, dsyncname);
+       if (result != ISC_R_SUCCESS) {
+               dnssec_log(zone, ISC_LOG_ERROR,
+                          "dsyncfetch: failed to create parent DSYNC fetch "
+                          "(child part): %s",
+                          isc_result_totext(result));
+               return result;
+       }
+
+       dns_name_init(&dsyncfetch->dsyncname);
+       dns_name_clone(dsyncname, &dsyncfetch->dsyncname);
+
+       fetch->qtype = dns_rdatatype_dsync;
+       fetch->qname = &dsyncfetch->dsyncname;
+
+       return ISC_R_SUCCESS;
+}
+
+/*
+ * Retry an DSYNC RRset lookup.
+ */
+static void
+dsyncfetch_continue(dns_zonefetch_t *fetch) {
+       dns_zone_t *zone;
+
+       REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_DSYNC);
+       REQUIRE(DNS_ZONE_VALID(fetch->zone));
+
+       zone = fetch->zone;
+
+#ifdef ENABLE_AFL
+       if (!dns_fuzzing_resolver) {
+#endif /* ifdef ENABLE_AFL */
+               LOCK_ZONE(zone);
+               zone->fetchcount[ZONEFETCHTYPE_DSYNC]++;
+
+               dns_zonefetch_reschedule(fetch);
+
+               if (isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
+                       dnssec_log(zone, ISC_LOG_DEBUG(3),
+                                  "Creating parent DSYNC fetch in "
+                                  "dsyncfetch_continue()");
+               }
+               UNLOCK_ZONE(zone);
+#ifdef ENABLE_AFL
+       }
+#endif /* ifdef ENABLE_AFL */
+}
+
+static void
+dsyncfetch_cancel(dns_zonefetch_t *fetch) {
+       dns_zone_t *zone;
+
+       REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_DSYNC);
+       REQUIRE(DNS_ZONE_VALID(fetch->zone));
+       REQUIRE(LOCKED_ZONE(fetch->zone));
+
+       zone = fetch->zone;
+
+       zone->fetchcount[ZONEFETCHTYPE_DSYNC]--;
+}
+
+static void
+dsyncfetch_cleanup(dns_zonefetch_t *fetch) {
+       REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_DSYNC);
+}
+
+/*
+ * A DSYNC RRset has been fetched; scan the RRset and start sending
+ * NOTIFY(CDS) queries to them.
+ */
+static isc_result_t
+dsyncfetch_done(dns_zonefetch_t *fetch, isc_result_t eresult) {
+       dns_dsyncfetch_t *dsyncfetch;
+       isc_result_t result = ISC_R_NOMORE;
+       dns_notify_t *notify = NULL;
+       dns_zone_t *zone = NULL;
+       dns_name_t *dsyncname = NULL;
+       char dsyncnamebuf[DNS_NAME_FORMATSIZE];
+       dns_rdataset_t *rrset = NULL;
+
+       REQUIRE(fetch != NULL);
+       REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_DSYNC);
+       REQUIRE(DNS_ZONE_VALID(fetch->zone));
+       REQUIRE(LOCKED_ZONE(fetch->zone));
+
+       dsyncfetch = &fetch->fetchdata.dsyncfetch;
+       zone = fetch->zone;
+       rrset = &fetch->rrset;
+       dsyncname = &dsyncfetch->dsyncname;
+
+       zone->fetchcount[ZONEFETCHTYPE_DSYNC]--;
+
+       dns_name_format(dsyncname, dsyncnamebuf, sizeof(dsyncnamebuf));
+       dns_zone_log(zone, ISC_LOG_DEBUG(3),
+                    "dsyncfetch: Returned from '%s' DSYNC fetch in "
+                    "dsyncfetch_done(): %s",
+                    dsyncnamebuf, isc_result_totext(eresult));
+
+       result = dns_zonefetch_verify(fetch, eresult, dns_trust_secure);
+       if (result != ISC_R_SUCCESS) {
+               goto done;
+       }
+
+       UNLOCK_ZONE(zone);
+
+       /* Notify targets. */
+       dns_rdata_dsync_t dsync;
+       unsigned int count = 0;
+       for (result = dns_rdataset_first(rrset); result == ISC_R_SUCCESS;
+            result = dns_rdataset_next(rrset))
+       {
+               dns_rdata_t rdata = DNS_RDATA_INIT;
+
+               dns_rdataset_current(rrset, &rdata);
+               result = dns_rdata_tostruct(&rdata, &dsync, NULL);
+               RUNTIME_CHECK(result == ISC_R_SUCCESS);
+
+               dns_rdata_reset(&rdata);
+               if (dsync.scheme != DNS_DSYNCSCHEME_NOTIFY) {
+                       dns_zone_log(zone, ISC_LOG_DEBUG(1),
+                                    "dsyncfetch: unsupported DSYNC scheme %u, "
+                                    "ignoring",
+                                    dsync.scheme);
+                       continue;
+               }
+
+               if (dsync.type != dns_rdatatype_cds) {
+                       char typebuf[DNS_RDATATYPE_FORMATSIZE];
+                       dns_rdatatype_format(dsync.type, typebuf,
+                                            sizeof(typebuf));
+
+                       dns_zone_log(zone, ISC_LOG_DEBUG(1),
+                                    "dsyncfetch: DSYNC RRtype %s not "
+                                    "supported, ignoring",
+                                    result == ISC_R_SUCCESS ? typebuf
+                                                            : "UNKNOWN");
+                       continue;
+               }
+
+               count++;
+               if (count > 1) {
+                       dns_zone_log(zone, ISC_LOG_WARNING,
+                                    "dsyncfetch: multiple DSYNC records "
+                                    "matching NOTIFY scheme and CDS RRtype, "
+                                    "dropping response");
+                       result = DNS_R_INVALIDDSYNC;
+                       break;
+               }
+       }
+
+       LOCK_ZONE(zone);
+
+       if (result == ISC_R_NOMORE) {
+               result = ISC_R_SUCCESS;
+       } else {
+               goto done;
+       }
+
+       bool isqueued = dns_notify_isqueued(&zone->notifycds, dns_rdatatype_cds,
+                                           dsync.port, 0, &dsync.target, NULL,
+                                           NULL, NULL);
+
+       UNLOCK_ZONE(zone);
+
+       if (!isqueued) {
+               dns_notify_create(zone->mctx, dns_rdatatype_cds, dsync.port,
+                                 DNS_NOTIFY_NOSOA, &notify);
+               if (isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
+                       char tbuf[DNS_NAME_FORMATSIZE];
+                       dns_name_format(&dsync.target, tbuf, sizeof(tbuf));
+                       dns_zone_log(zone, ISC_LOG_DEBUG(3),
+                                    "dsyncfetch: send NOTIFY(CDS) query to %s",
+                                    tbuf);
+               }
+               dns_zone_iattach(zone, &notify->zone);
+               dns_name_dup(&dsync.target, zone->mctx, &notify->ns);
+               LOCK_ZONE(zone);
+               ISC_LIST_APPEND(zone->notifycds.notifies, notify, link);
+               UNLOCK_ZONE(zone);
+               dns_notify_find_address(notify);
+       }
+
+       LOCK_ZONE(zone);
+
+done:
+       if (result != ISC_R_SUCCESS) {
+               dns_zone_log(zone, ISC_LOG_DEBUG(3),
+                            "dsyncfetch: error processing DSYNC RRset: %s",
+                            isc_result_totext(result));
+       }
+
+       return result;
+}
+
+/*
+ * An NS RRset has been fetched from the parent of a zone whose DSYNC RRset
+ * needs to be queried; scan the RRset and start resolving those queries.
+ */
+static isc_result_t
+nsfetch_dsync(dns_zonefetch_t *fetch, isc_result_t eresult) {
+       dns_nsfetch_t *nsfetch;
+       isc_result_t result = ISC_R_NOMORE;
+       dns_zone_t *zone = NULL;
+       dns_name_t *pname = NULL;
+       char pnamebuf[DNS_NAME_FORMATSIZE];
+
+       REQUIRE(fetch != NULL);
+       REQUIRE(fetch->fetchtype == ZONEFETCHTYPE_NS);
+       REQUIRE(DNS_ZONE_VALID(fetch->zone));
+       REQUIRE(LOCKED_ZONE(fetch->zone));
+
+       nsfetch = &fetch->fetchdata.nsfetch;
+       zone = fetch->zone;
+       pname = &nsfetch->pname;
+
+       zone->fetchcount[ZONEFETCHTYPE_NS]--;
+
+       dns_name_format(pname, pnamebuf, sizeof(pnamebuf));
+       dnssec_log(zone, ISC_LOG_DEBUG(3),
+                  "Returned from '%s' NS fetch in nsfetch_dsync(): %s",
+                  pnamebuf, isc_result_totext(eresult));
+
+       if (eresult == DNS_R_NCACHENXRRSET || eresult == DNS_R_NXRRSET) {
+               dnssec_log(zone, ISC_LOG_DEBUG(3),
+                          "NODATA response for NS '%s', level up", pnamebuf);
+               return DNS_R_CONTINUE;
+       }
+
+       result = dns_zonefetch_verify(fetch, eresult, dns_trust_secure);
+       if (result != ISC_R_SUCCESS) {
+               goto done;
+       }
+
+#ifdef ENABLE_AFL
+       if (!dns_fuzzing_resolver) {
+#endif /* ifdef ENABLE_AFL */
+               dns_zonefetch_t *zfetch = NULL;
+               dns_dsyncfetch_t *dsyncfetch;
+
+               zfetch = isc_mem_get(zone->mctx, sizeof(dns_zonefetch_t));
+               *zfetch = (dns_zonefetch_t){
+                       .zone = zone,
+                       .options = DNS_FETCHOPT_UNSHARED |
+                                  DNS_FETCHOPT_NOCACHED,
+                       .fetchtype = ZONEFETCHTYPE_DSYNC,
+                       .fetchmethods =
+                               (dns_zonefetch_methods_t){
+                                       .start_fetch = dsyncfetch_start,
+                                       .continue_fetch = dsyncfetch_continue,
+                                       .cancel_fetch = dsyncfetch_cancel,
+                                       .cleanup_fetch = dsyncfetch_cleanup,
+                                       .done_fetch = dsyncfetch_done,
+                               },
+               };
+               isc_mem_attach(zone->mctx, &zfetch->mctx);
+
+               zone->fetchcount[ZONEFETCHTYPE_DSYNC]++;
+
+               dsyncfetch = &zfetch->fetchdata.dsyncfetch;
+               dns_name_init(&dsyncfetch->pname);
+               dns_name_clone(pname, &dsyncfetch->pname);
+
+               dns_zonefetch_schedule(zfetch, &zone->origin);
+
+               if (isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
+                       dnssec_log(zone, ISC_LOG_DEBUG(3),
+                                  "Creating parent DSYNC fetch in "
+                                  "nsfetch_dsync()");
+               }
+#ifdef ENABLE_AFL
+       }
+#endif /* ifdef ENABLE_AFL */
+
+done:
+       return result;
+}
+
+static void
+zone_notifycds(dns_zone_t *zone) {
+       dns_notifytype_t notifytype = zone->notifycds.notifytype;
+
+       if (notifytype == dns_notifytype_no) {
+               return;
+       }
+
+       INSIST(notifytype == dns_notifytype_yes);
+
+#ifdef ENABLE_AFL
+       if (!dns_fuzzing_resolver) {
+#endif /* ifdef ENABLE_AFL */
+               dns_zonefetch_t *fetch = NULL;
+               dns_nsfetch_t *nsfetch;
+
+               fetch = isc_mem_get(zone->mctx, sizeof(dns_zonefetch_t));
+               *fetch = (dns_zonefetch_t){
+                       .zone = zone,
+                       .options = DNS_FETCHOPT_UNSHARED |
+                                  DNS_FETCHOPT_NOCACHED,
+                       .fetchtype = ZONEFETCHTYPE_NS,
+                       .fetchmethods =
+                               (dns_zonefetch_methods_t){
+                                       .start_fetch = nsfetch_start,
+                                       .continue_fetch = nsfetch_continue,
+                                       .cancel_fetch = nsfetch_cancel,
+                                       .cleanup_fetch = nsfetch_cleanup,
+                                       .done_fetch = nsfetch_dsync,
+                               },
+               };
+               isc_mem_attach(zone->mctx, &fetch->mctx);
+
+               LOCK_ZONE(zone);
+               zone->fetchcount[ZONEFETCHTYPE_NS]++;
+
+               nsfetch = &fetch->fetchdata.nsfetch;
+               dns_name_init(&nsfetch->pname);
+               dns_name_clone(&zone->origin, &nsfetch->pname);
+
+               dns_zonefetch_schedule(fetch, &zone->origin);
+
+               if (isc_log_wouldlog(ISC_LOG_DEBUG(3))) {
+                       dnssec_log(
+                               zone, ISC_LOG_DEBUG(3),
+                               "Creating parent NS fetch in zone_notifyds()");
+               }
+               UNLOCK_ZONE(zone);
+#ifdef ENABLE_AFL
+       }
+#endif /* ifdef ENABLE_AFL */
+}
+
 static void
 update_ttl(dns_rdataset_t *rdataset, dns_name_t *name, dns_ttl_t ttl,
           dns_diff_t *diff) {
@@ -21262,6 +21641,7 @@ zone_rekey(dns_zone_t *zone) {
        bool commit = false, newactive = false;
        bool newalg = false;
        bool fullsign;
+       bool notifycds = false;
        bool offlineksk = false;
        bool kasp_change = false;
        uint8_t options = 0;
@@ -21627,8 +22007,7 @@ zone_rekey(dns_zone_t *zone) {
                                               &cdnskeyset, now, &digests,
                                               cdnskeypub, ttl, &diff, mctx);
                if (result == ISC_R_SUCCESS) {
-                       dnssec_log(zone, ISC_LOG_DEBUG(3),
-                                  "zone_rekey:CDS/CDNSKEY updated");
+                       notifycds = true;
                } else if (result != DNS_R_UNCHANGED) {
                        dnssec_log(zone, ISC_LOG_ERROR,
                                   "zone_rekey:couldn't update CDS/CDNSKEY: %s",
@@ -21666,8 +22045,7 @@ zone_rekey(dns_zone_t *zone) {
                        &cdsset, &cdnskeyset, &zone->origin, zone->rdclass, ttl,
                        &diff, mctx, cdsdel, cdnskeydel);
                if (result == ISC_R_SUCCESS) {
-                       dnssec_log(zone, ISC_LOG_DEBUG(3),
-                                  "zone_rekey:CDS/CDNSKEY updated (DELETE)");
+                       notifycds = true;
                } else if (result != DNS_R_UNCHANGED) {
                        dnssec_log(zone, ISC_LOG_ERROR,
                                   "zone_rekey:couldn't update CDS/CDNSKEY "
@@ -21983,6 +22361,13 @@ zone_rekey(dns_zone_t *zone) {
                ISC_LIST_APPEND(zone->keyring, key, link);
        }
 
+       /*
+        * If the CDS/CDNSKEY RRset has changed, send NOTIFY(CDS) to endpoints.
+        */
+       if (notifycds) {
+               zone_notifycds(zone);
+       }
+
        result = ISC_R_SUCCESS;
 
 cleanup:
index 27319cc9effa555fed01b229f0011acebeeb1a1a..d8a5df9b1874607f3cb2bd519f5b022cde6df2a9 100644 (file)
@@ -43,7 +43,10 @@ dns_zonefetch_run(void *arg) {
        INSIST(view != NULL);
        INSIST(loop != NULL);
 
-       fetch->fetchmethods.start_fetch(fetch);
+       result = fetch->fetchmethods.start_fetch(fetch);
+       if (result != ISC_R_SUCCESS) {
+               goto cancel;
+       }
 
        result = dns_view_getresolver(view, &resolver);
        if (result != ISC_R_SUCCESS) {
index 34f08a7f7426c3f055a0481d8cb61766a2a5f099..3c5d6a75d7f929b225b21db205084760640af2c4 100644 (file)
@@ -209,6 +209,7 @@ typedef enum isc_result {
        DNS_R_NOSKRFILE,
        DNS_R_NOSKRBUNDLE,
        DNS_R_LOOPDETECTED,
+       DNS_R_INVALIDDSYNC,
 
        DST_R_UNSUPPORTEDALG,
        DST_R_CRYPTOFAILURE,
index de78e4422cec41632808c48111c4cbc1c0e90419..f362d812f7347ff8d68c98078aadcf3595103f14 100644 (file)
@@ -212,6 +212,7 @@ static const char *description[ISC_R_NRESULTS] = {
        [DNS_R_NOSKRFILE] = "no SKR file",
        [DNS_R_NOSKRBUNDLE] = "no available SKR bundle",
        [DNS_R_LOOPDETECTED] = "fetch loop detected",
+       [DNS_R_INVALIDDSYNC] = "invalid DSYNC response",
 
        [DST_R_UNSUPPORTEDALG] = "algorithm is unsupported",
        [DST_R_CRYPTOFAILURE] = "crypto failure",
@@ -445,6 +446,7 @@ static const char *identifier[ISC_R_NRESULTS] = {
        [DNS_R_NOSKRFILE] = "DNS_R_NOSKRFILE",
        [DNS_R_NOSKRBUNDLE] = "DNS_R_NOSKRBUNDLE",
        [DNS_R_LOOPDETECTED] = "DNS_R_LOOPDETECTED",
+       [DNS_R_INVALIDDSYNC] = "DNS_R_INVALIDDSYNC",
 
        [DST_R_UNSUPPORTEDALG] = "DST_R_UNSUPPORTEDALG",
        [DST_R_CRYPTOFAILURE] = "DST_R_CRYPTOFAILURE",