]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
3188. [bug] zone.c:zone_refreshkeys() could fail to detach
authorEvan Hunt <each@isc.org>
Tue, 1 Nov 2011 04:00:45 +0000 (04:00 +0000)
committerEvan Hunt <each@isc.org>
Tue, 1 Nov 2011 04:00:45 +0000 (04:00 +0000)
references correctly when errors occurred, causing
a hang on shutdown. [RT #26372]

CHANGES
lib/dns/include/dns/rriterator.h
lib/dns/rriterator.c
lib/dns/zone.c

diff --git a/CHANGES b/CHANGES
index 488e3bad7e4e3577e3aa6826e92e10415c916130..43b49c5ef20b36535970819e8deca42d07327ca0 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,7 @@
+3188.  [bug]           zone.c:zone_refreshkeys() could fail to detach
+                       references correctly when errors occurred, causing
+                       a hang on shutdown. [RT #26372]
+
 3187.  [port]          win32: support for Visual Studio 2008.  [RT #26356]
 
        --- 9.9.0b1 released ---
index 0e4b0a469a0dd7ec10ae2c383766e71c84084ffc..855412145f6d46ec08b2e2959d14e95d24ac3a2a 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rriterator.h,v 1.2 2009/06/30 02:52:32 each Exp $ */
+/* $Id: rriterator.h,v 1.3 2011/11/01 04:00:45 each Exp $ */
 
 #ifndef DNS_RRITERATOR_H
 #define DNS_RRITERATOR_H 1
@@ -77,26 +77,110 @@ typedef struct dns_rriterator {
 isc_result_t
 dns_rriterator_init(dns_rriterator_t *it, dns_db_t *db,
                       dns_dbversion_t *ver, isc_stdtime_t now);
+/*%
+ * Initialize an rriterator; sets the cursor to the origin node
+ * of the database.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ */
 
 isc_result_t
 dns_rriterator_first(dns_rriterator_t *it);
+/*%<
+ * Move the rriterator cursor to the first rdata in the database.
+ *
+ * Requires:
+ *\li  'it' is a valid, initialized rriterator
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMORE                   There are no rdata in the set.
+ */
 
 isc_result_t
 dns_rriterator_nextrrset(dns_rriterator_t *it);
+/*%<
+ * Move the rriterator cursor to the next rrset in the database,
+ * skipping over any remaining records that have the same rdatatype
+ * as the current one.
+ *
+ * Requires:
+ *\li  'it' is a valid, initialized rriterator
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMORE                   No more rrsets in the database
+ */
 
 isc_result_t
 dns_rriterator_next(dns_rriterator_t *it);
+/*%<
+ * Move the rriterator cursor to the next rrset in the database,
+ * skipping over any remaining records that have the same rdatatype
+ * as the current one.
+ *
+ * Requires:
+ *\li  'it' is a valid, initialized rriterator
+ *
+ * Returns:
+ *\li  #ISC_R_SUCCESS
+ *\li  #ISC_R_NOMORE                   No more records in the database
+ */
 
 void
 dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name,
                          isc_uint32_t *ttl, dns_rdataset_t **rdataset,
                          dns_rdata_t **rdata);
+/*%<
+ * Make '*name' refer to the current name.  If 'rdataset' is not NULL,
+ * make '*rdataset' refer to the current * rdataset.  If '*rdata' is not
+ * NULL, make '*rdata' refer to the current record.
+ *
+ * Requires:
+ *\li  '*name' is a valid name object
+ *\li  'rdataset' is NULL or '*rdataset' is NULL
+ *\li  'rdata' is NULL or '*rdata' is NULL
+ *
+ * Ensures:
+ *\li  'rdata' refers to the rdata at the rdata cursor location of
+ *\li  'rdataset'.
+ */
 
 void
 dns_rriterator_pause(dns_rriterator_t *it);
+/*%<
+ * Pause rriterator.  Frees any locks held by the database iterator.
+ * Callers should use this routine any time they are not going to
+ * execute another rriterator method in the immediate future.
+ *
+ * Requires:
+ *\li  'it' is a valid iterator.
+ *
+ * Ensures:
+ *\li  Any database locks being held for efficiency of iterator access are
+ *     released.
+ */
 
 void
 dns_rriterator_destroy(dns_rriterator_t *it);
+/*%<
+ * Shut down and free resources in rriterator 'it'.
+ *
+ * Requires:
+ *
+ *\li  'it' is a valid iterator.
+ *
+ * Ensures:
+ *
+ *\li  All resources used by the rriterator are freed.
+ */
 
 ISC_LANG_ENDDECLS
 
index c98caf324b1e7ecf686075638bddc9cb651ae963..561c5f8809a43c5dbc1dcfa362111d715427018c 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: rriterator.c,v 1.2 2009/06/30 02:52:32 each Exp $ */
+/* $Id: rriterator.c,v 1.3 2011/11/01 04:00:44 each Exp $ */
 
 /*! \file */
 
@@ -187,6 +187,8 @@ dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name,
        REQUIRE(name != NULL && *name == NULL);
        REQUIRE(VALID_RRITERATOR(it));
        REQUIRE(it->result == ISC_R_SUCCESS);
+       REQUIRE(rdataset == NULL || *rdataset == NULL);
+       REQUIRE(rdata == NULL || *rdata == NULL);
 
        *name = dns_fixedname_name(&it->fixedname);
        *ttl = it->rdataset.ttl;
@@ -194,9 +196,9 @@ dns_rriterator_current(dns_rriterator_t *it, dns_name_t **name,
        dns_rdata_reset(&it->rdata);
        dns_rdataset_current(&it->rdataset, &it->rdata);
 
-       if (rdataset)
+       if (rdataset != NULL)
                *rdataset = &it->rdataset;
 
-       if (rdata)
+       if (rdata != NULL)
                *rdata = &it->rdata;
 }
index eca693cdd0474251d214332ad23f85edd1a878f4..6b0a409209f52465ad45793940a06a563f8ec115 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: zone.c,v 1.643 2011/10/28 12:27:06 marka Exp $ */
+/* $Id: zone.c,v 1.644 2011/11/01 04:00:44 each Exp $ */
 
 /*! \file */
 
@@ -3360,7 +3360,7 @@ sync_keyzone(dns_zone_t *zone, dns_db_t *db) {
        for (result = dns_rriterator_first(&rrit);
             result == ISC_R_SUCCESS;
             result = dns_rriterator_nextrrset(&rrit)) {
-               dns_rdataset_t *rdataset;
+               dns_rdataset_t *rdataset = NULL;
                dns_name_t *rrname = NULL;
                isc_uint32_t ttl;
 
@@ -8102,6 +8102,7 @@ zone_refreshkeys(dns_zone_t *zone) {
        dns_rdata_keydata_t kd;
        isc_stdtime_t now;
        isc_boolean_t commit = ISC_FALSE;
+       isc_boolean_t fetching = ISC_FALSE, fetch_err = ISC_FALSE;
 
        ENTER;
        REQUIRE(zone->db != NULL);
@@ -8130,16 +8131,14 @@ zone_refreshkeys(dns_zone_t *zone) {
             result == ISC_R_SUCCESS;
             result = dns_rriterator_nextrrset(&rrit)) {
                isc_stdtime_t timer = 0xffffffff;
+               dns_name_t *name = NULL, *kname = NULL;
+               dns_rdataset_t *kdset = NULL;
                dns_keyfetch_t *kfetch;
-               dns_rdataset_t *kdset;
-               dns_name_t *name = NULL;
                isc_uint32_t ttl;
 
                dns_rriterator_current(&rrit, &name, &ttl, &kdset, NULL);
-               if (!dns_rdataset_isassociated(kdset))
-                       continue;
-
-               if (kdset->type != dns_rdatatype_keydata)
+               if (kdset == NULL || kdset->type != dns_rdatatype_keydata ||
+                   !dns_rdataset_isassociated(kdset))
                        continue;
 
                /*
@@ -8174,15 +8173,19 @@ zone_refreshkeys(dns_zone_t *zone) {
                if (timer > now)
                        continue;
 
-               zone->refreshkeycount++;
-
                kfetch = isc_mem_get(zone->mctx, sizeof(dns_keyfetch_t));
+               if (kfetch == NULL) {
+                       fetch_err = ISC_TRUE;
+                       goto failure;
+               }
+
+               zone->refreshkeycount++;
                kfetch->zone = zone;
                zone->irefs++;
                INSIST(zone->irefs != 0);
                dns_fixedname_init(&kfetch->name);
-               dns_name_dup(name, zone->mctx,
-                            dns_fixedname_name(&kfetch->name));
+               kname = dns_fixedname_name(&kfetch->name);
+               dns_name_dup(name, zone->mctx, kname);
                dns_rdataset_init(&kfetch->dnskeyset);
                dns_rdataset_init(&kfetch->dnskeysigset);
                dns_rdataset_init(&kfetch->keydataset);
@@ -8191,15 +8194,29 @@ zone_refreshkeys(dns_zone_t *zone) {
                dns_db_attach(db, &kfetch->db);
                kfetch->fetch = NULL;
 
-               dns_resolver_createfetch(zone->view->resolver,
-                                        dns_fixedname_name(&kfetch->name),
-                                        dns_rdatatype_dnskey,
-                                        NULL, NULL, NULL,
-                                        DNS_FETCHOPT_NOVALIDATE,
-                                        zone->task, keyfetch_done, kfetch,
-                                        &kfetch->dnskeyset,
-                                        &kfetch->dnskeysigset,
-                                        &kfetch->fetch);
+               result = dns_resolver_createfetch(zone->view->resolver,
+                                                 kname, dns_rdatatype_dnskey,
+                                                 NULL, NULL, NULL,
+                                                 DNS_FETCHOPT_NOVALIDATE,
+                                                 zone->task,
+                                                 keyfetch_done, kfetch,
+                                                 &kfetch->dnskeyset,
+                                                 &kfetch->dnskeysigset,
+                                                 &kfetch->fetch);
+               if (result == ISC_R_SUCCESS)
+                       fetching = ISC_TRUE;
+               else {
+                       zone->refreshkeycount--;
+                       zone->irefs--;
+                       dns_db_detach(&kfetch->db);
+                       dns_rdataset_disassociate(&kfetch->keydataset);
+                       dns_name_free(kname, zone->mctx);
+                       isc_mem_put(zone->mctx, kfetch, sizeof(dns_keyfetch_t));
+                       dns_zone_log(zone, ISC_LOG_WARNING,
+                                    "Failed to create fetch for "
+                                    "DNSKEY update");
+                       fetch_err = ISC_TRUE;
+               }
        }
        if (!ISC_LIST_EMPTY(diff.tuples)) {
                CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
@@ -8211,6 +8228,26 @@ zone_refreshkeys(dns_zone_t *zone) {
        }
 
   failure:
+       if (fetch_err) {
+               /*
+                * Error during a key fetch; retry in an hour.
+                */
+               isc_time_t timenow, timethen;
+               char timebuf[80];
+
+               TIME_NOW(&timenow);
+               DNS_ZONE_TIME_ADD(&timenow, HOUR, &timethen);
+               zone->refreshkeytime = timethen;
+               zone_settimer(zone, &timenow);
+
+               isc_time_formattimestamp(&zone->refreshkeytime, timebuf, 80);
+               dns_zone_log(zone, ISC_LOG_DEBUG(1), "retry key refresh: %s",
+                            timebuf);
+
+               if (!fetching)
+                       DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_REFRESHING);
+       }
+
        UNLOCK_ZONE(zone);
 
        dns_diff_clear(&diff);