summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorInternet Software Consortium, Inc <@isc.org>2011-11-01 14:44:50 -0600
committerInternet Software Consortium, Inc <@isc.org>2011-11-01 14:44:50 -0600
commit15c17fb71db9b8f876da1be5e6ddbba25ce61aba (patch)
tree8f808bcda25300ee1b2bbb66f7fb49ab3a01027a /lib
parent0985d8a79623e77e4d2c801a661d1b1180f41285 (diff)
downloadbind9-15c17fb71db9b8f876da1be5e6ddbba25ce61aba.tar.gz
9.9.0a2
Diffstat (limited to 'lib')
-rw-r--r--lib/bind9/check.c23
-rw-r--r--lib/dns/cache.c20
-rw-r--r--lib/dns/dnssec.c6
-rw-r--r--lib/dns/dst_api.c6
-rw-r--r--lib/dns/gssapictx.c20
-rw-r--r--lib/dns/include/dns/events.h7
-rw-r--r--lib/dns/include/dns/journal.h27
-rw-r--r--lib/dns/include/dns/update.h14
-rw-r--r--lib/dns/include/dns/view.h13
-rw-r--r--lib/dns/include/dns/zone.h59
-rw-r--r--lib/dns/include/dns/zt.h36
-rw-r--r--lib/dns/journal.c83
-rw-r--r--lib/dns/masterdump.c7
-rw-r--r--lib/dns/rbt.c6
-rw-r--r--lib/dns/rdataset.c8
-rw-r--r--lib/dns/spnego.c13
-rw-r--r--lib/dns/tests/Makefile.in15
-rw-r--r--lib/dns/tests/dbiterator_test.c11
-rw-r--r--lib/dns/tests/dnstest.c136
-rw-r--r--lib/dns/tests/dnstest.h33
-rw-r--r--lib/dns/tests/master_test.c57
-rw-r--r--lib/dns/tests/testdata/zt/zone1.db27
-rw-r--r--lib/dns/tests/zonemgr_test.c39
-rw-r--r--lib/dns/tests/zt_test.c262
-rw-r--r--lib/dns/tsig.c26
-rw-r--r--lib/dns/update.c1831
-rw-r--r--lib/dns/view.c18
-rw-r--r--lib/dns/win32/libdns.def5
-rw-r--r--lib/dns/xfrin.c5
-rw-r--r--lib/dns/zone.c736
-rw-r--r--lib/dns/zt.c101
-rw-r--r--lib/isc/include/isc/list.h17
-rw-r--r--lib/isc/include/isc/namespace.h7
-rw-r--r--lib/isc/include/isc/task.h64
-rw-r--r--lib/isc/include/isc/taskpool.h15
-rw-r--r--lib/isc/include/isc/util.h12
-rw-r--r--lib/isc/task.c275
-rw-r--r--lib/isc/task_api.c32
-rw-r--r--lib/isc/task_p.h12
-rw-r--r--lib/isc/taskpool.c15
-rw-r--r--lib/isc/tests/Makefile.in12
-rw-r--r--lib/isc/tests/isctest.c25
-rw-r--r--lib/isc/tests/isctest.h4
-rw-r--r--lib/isc/tests/socket_test.c20
-rw-r--r--lib/isc/tests/task_test.c411
-rw-r--r--lib/isc/tests/taskpool_test.c52
-rw-r--r--lib/isc/unix/socket.c6
-rw-r--r--lib/isc/win32/libisc.def5
-rw-r--r--lib/isccfg/aclconf.c4
-rw-r--r--lib/isccfg/namedconf.c4
-rw-r--r--lib/lwres/getnameinfo.c33
-rw-r--r--lib/lwres/lwinetpton.c13
52 files changed, 4389 insertions, 299 deletions
diff --git a/lib/bind9/check.c b/lib/bind9/check.c
index 2b7b894d..1df7989f 100644
--- a/lib/bind9/check.c
+++ b/lib/bind9/check.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: check.c,v 1.133 2011-06-17 07:05:02 each Exp $ */
+/* $Id: check.c,v 1.134 2011-08-30 05:16:14 marka Exp $ */
/*! \file */
@@ -1225,7 +1225,7 @@ check_update_policy(const cfg_obj_t *policy, isc_log_t *logctx) {
#define STATICSTUBZONE 64
#define REDIRECTZONE 128
#define STREDIRECTZONE 0 /* Set to REDIRECTZONE to allow xfr-in. */
-#define CHECKACL 256
+#define CHECKACL 512
typedef struct {
const char *name;
@@ -1255,7 +1255,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
static optionstable options[] = {
{ "allow-query", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE |
- CHECKACL | STATICSTUBZONE },
+ CHECKACL | STATICSTUBZONE },
{ "allow-notify", SLAVEZONE | CHECKACL },
{ "allow-transfer", MASTERZONE | SLAVEZONE | CHECKACL },
{ "notify", MASTERZONE | SLAVEZONE },
@@ -1279,13 +1279,14 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
{ "max-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
{ "min-refresh-time", SLAVEZONE | STUBZONE | STREDIRECTZONE },
{ "dnssec-secure-to-insecure", MASTERZONE },
- { "sig-validity-interval", MASTERZONE },
- { "sig-re-signing-interval", MASTERZONE },
- { "sig-signing-nodes", MASTERZONE },
- { "sig-signing-type", MASTERZONE },
- { "sig-signing-signatures", MASTERZONE },
+ { "sig-re-signing-interval", MASTERZONE | SLAVEZONE },
+ { "sig-signing-nodes", MASTERZONE | SLAVEZONE },
+ { "sig-signing-signatures", MASTERZONE | SLAVEZONE },
+ { "sig-signing-type", MASTERZONE | SLAVEZONE },
+ { "sig-validity-interval", MASTERZONE | SLAVEZONE },
+ { "signing", MASTERZONE | SLAVEZONE },
{ "zone-statistics", MASTERZONE | SLAVEZONE | STUBZONE |
- STATICSTUBZONE| REDIRECTZONE },
+ STATICSTUBZONE | REDIRECTZONE },
{ "allow-update", MASTERZONE | CHECKACL },
{ "allow-update-forwarding", SLAVEZONE | CHECKACL },
{ "file", MASTERZONE | SLAVEZONE | STUBZONE | HINTZONE | REDIRECTZONE },
@@ -1296,7 +1297,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
{ "pubkey", MASTERZONE | SLAVEZONE | STUBZONE },
{ "update-policy", MASTERZONE },
{ "database", MASTERZONE | SLAVEZONE | STUBZONE | REDIRECTZONE },
- { "key-directory", MASTERZONE },
+ { "key-directory", MASTERZONE | SLAVEZONE },
{ "check-wildcard", MASTERZONE },
{ "check-mx", MASTERZONE },
{ "check-dup-records", MASTERZONE },
@@ -1308,7 +1309,7 @@ check_zoneconf(const cfg_obj_t *zconfig, const cfg_obj_t *voptions,
{ "update-check-ksk", MASTERZONE },
{ "dnssec-dnskey-kskonly", MASTERZONE },
{ "dnssec-loadkeys-interval", MASTERZONE },
- { "auto-dnssec", MASTERZONE },
+ { "auto-dnssec", MASTERZONE | SLAVEZONE },
{ "try-tcp-refresh", SLAVEZONE | STREDIRECTZONE },
{ "server-addresses", STATICSTUBZONE },
{ "server-names", STATICSTUBZONE },
diff --git a/lib/dns/cache.c b/lib/dns/cache.c
index 38821c43..232a752e 100644
--- a/lib/dns/cache.c
+++ b/lib/dns/cache.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: cache.c,v 1.90 2011-08-02 20:36:12 each Exp $ */
+/* $Id: cache.c,v 1.91 2011-08-26 05:12:56 marka Exp $ */
/*! \file */
@@ -1186,7 +1186,7 @@ clearnode(dns_db_t *db, dns_dbnode_t *node) {
static isc_result_t
cleartree(dns_db_t *db, dns_name_t *name) {
- isc_result_t result;
+ isc_result_t result, answer = ISC_R_SUCCESS;
dns_dbiterator_t *iter = NULL;
dns_dbnode_t *node = NULL;
dns_fixedname_t fnodename;
@@ -1205,12 +1205,22 @@ cleartree(dns_db_t *db, dns_name_t *name) {
while (result == ISC_R_SUCCESS) {
result = dns_dbiterator_current(iter, &node, nodename);
- if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
+ if (result == DNS_R_NEWORIGIN)
+ result = ISC_R_SUCCESS;
+ if (result != ISC_R_SUCCESS)
goto cleanup;
+ /*
+ * Are we done?
+ */
if (! dns_name_issubdomain(nodename, name))
goto cleanup;
+ /*
+ * If clearnode fails record and move onto the next node.
+ */
result = clearnode(db, node);
+ if (result != ISC_R_SUCCESS && answer == ISC_R_SUCCESS)
+ answer = result;
dns_db_detachnode(db, &node);
result = dns_dbiterator_next(iter);
}
@@ -1218,12 +1228,14 @@ cleartree(dns_db_t *db, dns_name_t *name) {
cleanup:
if (result == ISC_R_NOMORE || result == ISC_R_NOTFOUND)
result = ISC_R_SUCCESS;
+ if (result != ISC_R_SUCCESS && answer == ISC_R_SUCCESS)
+ answer = result;
if (node != NULL)
dns_db_detachnode(db, &node);
if (iter != NULL)
dns_dbiterator_destroy(&iter);
- return (result);
+ return (answer);
}
isc_result_t
diff --git a/lib/dns/dnssec.c b/lib/dns/dnssec.c
index 33cfd361..3c568c73 100644
--- a/lib/dns/dnssec.c
+++ b/lib/dns/dnssec.c
@@ -16,7 +16,7 @@
*/
/*
- * $Id: dnssec.c,v 1.124 2011-05-06 21:08:33 each Exp $
+ * $Id: dnssec.c,v 1.125 2011-08-26 05:29:48 marka Exp $
*/
/*! \file */
@@ -1705,10 +1705,8 @@ dns_dnssec_updatekeys(dns_dnsseckeylist_t *keys, dns_dnsseckeylist_t *newkeys,
shortest = thisttl;
}
- if (shortest != 0) {
- found_ttl = ISC_TRUE;
+ if (shortest != 0)
ttl = shortest;
- }
}
/*
diff --git a/lib/dns/dst_api.c b/lib/dns/dst_api.c
index c8e4e897..5a490c05 100644
--- a/lib/dns/dst_api.c
+++ b/lib/dns/dst_api.c
@@ -31,7 +31,7 @@
/*
* Principal Author: Brian Wellington
- * $Id: dst_api.c,v 1.63 2011-08-18 23:46:34 tbox Exp $
+ * $Id: dst_api.c,v 1.64 2011-09-05 18:00:22 each Exp $
*/
/*! \file */
@@ -1579,7 +1579,7 @@ write_public_key(const dst_key_t *key, int type, const char *directory) {
fprintf(fp, "%d ", key->key_ttl);
isc_buffer_usedregion(&classb, &r);
- if ((unsigned)isc_util_fwrite(r.base, 1, r.length, fp) != r.length)
+ if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length)
ret = DST_R_WRITEERROR;
if ((type & DST_TYPE_KEY) != 0)
@@ -1588,7 +1588,7 @@ write_public_key(const dst_key_t *key, int type, const char *directory) {
fprintf(fp, " DNSKEY ");
isc_buffer_usedregion(&textb, &r);
- if ((unsigned)isc_util_fwrite(r.base, 1, r.length, fp) != r.length)
+ if ((unsigned) fwrite(r.base, 1, r.length, fp) != r.length)
ret = DST_R_WRITEERROR;
fputc('\n', fp);
diff --git a/lib/dns/gssapictx.c b/lib/dns/gssapictx.c
index a6c5f450..938671c1 100644
--- a/lib/dns/gssapictx.c
+++ b/lib/dns/gssapictx.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: gssapictx.c,v 1.28 2011-04-07 23:03:22 marka Exp $ */
+/* $Id: gssapictx.c,v 1.29 2011-08-29 06:33:25 marka Exp $ */
#include <config.h>
@@ -135,6 +135,7 @@ name_to_gbuffer(dns_name_t *name, isc_buffer_t *buffer,
}
result = dns_name_toprincipal(namep, buffer);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_buffer_putuint8(buffer, 0);
isc_buffer_usedregion(buffer, &r);
REGION_TO_GBUFFER(r, *gbuffer);
@@ -309,7 +310,7 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate,
if (gret != GSS_S_COMPLETE) {
gss_log(3, "failed to acquire %s credentials for %s: %s",
initiate ? "initiate" : "accept",
- (char *)gnamebuf.value,
+ (gname != NULL) ? (char *)gnamebuf.value : "?",
gss_error_tostring(gret, minor, buf, sizeof(buf)));
check_config((char *)array);
return (ISC_R_FAILURE);
@@ -317,12 +318,14 @@ dst_gssapi_acquirecred(dns_name_t *name, isc_boolean_t initiate,
gss_log(4, "acquired %s credentials for %s",
initiate ? "initiate" : "accept",
- (char *)gnamebuf.value);
+ (gname != NULL) ? (char *)gnamebuf.value : "?");
log_cred(*cred);
return (ISC_R_SUCCESS);
#else
+ REQUIRE(cred != NULL && *cred == NULL);
+
UNUSED(name);
UNUSED(initiate);
UNUSED(cred);
@@ -342,13 +345,15 @@ dst_gssapi_identitymatchesrealmkrb5(dns_name_t *signer, dns_name_t *name,
char *sname;
char *rname;
isc_buffer_t buffer;
+ isc_result_t result;
/*
* It is far, far easier to write the names we are looking at into
* a string, and do string operations on them.
*/
isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
- dns_name_toprincipal(signer, &buffer);
+ result = dns_name_toprincipal(signer, &buffer);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_buffer_putuint8(&buffer, 0);
if (name != NULL)
dns_name_format(name, nbuf, sizeof(nbuf));
@@ -414,13 +419,15 @@ dst_gssapi_identitymatchesrealmms(dns_name_t *signer, dns_name_t *name,
char *nname;
char *rname;
isc_buffer_t buffer;
+ isc_result_t result;
/*
* It is far, far easier to write the names we are looking at into
* a string, and do string operations on them.
*/
isc_buffer_init(&buffer, sbuf, sizeof(sbuf));
- dns_name_toprincipal(signer, &buffer);
+ result = dns_name_toprincipal(signer, &buffer);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
isc_buffer_putuint8(&buffer, 0);
if (name != NULL)
dns_name_format(name, nbuf, sizeof(nbuf));
@@ -664,8 +671,7 @@ dst_gssapi_acceptctx(gss_cred_id_t cred,
gss_log(3, "failed "
"gsskrb5_register_acceptor_identity(%s): %s",
gssapi_keytab,
- gss_error_tostring(gret, minor,
- buf, sizeof(buf)));
+ gss_error_tostring(gret, 0, buf, sizeof(buf)));
return (DNS_R_INVALIDTKEY);
}
#else
diff --git a/lib/dns/include/dns/events.h b/lib/dns/include/dns/events.h
index d9858336..88c2719c 100644
--- a/lib/dns/include/dns/events.h
+++ b/lib/dns/include/dns/events.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007, 2009, 2010 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007, 2009-2011 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2002 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: events.h,v 1.56 2010-12-21 03:11:42 marka Exp $ */
+/* $Id: events.h,v 1.59 2011-09-02 21:15:36 each Exp $ */
#ifndef DNS_EVENTS_H
#define DNS_EVENTS_H 1
@@ -74,6 +74,9 @@
#define DNS_EVENT_CLIENTREQDONE (ISC_EVENTCLASS_DNS + 44)
#define DNS_EVENT_ADBGROWENTRIES (ISC_EVENTCLASS_DNS + 45)
#define DNS_EVENT_ADBGROWNAMES (ISC_EVENTCLASS_DNS + 46)
+#define DNS_EVENT_ZONESECURESERIAL (ISC_EVENTCLASS_DNS + 47)
+#define DNS_EVENT_ZONESECUREDB (ISC_EVENTCLASS_DNS + 48)
+#define DNS_EVENT_ZONELOAD (ISC_EVENTCLASS_DNS + 49)
#define DNS_EVENT_FIRSTEVENT (ISC_EVENTCLASS_DNS + 0)
#define DNS_EVENT_LASTEVENT (ISC_EVENTCLASS_DNS + 65535)
diff --git a/lib/dns/include/dns/journal.h b/lib/dns/include/dns/journal.h
index 28a7dbe3..c5024a37 100644
--- a/lib/dns/include/dns/journal.h
+++ b/lib/dns/include/dns/journal.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2009, 2011 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: journal.h,v 1.37 2009-11-04 23:48:18 tbox Exp $ */
+/* $Id: journal.h,v 1.39 2011-08-30 23:46:53 tbox Exp $ */
#ifndef DNS_JOURNAL_H
#define DNS_JOURNAL_H 1
@@ -46,6 +46,10 @@
***/
#define DNS_JOURNALOPT_RESIGN 0x00000001
+#define DNS_JOURNAL_READ 0x00000000 /* ISC_FALSE */
+#define DNS_JOURNAL_CREATE 0x00000001 /* ISC_TRUE */
+#define DNS_JOURNAL_WRITE 0x00000002
+
/***
*** Types
***/
@@ -95,16 +99,15 @@ dns_db_createsoatuple(dns_db_t *db, dns_dbversion_t *ver, isc_mem_t *mctx,
*/
isc_result_t
-dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
+dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode,
dns_journal_t **journalp);
/*%<
* Open the journal file 'filename' and create a dns_journal_t object for it.
*
- * If 'write' is ISC_TRUE, the journal is open for writing. If it does
- * not exist, it is created.
- *
- * If 'write' is ISC_FALSE, the journal is open for reading. If it does
- * not exist, ISC_R_NOTFOUND is returned.
+ * DNS_JOURNAL_CREATE open the journal for reading and writing and create
+ * the journal if it does not exist.
+ * DNS_JOURNAL_WRITE open the journal for readinge and writing.
+ * DNS_JOURNAL_READ open the journal for reading only.
*/
void
@@ -284,6 +287,14 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
* exists and is non-empty 'serial' must exist in the journal.
*/
+isc_uint32_t
+dns_journal_get_bitws(dns_journal_t *j);
+void
+dns_journal_set_bitws(dns_journal_t *j, isc_uint32_t bitws);
+/*%<
+ * Get and set bump in the wire serial.
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_JOURNAL_H */
diff --git a/lib/dns/include/dns/update.h b/lib/dns/include/dns/update.h
index cf5d0146..31239999 100644
--- a/lib/dns/include/dns/update.h
+++ b/lib/dns/include/dns/update.h
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: update.h,v 1.2 2011-07-01 02:25:48 marka Exp $ */
+/* $Id: update.h,v 1.5 2011-08-30 23:46:53 tbox Exp $ */
#ifndef DNS_UPDATE_H
#define DNS_UPDATE_H 1
@@ -28,6 +28,13 @@
#include <isc/lang.h>
#include <dns/types.h>
+#include <dns/diff.h>
+
+typedef struct {
+ void (*func)(void *arg, dns_zone_t *zone, int level,
+ const char *message);
+ void *arg;
+} dns_update_log_t;
ISC_LANG_BEGINDECLS
@@ -47,6 +54,11 @@ dns_update_soaserial(isc_uint32_t serial, dns_updatemethod_t method);
* if not.
*/
+isc_result_t
+dns_update_signatures(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
+ dns_dbversion_t *oldver, dns_dbversion_t *newver,
+ dns_diff_t *diff, isc_uint32_t sigvalidityinterval);
+
ISC_LANG_ENDDECLS
#endif /* DNS_UPDATE_H */
diff --git a/lib/dns/include/dns/view.h b/lib/dns/include/dns/view.h
index 9b6e2e66..690ca7a5 100644
--- a/lib/dns/include/dns/view.h
+++ b/lib/dns/include/dns/view.h
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: view.h,v 1.134 2011-08-02 20:36:13 each Exp $ */
+/* $Id: view.h,v 1.136 2011-09-06 22:29:33 smann Exp $ */
#ifndef DNS_VIEW_H
#define DNS_VIEW_H 1
@@ -76,6 +76,7 @@
#include <dns/rdatastruct.h>
#include <dns/rpz.h>
#include <dns/types.h>
+#include <dns/zt.h>
ISC_LANG_BEGINDECLS
@@ -141,7 +142,6 @@ struct dns_view {
dns_rbt_t * answeracl_exclude;
dns_rbt_t * denyanswernames;
dns_rbt_t * answernames_exclude;
- isc_boolean_t requestixfr;
isc_boolean_t provideixfr;
isc_boolean_t requestnsid;
dns_ttl_t maxcachettl;
@@ -728,14 +728,21 @@ dns_view_load(dns_view_t *view, isc_boolean_t stop);
isc_result_t
dns_view_loadnew(dns_view_t *view, isc_boolean_t stop);
+
+isc_result_t
+dns_view_asyncload(dns_view_t *view, dns_zt_allloaded_t callback, void *arg);
/*%<
* Load zones attached to this view. dns_view_load() loads
* all zones whose master file has changed since the last
* load; dns_view_loadnew() loads only zones that have never
* been loaded.
*
+ * dns_view_asyncload() loads zones asynchronously. When all zones
+ * in the view have finished loading, 'callback' is called with argument
+ * 'arg' to inform the caller.
+ *
* If 'stop' is ISC_TRUE, stop on the first error and return it.
- * If 'stop' is ISC_FALSE, ignore errors.
+ * If 'stop' is ISC_FALSE (or we are loading asynchronously), ignore errors.
*
* Requires:
*
diff --git a/lib/dns/include/dns/zone.h b/lib/dns/include/dns/zone.h
index 6e4e2e3f..1d8e434c 100644
--- a/lib/dns/include/dns/zone.h
+++ b/lib/dns/include/dns/zone.h
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.h,v 1.191 2011-07-06 01:36:32 each Exp $ */
+/* $Id: zone.h,v 1.194 2011-09-06 22:29:33 smann Exp $ */
#ifndef DNS_ZONE_H
#define DNS_ZONE_H 1
@@ -35,6 +35,7 @@
#include <dns/masterdump.h>
#include <dns/rdatastruct.h>
#include <dns/types.h>
+#include <dns/zt.h>
typedef enum {
dns_zone_none,
@@ -44,7 +45,7 @@ typedef enum {
dns_zone_staticstub,
dns_zone_key,
dns_zone_dlz,
- dns_zone_redirect,
+ dns_zone_redirect
} dns_zonetype_t;
#define DNS_ZONEOPT_SERVERS 0x00000001U /*%< perform server checks */
@@ -287,6 +288,7 @@ dns_zone_loadnew(dns_zone_t *zone);
isc_result_t
dns_zone_loadandthaw(dns_zone_t *zone);
+
/*%<
* Cause the database to be loaded from its backing store.
* Confirm that the minimum requirements for the zone type are
@@ -311,6 +313,25 @@ dns_zone_loadandthaw(dns_zone_t *zone);
*\li Any result value from dns_db_load().
*/
+isc_result_t
+dns_zone_asyncload(dns_zone_t *zone, dns_zt_zoneloaded_t done, void *arg);
+/*%<
+ * Cause the database to be loaded from its backing store asynchronously.
+ * Other zone maintenance functions are suspended until this is complete.
+ * When finished, 'done' is called to inform the caller, with 'arg' as
+ * its first argument and 'zone' as its second. (Normally, 'arg' is
+ * expected to point to the zone table but is left undefined for testing
+ * purposes.)
+ */
+
+isc_boolean_t
+dns__zone_loadpending(dns_zone_t *zone);
+/*%<
+ * Indicates whether the zone is waiting to be loaded asynchronously.
+ * (Not currently intended for use outside of this module and associated
+ * tests.)
+ */
+
void
dns_zone_attach(dns_zone_t *source, dns_zone_t **target);
/*%<
@@ -1428,6 +1449,14 @@ dns_zonemgr_forcemaint(dns_zonemgr_t *zmgr);
*/
void
+dns__zonemgr_run(isc_task_t *task, isc_event_t *event);
+/*%<
+ * Event handler to call dns_zonemgr_forcemaint(); used to start
+ * zone operations from a unit test. Not intended for use outside
+ * libdns or related tests.
+ */
+
+void
dns_zonemgr_resumexfrs(dns_zonemgr_t *zmgr);
/*%<
* Attempt to start any stalled zone transfers.
@@ -1903,6 +1932,25 @@ dns_zone_setrefreshkeyinterval(dns_zone_t *zone, isc_uint32_t interval);
* \li 'zone' to be valid.
*/
+isc_boolean_t
+dns_zone_getrequestixfr(dns_zone_t *zone);
+/*%
+ * Returns the true/false value of the request-ixfr option in the zone.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ */
+
+void
+dns_zone_setrequestixfr(dns_zone_t *zone, isc_boolean_t flag);
+/*%
+ * Sets the request-ixfr option for the zone. Either true or false. The
+ * default value is determined by the setting of this option in the view.
+ *
+ * Requires:
+ * \li 'zone' to be valid.
+ */
+
void
dns_zone_setserialupdatemethod(dns_zone_t *zone, dns_updatemethod_t method);
/*%
@@ -1923,6 +1971,13 @@ dns_zone_getserialupdatemethod(dns_zone_t *zone);
* Requires:
* \li 'zone' to be valid.
*/
+
+void
+dns_zone_link(dns_zone_t *zone, dns_zone_t *raw);
+
+void
+dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw);
+
ISC_LANG_ENDDECLS
#endif /* DNS_ZONE_H */
diff --git a/lib/dns/include/dns/zt.h b/lib/dns/include/dns/zt.h
index 6e5ef5c6..e636fc68 100644
--- a/lib/dns/include/dns/zt.h
+++ b/lib/dns/include/dns/zt.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004-2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004-2007, 2011 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2002 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zt.h,v 1.38 2007-06-19 23:47:17 tbox Exp $ */
+/* $Id: zt.h,v 1.40 2011-09-02 23:46:32 tbox Exp $ */
#ifndef DNS_ZT_H
#define DNS_ZT_H 1
@@ -30,6 +30,21 @@
ISC_LANG_BEGINDECLS
+typedef isc_result_t
+(*dns_zt_allloaded_t)(void *arg);
+/*%<
+ * Method prototype: when all pending zone loads are complete,
+ * the zone table can inform the caller via a callback function with
+ * this signature.
+ */
+
+typedef isc_result_t
+(*dns_zt_zoneloaded_t)(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task);
+/*%<
+ * Method prototype: when a zone finishes loading, the zt object
+ * can be informed via a callback function with this signature.
+ */
+
isc_result_t
dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **zt);
/*%<
@@ -134,6 +149,9 @@ dns_zt_load(dns_zt_t *zt, isc_boolean_t stop);
isc_result_t
dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop);
+
+isc_result_t
+dns_zt_asyncload(dns_zt_t *zt, dns_zt_allloaded_t alldone, void *arg);
/*%<
* Load all zones in the table. If 'stop' is ISC_TRUE,
* stop on the first error and return it. If 'stop'
@@ -142,6 +160,10 @@ dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop);
* dns_zt_loadnew() only loads zones that are not yet loaded.
* dns_zt_load() also loads zones that are already loaded and
* and whose master file has changed since the last load.
+ * dns_zt_asyncload() loads zones asynchronously; when all
+ * zones in the zone table have finished loaded (or failed due
+ * to errors), the caller is informed by calling 'alldone'
+ * with an argument of 'arg'.
*
* Requires:
* \li 'zt' to be valid
@@ -178,6 +200,16 @@ dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub,
* any error code from 'action'.
*/
+isc_boolean_t
+dns_zt_loadspending(dns_zt_t *zt);
+/*%<
+ * Returns ISC_TRUE if and only if there are zones still waiting to
+ * be loaded in zone table 'zt'.
+ *
+ * Requires:
+ * \li 'zt' to be valid.
+ */
+
ISC_LANG_ENDDECLS
#endif /* DNS_ZT_H */
diff --git a/lib/dns/journal.c b/lib/dns/journal.c
index c6350d63..16fe541b 100644
--- a/lib/dns/journal.c
+++ b/lib/dns/journal.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: journal.c,v 1.114 2011-03-12 04:59:48 tbox Exp $ */
+/* $Id: journal.c,v 1.116 2011-08-30 23:46:52 tbox Exp $ */
#include <config.h>
@@ -213,6 +213,8 @@ typedef union {
journal_rawpos_t end;
/*% Number of index entries following the header. */
unsigned char index_size[4];
+ /*% Bump in the wire serial. */
+ unsigned char bitws[4];
} h;
/* Pad the header to a fixed size. */
unsigned char pad[JOURNAL_HEADER_SIZE];
@@ -252,6 +254,7 @@ typedef struct {
journal_pos_t begin;
journal_pos_t end;
isc_uint32_t index_size;
+ isc_uint32_t bitws;
} journal_header_t;
/*%
@@ -284,7 +287,7 @@ typedef struct {
*/
static journal_header_t
-initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0 };
+initial_journal_header = { ";BIND LOG V9\n", { 0, 0 }, { 0, 0 }, 0, 0 };
#define JOURNAL_EMPTY(h) ((h)->begin.offset == (h)->end.offset)
@@ -292,7 +295,8 @@ typedef enum {
JOURNAL_STATE_INVALID,
JOURNAL_STATE_READ,
JOURNAL_STATE_WRITE,
- JOURNAL_STATE_TRANSACTION
+ JOURNAL_STATE_TRANSACTION,
+ JOURNAL_STATE_BITWS
} journal_state_t;
struct dns_journal {
@@ -353,6 +357,7 @@ journal_header_decode(journal_rawheader_t *raw, journal_header_t *cooked) {
journal_pos_decode(&raw->h.begin, &cooked->begin);
journal_pos_decode(&raw->h.end, &cooked->end);
cooked->index_size = decode_uint32(raw->h.index_size);
+ cooked->bitws = decode_uint32(raw->h.bitws);
}
static void
@@ -363,6 +368,7 @@ journal_header_encode(journal_header_t *cooked, journal_rawheader_t *raw) {
journal_pos_encode(&raw->h.begin, &cooked->begin);
journal_pos_encode(&raw->h.end, &cooked->end);
encode_uint32(cooked->index_size, raw->h.index_size);
+ encode_uint32(cooked->bitws, raw->h.bitws);
}
/*
@@ -667,13 +673,17 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
}
isc_result_t
-dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
+dns_journal_open(isc_mem_t *mctx, const char *filename, unsigned int mode,
dns_journal_t **journalp) {
isc_result_t result;
int namelen;
char backup[1024];
+ isc_boolean_t write, create;
- result = journal_open(mctx, filename, write, write, journalp);
+ create = ISC_TF(mode & DNS_JOURNAL_CREATE);
+ write = ISC_TF(mode & (DNS_JOURNAL_WRITE|DNS_JOURNAL_CREATE));
+
+ result = journal_open(mctx, filename, write, create, journalp);
if (result == ISC_R_NOTFOUND) {
namelen = strlen(filename);
if (namelen > 4 && strcmp(filename + namelen - 4, ".jnl") == 0)
@@ -944,7 +954,8 @@ dns_journal_begin_transaction(dns_journal_t *j) {
journal_rawxhdr_t hdr;
REQUIRE(DNS_JOURNAL_VALID(j));
- REQUIRE(j->state == JOURNAL_STATE_WRITE);
+ REQUIRE(j->state == JOURNAL_STATE_WRITE ||
+ j->state == JOURNAL_STATE_BITWS);
/*
* Find the file offset where the new transaction should
@@ -1067,7 +1078,21 @@ dns_journal_commit(dns_journal_t *j) {
journal_rawheader_t rawheader;
REQUIRE(DNS_JOURNAL_VALID(j));
- REQUIRE(j->state == JOURNAL_STATE_TRANSACTION);
+ REQUIRE(j->state == JOURNAL_STATE_TRANSACTION ||
+ j->state == JOURNAL_STATE_BITWS);
+
+ /*
+ * Just write out a updated header.
+ */
+ if (j->state == JOURNAL_STATE_BITWS) {
+ CHECK(journal_fsync(j));
+ journal_header_encode(&j->header, &rawheader);
+ CHECK(journal_seek(j, 0));
+ CHECK(journal_write(j, &rawheader, sizeof(rawheader)));
+ CHECK(journal_fsync(j));
+ j->state = JOURNAL_STATE_WRITE;
+ return (ISC_R_SUCCESS);
+ }
/*
* Perform some basic consistency checks.
@@ -1124,19 +1149,24 @@ dns_journal_commit(dns_journal_t *j) {
*/
CHECK(journal_fsync(j));
- /*
- * Update the transaction header.
- */
- CHECK(journal_seek(j, j->x.pos[0].offset));
- CHECK(journal_write_xhdr(j, (j->x.pos[1].offset - j->x.pos[0].offset) -
- sizeof(journal_rawxhdr_t),
- j->x.pos[0].serial, j->x.pos[1].serial));
+ if (j->state == JOURNAL_STATE_TRANSACTION) {
+ isc_offset_t offset;
+ offset = (j->x.pos[1].offset - j->x.pos[0].offset) -
+ sizeof(journal_rawxhdr_t);
+ /*
+ * Update the transaction header.
+ */
+ CHECK(journal_seek(j, j->x.pos[0].offset));
+ CHECK(journal_write_xhdr(j, offset, j->x.pos[0].serial,
+ j->x.pos[1].serial));
+ }
/*
* Update the journal header.
*/
if (JOURNAL_EMPTY(&j->header)) {
j->header.begin = j->x.pos[0];
+ j->header.bitws = j->header.begin.serial;
}
j->header.end = j->x.pos[1];
journal_header_encode(&j->header, &rawheader);
@@ -1415,6 +1445,7 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
return (result);
}
+ fprintf(file, "BITWS = %u\n", j->header.bitws);
dns_diff_init(j->mctx, &diff);
/*
@@ -1497,14 +1528,33 @@ dns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) {
/*
* Miscellaneous accessors.
*/
-isc_uint32_t dns_journal_first_serial(dns_journal_t *j) {
+isc_uint32_t
+dns_journal_first_serial(dns_journal_t *j) {
return (j->header.begin.serial);
}
-isc_uint32_t dns_journal_last_serial(dns_journal_t *j) {
+isc_uint32_t
+dns_journal_last_serial(dns_journal_t *j) {
return (j->header.end.serial);
}
+void
+dns_journal_set_bitws(dns_journal_t *j, isc_uint32_t bitws) {
+
+ REQUIRE(j->state == JOURNAL_STATE_WRITE ||
+ j->state == JOURNAL_STATE_BITWS ||
+ j->state == JOURNAL_STATE_TRANSACTION);
+
+ j->header.bitws = bitws;
+ if (j->state == JOURNAL_STATE_WRITE)
+ j->state = JOURNAL_STATE_BITWS;
+}
+
+isc_uint32_t
+dns_journal_get_bitws(dns_journal_t *j) {
+ return (j->header.bitws);
+}
+
/**************************************************************************/
/*
* Iteration support.
@@ -2145,6 +2195,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
new->header.begin.offset = indexend;
new->header.end.serial = j->header.end.serial;
new->header.end.offset = indexend + copy_length;
+ new->header.bitws = j->header.bitws;
/*
* Update the journal header.
diff --git a/lib/dns/masterdump.c b/lib/dns/masterdump.c
index 8d911c10..61a9cfc1 100644
--- a/lib/dns/masterdump.c
+++ b/lib/dns/masterdump.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: masterdump.c,v 1.108 2011-06-08 22:13:50 each Exp $ */
+/* $Id: masterdump.c,v 1.109 2011-09-07 19:11:13 each Exp $ */
/*! \file */
@@ -419,12 +419,11 @@ rdataset_totext(dns_rdataset_t *rdataset,
rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
result = dns_rdataset_first(rdataset);
- REQUIRE(result == ISC_R_SUCCESS);
current_ttl = ctx->current_ttl;
current_ttl_valid = ctx->current_ttl_valid;
- do {
+ while (result == ISC_R_SUCCESS) {
column = 0;
/*
@@ -550,7 +549,7 @@ rdataset_totext(dns_rdataset_t *rdataset,
first = ISC_FALSE;
result = dns_rdataset_next(rdataset);
- } while (result == ISC_R_SUCCESS);
+ }
if (result != ISC_R_NOMORE)
return (result);
diff --git a/lib/dns/rbt.c b/lib/dns/rbt.c
index 1b4ff3ac..38f3fc15 100644
--- a/lib/dns/rbt.c
+++ b/lib/dns/rbt.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rbt.c,v 1.148 2011-03-12 04:59:48 tbox Exp $ */
+/* $Id: rbt.c,v 1.149 2011-08-25 05:56:50 marka Exp $ */
/*! \file */
@@ -1929,6 +1929,8 @@ dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {
sibling = RIGHT(parent);
}
+ INSIST(sibling != NULL);
+
if (IS_BLACK(LEFT(sibling)) &&
IS_BLACK(RIGHT(sibling))) {
MAKE_RED(sibling);
@@ -1965,6 +1967,8 @@ dns_rbt_deletefromlevel(dns_rbtnode_t *delete, dns_rbtnode_t **rootp) {
sibling = LEFT(parent);
}
+ INSIST(sibling != NULL);
+
if (IS_BLACK(LEFT(sibling)) &&
IS_BLACK(RIGHT(sibling))) {
MAKE_RED(sibling);
diff --git a/lib/dns/rdataset.c b/lib/dns/rdataset.c
index 93f67f9c..979abb56 100644
--- a/lib/dns/rdataset.c
+++ b/lib/dns/rdataset.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdataset.c,v 1.90 2011-06-08 22:13:50 each Exp $ */
+/* $Id: rdataset.c,v 1.91 2011-08-25 06:28:11 marka Exp $ */
/*! \file */
@@ -442,11 +442,11 @@ towiresorted(dns_rdataset_t *rdataset, const dns_name_t *owner_name,
j = val % count;
for (i = 0; i < count; i++) {
if (order != NULL)
- sorted[j].key = (*order)(&shuffled[i],
+ sorted[i].key = (*order)(&shuffled[j],
order_arg);
else
- sorted[j].key = 0; /* Unused */
- sorted[j].rdata = &shuffled[i];
+ sorted[i].key = 0; /* Unused */
+ sorted[i].rdata = &shuffled[j];
j++;
if (j == count)
j = 0; /* Wrap around. */
diff --git a/lib/dns/spnego.c b/lib/dns/spnego.c
index f71d6cc6..8f1b067c 100644
--- a/lib/dns/spnego.c
+++ b/lib/dns/spnego.c
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: spnego.c,v 1.18 2011-04-04 11:09:11 marka Exp $ */
+/* $Id: spnego.c,v 1.20 2011-08-29 04:15:50 marka Exp $ */
/*! \file
* \brief
@@ -948,8 +948,9 @@ der_match_tag_and_length(const unsigned char *p, size_t len,
e = der_get_length(p, len, length_ret, &l);
if (e)
return (e);
- p += l;
+ /* p += l; */
len -= l;
+ POST(len);
ret += l;
if (size)
*size = ret;
@@ -980,6 +981,7 @@ decode_enumerated(const unsigned char *p, size_t len, void *num, size_t *size)
return (e);
p += l;
len -= l;
+ POST(p); POST(len);
ret += l;
if (size)
*size = ret;
@@ -1016,6 +1018,7 @@ decode_octet_string(const unsigned char *p, size_t len,
return (e);
p += l;
len -= l;
+ POST(p); POST(len);
ret += l;
if (size)
*size = ret;
@@ -1052,6 +1055,7 @@ decode_oid(const unsigned char *p, size_t len,
return (e);
p += l;
len -= l;
+ POST(p); POST(len);
ret += l;
if (size)
*size = ret;
@@ -1198,6 +1202,7 @@ der_put_octet_string(unsigned char *p, size_t len,
return (ASN1_OVERFLOW);
p -= data->length;
len -= data->length;
+ POST(len);
memcpy(p + 1, data->data, data->length);
*size = data->length;
return (0);
@@ -1263,6 +1268,7 @@ der_put_length_and_tag(unsigned char *p, size_t len, size_t len_val,
return (e);
p -= l;
len -= l;
+ POST(p); POST(len);
ret += l;
*size = ret;
return (0);
@@ -1287,6 +1293,7 @@ encode_enumerated(unsigned char *p, size_t len, const void *data, size_t *size)
return (e);
p -= l;
len -= l;
+ POST(p); POST(len);
ret += l;
*size = ret;
return (0);
@@ -1311,6 +1318,7 @@ encode_octet_string(unsigned char *p, size_t len,
return (e);
p -= l;
len -= l;
+ POST(p); POST(len);
ret += l;
*size = ret;
return (0);
@@ -1335,6 +1343,7 @@ encode_oid(unsigned char *p, size_t len,
return (e);
p -= l;
len -= l;
+ POST(p); POST(len);
ret += l;
*size = ret;
return (0);
diff --git a/lib/dns/tests/Makefile.in b/lib/dns/tests/Makefile.in
index 0056d9d4..bf18e285 100644
--- a/lib/dns/tests/Makefile.in
+++ b/lib/dns/tests/Makefile.in
@@ -12,7 +12,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.7 2011-08-23 01:29:38 each Exp $
+# $Id: Makefile.in,v 1.8 2011-09-02 21:15:37 each Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@@ -37,12 +37,12 @@ DNSDEPLIBS = ../libdns.@A@
LIBS = @LIBS@ @ATFLIBS@
OBJS = dnstest.@O@
-SRCS = dnstest.c master_test.c time_test.c update_test.c \
- zonemgr_test.c dbiterator_test.c
+SRCS = dnstest.c master_test.c dbiterator_test.c time_test.c \
+ update_test.c zonemgr_test.c zt_test.c
SUBDIRS =
-TARGETS = master_test@EXEEXT@ time_test@EXEEXT@ update_test@EXEEXT@ \
- zonemgr_test@EXEEXT@ dbiterator_test@EXEEXT@
+TARGETS = master_test@EXEEXT@ dbiterator_test@EXEEXT@ time_test@EXEEXT@ \
+ update_test@EXEEXT@ zonemgr_test@EXEEXT@ zt_test@EXEEXT@
@BIND9_MAKE_RULES@
@@ -71,6 +71,11 @@ dbiterator_test@EXEEXT@: dbiterator_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPL
dbiterator_test.@O@ dnstest.@O@ ${DNSLIBS} \
${ISCLIBS} ${LIBS}
+zt_test@EXEEXT@: zt_test.@O@ dnstest.@O@ ${ISCDEPLIBS} ${DNSDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ zt_test.@O@ dnstest.@O@ ${DNSLIBS} \
+ ${ISCLIBS} ${LIBS}
+
unit::
sh ${top_srcdir}/unit/unittest.sh
diff --git a/lib/dns/tests/dbiterator_test.c b/lib/dns/tests/dbiterator_test.c
index b8787a9e..12af6908 100644
--- a/lib/dns/tests/dbiterator_test.c
+++ b/lib/dns/tests/dbiterator_test.c
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dbiterator_test.c,v 1.4 2011-08-23 23:54:00 tbox Exp $ */
+/* $Id: dbiterator_test.c,v 1.5 2011-08-29 23:44:07 marka Exp $ */
/*! \file */
@@ -161,6 +161,9 @@ test_walk(const atf_tc_t *tc) {
result == ISC_R_SUCCESS;
result = dns_dbiterator_next(iter)) {
result = dns_dbiterator_current(iter, &node, name);
+ if (result == DNS_R_NEWORIGIN)
+ result = ISC_R_SUCCESS;
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
dns_db_detachnode(db, &node);
i++;
}
@@ -221,6 +224,9 @@ static void test_reverse(const atf_tc_t *tc) {
result == ISC_R_SUCCESS;
result = dns_dbiterator_prev(iter)) {
result = dns_dbiterator_current(iter, &node, name);
+ if (result == DNS_R_NEWORIGIN)
+ result = ISC_R_SUCCESS;
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
dns_db_detachnode(db, &node);
i++;
}
@@ -285,6 +291,9 @@ static void test_seek(const atf_tc_t *tc) {
while (result == ISC_R_SUCCESS) {
result = dns_dbiterator_current(iter, &node, name);
+ if (result == DNS_R_NEWORIGIN)
+ result = ISC_R_SUCCESS;
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
dns_db_detachnode(db, &node);
result = dns_dbiterator_next(iter);
i++;
diff --git a/lib/dns/tests/dnstest.c b/lib/dns/tests/dnstest.c
index 300a429b..019154ab 100644
--- a/lib/dns/tests/dnstest.c
+++ b/lib/dns/tests/dnstest.c
@@ -14,12 +14,15 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnstest.c,v 1.4 2011-07-06 01:36:32 each Exp $ */
+/* $Id: dnstest.c,v 1.7 2011-09-03 19:22:43 each Exp $ */
/*! \file */
#include <config.h>
+#include <time.h>
+#include <unistd.h>
+
#include <isc/app.h>
#include <isc/buffer.h>
#include <isc/entropy.h>
@@ -32,9 +35,12 @@
#include <isc/timer.h>
#include <isc/util.h>
+#include <dns/fixedname.h>
#include <dns/log.h>
#include <dns/name.h>
#include <dns/result.h>
+#include <dns/view.h>
+#include <dns/zone.h>
#include <dst/dst.h>
@@ -44,8 +50,11 @@ isc_mem_t *mctx = NULL;
isc_entropy_t *ectx = NULL;
isc_log_t *lctx = NULL;
isc_taskmgr_t *taskmgr = NULL;
+isc_task_t *maintask = NULL;
isc_timermgr_t *timermgr = NULL;
isc_socketmgr_t *socketmgr = NULL;
+dns_zonemgr_t *zonemgr = NULL;
+isc_boolean_t app_running = ISC_FALSE;
int ncpus;
static isc_boolean_t hash_active = ISC_FALSE, dst_active = ISC_FALSE;
@@ -67,8 +76,12 @@ static isc_logcategory_t categories[] = {
static void
cleanup_managers() {
+ if (app_running)
+ isc_app_finish();
if (socketmgr != NULL)
isc_socketmgr_destroy(&socketmgr);
+ if (maintask != NULL)
+ isc_task_destroy(&maintask);
if (taskmgr != NULL)
isc_taskmgr_destroy(&taskmgr);
if (timermgr != NULL)
@@ -87,6 +100,8 @@ create_managers() {
CHECK(isc_taskmgr_create(mctx, ncpus, 0, &taskmgr));
CHECK(isc_timermgr_create(mctx, &timermgr));
CHECK(isc_socketmgr_create(mctx, &socketmgr));
+ CHECK(isc_task_create(taskmgr, 0, &maintask));
+ CHECK(isc_app_start());
return (ISC_R_SUCCESS);
cleanup:
@@ -134,6 +149,14 @@ dns_test_begin(FILE *logfile, isc_boolean_t start_managers) {
if (start_managers)
CHECK(create_managers());
+ /*
+ * atf-run changes us to a /tmp directory, so tests
+ * that access test data files must first chdir to the proper
+ * location.
+ */
+ if (chdir(TESTS) == -1)
+ CHECK(ISC_R_FAILURE);
+
return (ISC_R_SUCCESS);
cleanup:
@@ -162,3 +185,114 @@ dns_test_end() {
isc_mem_destroy(&mctx);
}
+/*
+ * Create a zone with origin 'name', return a pointer to the zone object in
+ * 'zonep'. If 'view' is set, add the zone to that view; otherwise, create
+ * a new view for the purpose.
+ *
+ * If the created view is going to be needed by the caller subsequently,
+ * then 'keepview' should be set to true; this will prevent the view
+ * from being detached. In this case, the caller is responsible for
+ * detaching the view.
+ */
+isc_result_t
+dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
+ isc_boolean_t keepview)
+{
+ isc_result_t result;
+ dns_zone_t *zone = NULL;
+ isc_buffer_t buffer;
+ dns_fixedname_t fixorigin;
+ dns_name_t *origin;
+
+ if (view == NULL)
+ CHECK(dns_view_create(mctx, dns_rdataclass_in, "view", &view));
+ else if (!keepview)
+ keepview = ISC_TRUE;
+
+ CHECK(dns_zone_create(&zone, mctx));
+
+ isc_buffer_init(&buffer, name, strlen(name));
+ isc_buffer_add(&buffer, strlen(name));
+ dns_fixedname_init(&fixorigin);
+ origin = dns_fixedname_name(&fixorigin);
+ CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
+ CHECK(dns_zone_setorigin(zone, origin));
+ dns_zone_setview(zone, view);
+ dns_zone_settype(zone, dns_zone_master);
+ dns_zone_setclass(zone, view->rdclass);
+ dns_view_addzone(view, zone);
+
+ if (!keepview)
+ dns_view_detach(&view);
+
+ *zonep = zone;
+
+ return (ISC_R_SUCCESS);
+
+ cleanup:
+ if (zone != NULL)
+ dns_zone_detach(&zone);
+ if (view != NULL)
+ dns_view_detach(&view);
+ return (result);
+}
+
+isc_result_t
+dns_test_setupzonemgr() {
+ isc_result_t result;
+ REQUIRE(zonemgr == NULL);
+
+ result = dns_zonemgr_create(mctx, taskmgr, timermgr, socketmgr,
+ &zonemgr);
+ return (result);
+}
+
+isc_result_t
+dns_test_managezone(dns_zone_t *zone) {
+ isc_result_t result;
+ REQUIRE(zonemgr != NULL);
+
+ result = dns_zonemgr_setsize(zonemgr, 1);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ result = dns_zonemgr_managezone(zonemgr, zone);
+ return (result);
+}
+
+void
+dns_test_releasezone(dns_zone_t *zone) {
+ REQUIRE(zonemgr != NULL);
+ dns_zonemgr_releasezone(zonemgr, zone);
+}
+
+void
+dns_test_closezonemgr() {
+ REQUIRE(zonemgr != NULL);
+
+ dns_zonemgr_shutdown(zonemgr);
+ dns_zonemgr_detach(&zonemgr);
+}
+
+/*
+ * Sleep for 'usec' microseconds.
+ */
+void
+dns_test_nap(isc_uint32_t usec) {
+#ifdef HAVE_NANOSLEEP
+ struct timespec ts;
+
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ nanosleep(&ts, NULL);
+#elif HAVE_USLEEP
+ usleep(usec);
+#else
+ /*
+ * No fractional-second sleep function is available, so we
+ * round up to the nearest second and sleep instead
+ */
+ sleep((usec / 1000000) + 1);
+#endif
+}
diff --git a/lib/dns/tests/dnstest.h b/lib/dns/tests/dnstest.h
index 00a2c376..8bddd410 100644
--- a/lib/dns/tests/dnstest.h
+++ b/lib/dns/tests/dnstest.h
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: dnstest.h,v 1.3 2011-07-06 01:36:32 each Exp $ */
+/* $Id: dnstest.h,v 1.4 2011-09-02 21:15:37 each Exp $ */
/*! \file */
@@ -31,6 +31,7 @@
#include <isc/util.h>
#include <dns/result.h>
+#include <dns/zone.h>
#define CHECK(r) \
do { \
@@ -42,11 +43,13 @@
extern isc_mem_t *mctx;
extern isc_entropy_t *ectx;
extern isc_log_t *lctx;
-isc_taskmgr_t *taskmgr;
-isc_timermgr_t *timermgr;
-isc_socketmgr_t *socketmgr;
-int ncpus;
-
+extern isc_taskmgr_t *taskmgr;
+extern isc_task_t *maintask;
+extern isc_timermgr_t *timermgr;
+extern isc_socketmgr_t *socketmgr;
+extern dns_zonemgr_t *zonemgr;
+extern isc_boolean_t app_running;
+extern int ncpus;
isc_result_t
dns_test_begin(FILE *logfile, isc_boolean_t create_managers);
@@ -54,3 +57,21 @@ dns_test_begin(FILE *logfile, isc_boolean_t create_managers);
void
dns_test_end(void);
+isc_result_t
+dns_test_makezone(const char *name, dns_zone_t **zonep, dns_view_t *view,
+ isc_boolean_t keepview);
+
+isc_result_t
+dns_test_setupzonemgr(void);
+
+isc_result_t
+dns_test_managezone(dns_zone_t *zone);
+
+void
+dns_test_releasezone(dns_zone_t *zone);
+
+void
+dns_test_closezonemgr(void);
+
+void
+dns_test_nap(isc_uint32_t usec);
diff --git a/lib/dns/tests/master_test.c b/lib/dns/tests/master_test.c
index 2920b8cf..afe6eaa4 100644
--- a/lib/dns/tests/master_test.c
+++ b/lib/dns/tests/master_test.c
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: master_test.c,v 1.4 2011-07-06 01:36:32 each Exp $ */
+/* $Id: master_test.c,v 1.6 2011-09-07 19:11:14 each Exp $ */
/*! \file */
@@ -27,8 +27,10 @@
#include <dns/cache.h>
#include <dns/callbacks.h>
#include <dns/master.h>
+#include <dns/masterdump.h>
#include <dns/name.h>
#include <dns/rdata.h>
+#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include "dnstest.h"
@@ -85,14 +87,6 @@ test_master(const char *testfile) {
dns_rdatacallbacks_init_stdio(&callbacks);
callbacks.add = add_callback;
- /*
- * atf-run changes us to a /tmp directory, so tests
- * that access test data files must first chdir to the proper
- * location.
- */
- if (chdir(TESTS) == -1)
- return (ISC_R_FAILURE);
-
result = dns_master_loadfile(testfile, &dns_origin, &dns_origin,
dns_rdataclass_in, ISC_TRUE,
&callbacks, mctx);
@@ -334,6 +328,50 @@ ATF_TC_BODY(master_leadingzero, tc) {
dns_test_end();
}
+ATF_TC(master_totext);
+ATF_TC_HEAD(master_totext, tc) {
+ atf_tc_set_md_var(tc, "descr", "masterfile totext tests");
+}
+ATF_TC_BODY(master_totext, tc) {
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+ dns_rdatalist_t rdatalist;
+ isc_buffer_t target;
+ unsigned char buf[BIGBUFLEN];
+
+ UNUSED(tc);
+
+ result = dns_test_begin(NULL, ISC_FALSE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* First, test with an empty rdataset */
+ rdatalist.rdclass = dns_rdataclass_in;
+ rdatalist.type = dns_rdatatype_none;
+ rdatalist.covers = dns_rdatatype_none;
+ rdatalist.ttl = 0;
+ ISC_LIST_INIT(rdatalist.rdata);
+ ISC_LINK_INIT(&rdatalist, link);
+
+ dns_rdataset_init(&rdataset);
+ result = dns_rdatalist_tordataset(&rdatalist, &rdataset);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+
+ isc_buffer_init(&target, buf, BIGBUFLEN);
+ result = dns_master_rdatasettotext(dns_rootname,
+ &rdataset, &dns_master_style_debug,
+ &target);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_EQ(isc_buffer_usedlength(&target), 0);
+
+ /*
+ * XXX: We will also need to add tests for dumping various
+ * rdata types, classes, etc, and comparing the results against
+ * known-good output.
+ */
+
+ dns_test_end();
+}
+
/*
* Main
*/
@@ -349,6 +387,7 @@ ATF_TP_ADD_TCS(tp) {
ATF_TP_ADD_TC(tp, master_includefail);
ATF_TP_ADD_TC(tp, master_blanklines);
ATF_TP_ADD_TC(tp, master_leadingzero);
+ ATF_TP_ADD_TC(tp, master_totext);
return (atf_no_error());
}
diff --git a/lib/dns/tests/testdata/zt/zone1.db b/lib/dns/tests/testdata/zt/zone1.db
new file mode 100644
index 00000000..4744a4d3
--- /dev/null
+++ b/lib/dns/tests/testdata/zt/zone1.db
@@ -0,0 +1,27 @@
+; Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+;
+; Permission to use, copy, modify, and/or distribute this software for any
+; purpose with or without fee is hereby granted, provided that the above
+; copyright notice and this permission notice appear in all copies.
+;
+; THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+; REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+; AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+; INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+; LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+; OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+; PERFORMANCE OF THIS SOFTWARE.
+
+; $Id: zone1.db,v 1.3 2011-09-02 23:46:32 tbox Exp $
+
+$TTL 1000
+@ in soa localhost. postmaster.localhost. (
+ 1993050801 ;serial
+ 3600 ;refresh
+ 1800 ;retry
+ 604800 ;expiration
+ 3600 ) ;minimum
+ in ns ns.vix.com.
+ in ns ns2.vix.com.
+ in ns ns3.vix.com.
+a in a 1.2.3.4
diff --git a/lib/dns/tests/zonemgr_test.c b/lib/dns/tests/zonemgr_test.c
index 502e7ec7..b00165cb 100644
--- a/lib/dns/tests/zonemgr_test.c
+++ b/lib/dns/tests/zonemgr_test.c
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zonemgr_test.c,v 1.2 2011-07-06 05:05:51 each Exp $ */
+/* $Id: zonemgr_test.c,v 1.3 2011-09-02 21:15:37 each Exp $ */
/*! \file */
@@ -34,41 +34,6 @@
#include "dnstest.h"
-static isc_result_t
-make_zone(const char *name, dns_zone_t **zonep) {
- isc_result_t result;
- dns_view_t *view = NULL;
- dns_zone_t *zone = NULL;
- isc_buffer_t buffer;
- dns_fixedname_t fixorigin;
- dns_name_t *origin;
-
- CHECK(dns_view_create(mctx, dns_rdataclass_in, "view", &view));
- CHECK(dns_zone_create(&zone, mctx));
-
- isc_buffer_init(&buffer, name, strlen(name));
- isc_buffer_add(&buffer, strlen(name));
- dns_fixedname_init(&fixorigin);
- origin = dns_fixedname_name(&fixorigin);
- CHECK(dns_name_fromtext(origin, &buffer, dns_rootname, 0, NULL));
- CHECK(dns_zone_setorigin(zone, origin));
- dns_zone_setview(zone, view);
- dns_zone_settype(zone, dns_zone_master);
- dns_zone_setclass(zone, view->rdclass);
-
- dns_view_detach(&view);
- *zonep = zone;
-
- return (ISC_R_SUCCESS);
-
- cleanup:
- if (zone != NULL)
- dns_zone_detach(&zone);
- if (view != NULL)
- dns_view_detach(&view);
- return (result);
-}
-
/*
* Individual unit tests
*/
@@ -115,7 +80,7 @@ ATF_TC_BODY(zonemgr_managezone, tc) {
&zonemgr);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
- result = make_zone("foo", &zone);
+ result = dns_test_makezone("foo", &zone, NULL, ISC_FALSE);
ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
/* This should not succeed until the dns_zonemgr_setsize() is run */
diff --git a/lib/dns/tests/zt_test.c b/lib/dns/tests/zt_test.c
new file mode 100644
index 00000000..1239c39a
--- /dev/null
+++ b/lib/dns/tests/zt_test.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: zt_test.c,v 1.5 2011-09-03 16:15:08 each Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/app.h>
+#include <isc/buffer.h>
+#include <isc/task.h>
+#include <isc/timer.h>
+
+#include <dns/db.h>
+#include <dns/name.h>
+#include <dns/view.h>
+#include <dns/zone.h>
+#include <dns/zt.h>
+
+#include "dnstest.h"
+
+/*
+ * Helper functions
+ */
+static isc_result_t
+count_zone(dns_zone_t *zone, void *uap) {
+ int *nzones = (int *)uap;
+
+ UNUSED(zone);
+
+ *nzones += 1;
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+load_done(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
+ /* We treat zt as a pointer to a boolean for testing purposes */
+ isc_boolean_t *done = (isc_boolean_t *) zt;
+
+ UNUSED(zone);
+ UNUSED(task);
+
+ *done = ISC_TRUE;
+ isc_app_shutdown();
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+all_done(void *arg) {
+ isc_boolean_t *done = (isc_boolean_t *) arg;
+
+ *done = ISC_TRUE;
+ isc_app_shutdown();
+ return (ISC_R_SUCCESS);
+}
+
+/*
+ * Individual unit tests
+ */
+ATF_TC(apply);
+ATF_TC_HEAD(apply, tc) {
+ atf_tc_set_md_var(tc, "descr", "apply a function to a zone table");
+}
+ATF_TC_BODY(apply, tc) {
+ isc_result_t result;
+ dns_zone_t *zone = NULL;
+ dns_view_t *view = NULL;
+ int nzones = 0;
+
+ UNUSED(tc);
+
+ result = dns_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_test_makezone("foo", &zone, NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ view = dns_zone_getview(zone);
+ ATF_REQUIRE(view->zonetable != NULL);
+
+ ATF_CHECK_EQ(0, nzones);
+ result = dns_zt_apply(view->zonetable, ISC_FALSE, count_zone, &nzones);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK_EQ(1, nzones);
+
+ /* These steps are necessary so the zone can be detached properly */
+ result = dns_test_setupzonemgr();
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ dns_test_releasezone(zone);
+ dns_test_closezonemgr();
+
+ /* The view was left attached in dns_test_makezone() */
+ dns_view_detach(&view);
+ dns_zone_detach(&zone);
+
+ dns_test_end();
+}
+
+ATF_TC(asyncload_zone);
+ATF_TC_HEAD(asyncload_zone, tc) {
+ atf_tc_set_md_var(tc, "descr", "asynchronous zone load");
+}
+ATF_TC_BODY(asyncload_zone, tc) {
+ isc_result_t result;
+ dns_zone_t *zone = NULL;
+ dns_view_t *view = NULL;
+ dns_db_t *db = NULL;
+ isc_boolean_t done = ISC_FALSE;
+ int i = 0;
+
+ UNUSED(tc);
+
+ result = dns_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_test_makezone("foo", &zone, NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_test_setupzonemgr();
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ view = dns_zone_getview(zone);
+ ATF_REQUIRE(view->zonetable != NULL);
+
+ ATF_CHECK(!dns__zone_loadpending(zone));
+ ATF_CHECK(!done);
+ dns_zone_setfile(zone, "testdata/zt/zone1.db");
+ dns_zone_asyncload(zone, load_done, (void *) &done);
+ ATF_CHECK(dns__zone_loadpending(zone));
+
+ isc_app_run();
+ while (dns__zone_loadpending(zone) && i++ < 5000)
+ dns_test_nap(1000);
+ ATF_CHECK(done);
+
+ /* The zone should now be loaded; test it */
+ result = dns_zone_getdb(zone, &db);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(db != NULL);
+ if (db != NULL)
+ dns_db_detach(&db);
+
+ dns_test_releasezone(zone);
+ dns_test_closezonemgr();
+
+ dns_zone_detach(&zone);
+ dns_view_detach(&view);
+
+ dns_test_end();
+}
+
+ATF_TC(asyncload_zt);
+ATF_TC_HEAD(asyncload_zt, tc) {
+ atf_tc_set_md_var(tc, "descr", "asynchronous zone table load");
+}
+ATF_TC_BODY(asyncload_zt, tc) {
+ isc_result_t result;
+ dns_zone_t *zone1 = NULL, *zone2 = NULL, *zone3 = NULL;
+ dns_view_t *view;
+ dns_zt_t *zt;
+ dns_db_t *db = NULL;
+ isc_boolean_t done = ISC_FALSE;
+ int i = 0;
+
+ UNUSED(tc);
+
+ result = dns_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = dns_test_makezone("foo", &zone1, NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ dns_zone_setfile(zone1, "testdata/zt/zone1.db");
+ view = dns_zone_getview(zone1);
+
+ result = dns_test_makezone("bar", &zone2, view, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ dns_zone_setfile(zone2, "testdata/zt/zone1.db");
+
+ /* This one will fail to load */
+ result = dns_test_makezone("fake", &zone3, view, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ dns_zone_setfile(zone3, "testdata/zt/nonexistent.db");
+
+ zt = view->zonetable;
+ ATF_REQUIRE(zt != NULL);
+
+ result = dns_test_setupzonemgr();
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ result = dns_test_managezone(zone3);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ ATF_CHECK(!dns__zone_loadpending(zone1));
+ ATF_CHECK(!dns__zone_loadpending(zone2));
+ ATF_CHECK(!done);
+ dns_zt_asyncload(zt, all_done, (void *) &done);
+
+ isc_app_run();
+ while (!done && i++ < 5000)
+ dns_test_nap(1000);
+ ATF_CHECK(done);
+
+ /* Both zones should now be loaded; test them */
+ result = dns_zone_getdb(zone1, &db);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(db != NULL);
+ if (db != NULL)
+ dns_db_detach(&db);
+
+ result = dns_zone_getdb(zone2, &db);
+ ATF_CHECK_EQ(result, ISC_R_SUCCESS);
+ ATF_CHECK(db != NULL);
+ if (db != NULL)
+ dns_db_detach(&db);
+
+ dns_test_releasezone(zone3);
+ dns_test_releasezone(zone2);
+ dns_test_releasezone(zone1);
+ dns_test_closezonemgr();
+
+ dns_zone_detach(&zone1);
+ dns_zone_detach(&zone2);
+ dns_zone_detach(&zone3);
+ dns_view_detach(&view);
+
+ dns_test_end();
+}
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, apply);
+ ATF_TP_ADD_TC(tp, asyncload_zone);
+ ATF_TP_ADD_TC(tp, asyncload_zt);
+ return (atf_no_error());
+}
diff --git a/lib/dns/tsig.c b/lib/dns/tsig.c
index 06fe182e..498ca0e3 100644
--- a/lib/dns/tsig.c
+++ b/lib/dns/tsig.c
@@ -16,7 +16,7 @@
*/
/*
- * $Id: tsig.c,v 1.148 2011-03-21 19:54:03 each Exp $
+ * $Id: tsig.c,v 1.150 2011-08-29 04:02:54 marka Exp $
*/
/*! \file */
#include <config.h>
@@ -889,6 +889,7 @@ dns_tsig_sign(dns_message_t *msg) {
isc_result_t ret;
unsigned char badtimedata[BADTIMELEN];
unsigned int sigsize = 0;
+ isc_boolean_t response = is_response(msg);
REQUIRE(msg != NULL);
REQUIRE(VALID_TSIG_KEY(dns_message_gettsigkey(msg)));
@@ -896,7 +897,7 @@ dns_tsig_sign(dns_message_t *msg) {
/*
* If this is a response, there should be a query tsig.
*/
- if (is_response(msg) && msg->querytsig == NULL)
+ if (response && msg->querytsig == NULL)
return (DNS_R_EXPECTEDTSIG);
dynbuf = NULL;
@@ -919,7 +920,7 @@ dns_tsig_sign(dns_message_t *msg) {
isc_buffer_init(&databuf, data, sizeof(data));
- if (is_response(msg))
+ if (response)
tsig.error = msg->querytsigstatus;
else
tsig.error = dns_rcode_noerror;
@@ -948,7 +949,7 @@ dns_tsig_sign(dns_message_t *msg) {
/*
* If this is a response, digest the query signature.
*/
- if (is_response(msg)) {
+ if (response) {
dns_rdata_t querytsigrdata = DNS_RDATA_INIT;
ret = dns_rdataset_first(msg->querytsig);
@@ -1017,8 +1018,10 @@ dns_tsig_sign(dns_message_t *msg) {
}
/* Digest the timesigned and fudge */
isc_buffer_clear(&databuf);
- if (tsig.error == dns_tsigerror_badtime)
+ if (tsig.error == dns_tsigerror_badtime) {
+ INSIST(response);
tsig.timesigned = querytsig.timesigned;
+ }
isc_buffer_putuint48(&databuf, tsig.timesigned);
isc_buffer_putuint16(&databuf, tsig.fudge);
isc_buffer_usedregion(&databuf, &r);
@@ -1068,7 +1071,7 @@ dns_tsig_sign(dns_message_t *msg) {
digestbits = dst_key_getbits(key->key);
if (digestbits != 0) {
unsigned int bytes = (digestbits + 1) / 8;
- if (is_response(msg) && bytes < querytsig.siglen)
+ if (response && bytes < querytsig.siglen)
bytes = querytsig.siglen;
if (bytes > isc_buffer_usedlength(&sigbuf))
bytes = isc_buffer_usedlength(&sigbuf);
@@ -1170,10 +1173,12 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
isc_uint16_t addcount, id;
unsigned int siglen;
unsigned int alg;
+ isc_boolean_t response;
REQUIRE(source != NULL);
REQUIRE(DNS_MESSAGE_VALID(msg));
tsigkey = dns_message_gettsigkey(msg);
+ response = is_response(msg);
REQUIRE(tsigkey == NULL || VALID_TSIG_KEY(tsigkey));
@@ -1195,8 +1200,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
* If this is a response and there's no key or query TSIG, there
* shouldn't be one on the response.
*/
- if (is_response(msg) &&
- (tsigkey == NULL || msg->querytsig == NULL))
+ if (response && (tsigkey == NULL || msg->querytsig == NULL))
return (DNS_R_UNEXPECTEDTSIG);
mctx = msg->mctx;
@@ -1215,7 +1219,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
if (ret != ISC_R_SUCCESS)
return (ret);
dns_rdata_reset(&rdata);
- if (is_response(msg)) {
+ if (response) {
ret = dns_rdataset_first(msg->querytsig);
if (ret != ISC_R_SUCCESS)
return (ret);
@@ -1228,7 +1232,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
/*
* Do the key name and algorithm match that of the query?
*/
- if (is_response(msg) &&
+ if (response &&
(!dns_name_equal(keyname, &tsigkey->name) ||
!dns_name_equal(&tsig.algorithm, &querytsig.algorithm))) {
msg->tsigstatus = dns_tsigerror_badkey;
@@ -1326,7 +1330,7 @@ dns_tsig_verify(isc_buffer_t *source, dns_message_t *msg,
if (ret != ISC_R_SUCCESS)
return (ret);
- if (is_response(msg)) {
+ if (response) {
isc_buffer_init(&databuf, data, sizeof(data));
isc_buffer_putuint16(&databuf, querytsig.siglen);
isc_buffer_usedregion(&databuf, &r);
diff --git a/lib/dns/update.c b/lib/dns/update.c
index a9b1dfad..9099994d 100644
--- a/lib/dns/update.c
+++ b/lib/dns/update.c
@@ -14,14 +14,1839 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: update.c,v 1.3 2011-07-01 23:47:44 tbox Exp $ */
+/* $Id: update.c,v 1.5 2011-08-30 23:46:52 tbox Exp $ */
-#include "config.h"
+#include <config.h>
-#include <isc/stdtime.h>
+#include <isc/log.h>
+#include <isc/netaddr.h>
+#include <isc/print.h>
#include <isc/serial.h>
+#include <isc/stats.h>
+#include <isc/stdtime.h>
+#include <isc/string.h>
+#include <isc/taskpool.h>
+#include <isc/util.h>
+#include <dns/db.h>
+#include <dns/dbiterator.h>
+#include <dns/diff.h>
+#include <dns/dnssec.h>
+#include <dns/events.h>
+#include <dns/fixedname.h>
+#include <dns/journal.h>
+#include <dns/keyvalues.h>
+#include <dns/log.h>
+#include <dns/message.h>
+#include <dns/nsec.h>
+#include <dns/nsec3.h>
+#include <dns/private.h>
+#include <dns/rdataclass.h>
+#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
+#include <dns/rdatastruct.h>
+#include <dns/rdatatype.h>
+#include <dns/result.h>
+#include <dns/soa.h>
+#include <dns/ssu.h>
+#include <dns/tsig.h>
#include <dns/update.h>
+#include <dns/view.h>
+#include <dns/zone.h>
+#include <dns/zt.h>
+
+
+/**************************************************************************/
+
+/*%
+ * Log level for tracing dynamic update protocol requests.
+ */
+#define LOGLEVEL_PROTOCOL ISC_LOG_INFO
+
+/*%
+ * Log level for low-level debug tracing.
+ */
+#define LOGLEVEL_DEBUG ISC_LOG_DEBUG(8)
+
+/*%
+ * Check an operation for failure. These macros all assume that
+ * the function using them has a 'result' variable and a 'failure'
+ * label.
+ */
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+/*%
+ * Fail unconditionally with result 'code', which must not
+ * be ISC_R_SUCCESS. The reason for failure presumably has
+ * been logged already.
+ *
+ * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
+ * from complaining about "end-of-loop code not reached".
+ */
+
+#define FAIL(code) \
+ do { \
+ result = (code); \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+/*%
+ * Fail unconditionally and log as a client error.
+ * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
+ * from complaining about "end-of-loop code not reached".
+ */
+#define FAILC(code, msg) \
+ do { \
+ const char *_what = "failed"; \
+ result = (code); \
+ switch (result) { \
+ case DNS_R_NXDOMAIN: \
+ case DNS_R_YXDOMAIN: \
+ case DNS_R_YXRRSET: \
+ case DNS_R_NXRRSET: \
+ _what = "unsuccessful"; \
+ } \
+ update_log(log, zone, LOGLEVEL_PROTOCOL, \
+ "update %s: %s (%s)", _what, \
+ msg, isc_result_totext(result)); \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+#define FAILN(code, name, msg) \
+ do { \
+ const char *_what = "failed"; \
+ result = (code); \
+ switch (result) { \
+ case DNS_R_NXDOMAIN: \
+ case DNS_R_YXDOMAIN: \
+ case DNS_R_YXRRSET: \
+ case DNS_R_NXRRSET: \
+ _what = "unsuccessful"; \
+ } \
+ if (isc_log_wouldlog(dns_lctx, LOGLEVEL_PROTOCOL)) { \
+ char _nbuf[DNS_NAME_FORMATSIZE]; \
+ dns_name_format(name, _nbuf, sizeof(_nbuf)); \
+ update_log(log, zone, LOGLEVEL_PROTOCOL, \
+ "update %s: %s: %s (%s)", _what, _nbuf, \
+ msg, isc_result_totext(result)); \
+ } \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+#define FAILNT(code, name, type, msg) \
+ do { \
+ const char *_what = "failed"; \
+ result = (code); \
+ switch (result) { \
+ case DNS_R_NXDOMAIN: \
+ case DNS_R_YXDOMAIN: \
+ case DNS_R_YXRRSET: \
+ case DNS_R_NXRRSET: \
+ _what = "unsuccessful"; \
+ } \
+ if (isc_log_wouldlog(dns_lctx, LOGLEVEL_PROTOCOL)) { \
+ char _nbuf[DNS_NAME_FORMATSIZE]; \
+ char _tbuf[DNS_RDATATYPE_FORMATSIZE]; \
+ dns_name_format(name, _nbuf, sizeof(_nbuf)); \
+ dns_rdatatype_format(type, _tbuf, sizeof(_tbuf)); \
+ update_log(log, zone, LOGLEVEL_PROTOCOL, \
+ "update %s: %s/%s: %s (%s)", \
+ _what, _nbuf, _tbuf, msg, \
+ isc_result_totext(result)); \
+ } \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+/*%
+ * Fail unconditionally and log as a server error.
+ * The test against ISC_R_SUCCESS is there to keep the Solaris compiler
+ * from complaining about "end-of-loop code not reached".
+ */
+#define FAILS(code, msg) \
+ do { \
+ result = (code); \
+ update_log(log, zone, LOGLEVEL_PROTOCOL, \
+ "error: %s: %s", \
+ msg, isc_result_totext(result)); \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
+/**************************************************************************/
+
+typedef struct rr rr_t;
+
+struct rr {
+ /* dns_name_t name; */
+ isc_uint32_t ttl;
+ dns_rdata_t rdata;
+};
+
+typedef struct update_event update_event_t;
+
+/**************************************************************************/
+
+static void
+update_log(dns_update_log_t *callback, dns_zone_t *zone,
+ int level, const char *fmt, ...) ISC_FORMAT_PRINTF(4, 5);
+
+static void
+update_log(dns_update_log_t *callback, dns_zone_t *zone,
+ int level, const char *fmt, ...)
+{
+ va_list ap;
+ char message[4096];
+
+ if (callback == NULL)
+ return;
+
+ if (isc_log_wouldlog(dns_lctx, level) == ISC_FALSE)
+ return;
+
+
+ va_start(ap, fmt);
+ vsnprintf(message, sizeof(message), fmt, ap);
+ va_end(ap);
+
+ (callback->func)(callback->arg, zone, level, message);
+}
+
+/*%
+ * Update a single RR in version 'ver' of 'db' and log the
+ * update in 'diff'.
+ *
+ * Ensures:
+ * \li '*tuple' == NULL. Either the tuple is freed, or its
+ * ownership has been transferred to the diff.
+ */
+static isc_result_t
+do_one_tuple(dns_difftuple_t **tuple, dns_db_t *db, dns_dbversion_t *ver,
+ dns_diff_t *diff)
+{
+ dns_diff_t temp_diff;
+ isc_result_t result;
+
+ /*
+ * Create a singleton diff.
+ */
+ dns_diff_init(diff->mctx, &temp_diff);
+ temp_diff.resign = diff->resign;
+ ISC_LIST_APPEND(temp_diff.tuples, *tuple, link);
+
+ /*
+ * Apply it to the database.
+ */
+ result = dns_diff_apply(&temp_diff, db, ver);
+ ISC_LIST_UNLINK(temp_diff.tuples, *tuple, link);
+ if (result != ISC_R_SUCCESS) {
+ dns_difftuple_free(tuple);
+ return (result);
+ }
+
+ /*
+ * Merge it into the current pending journal entry.
+ */
+ dns_diff_appendminimal(diff, tuple);
+
+ /*
+ * Do not clear temp_diff.
+ */
+ return (ISC_R_SUCCESS);
+}
+
+static isc_result_t
+update_one_rr(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
+ dns_diffop_t op, dns_name_t *name, dns_ttl_t ttl,
+ dns_rdata_t *rdata)
+{
+ dns_difftuple_t *tuple = NULL;
+ isc_result_t result;
+ result = dns_difftuple_create(diff->mctx, op,
+ name, ttl, rdata, &tuple);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ return (do_one_tuple(&tuple, db, ver, diff));
+}
+
+/**************************************************************************/
+/*
+ * Callback-style iteration over rdatasets and rdatas.
+ *
+ * foreach_rrset() can be used to iterate over the RRsets
+ * of a name and call a callback function with each
+ * one. Similarly, foreach_rr() can be used to iterate
+ * over the individual RRs at name, optionally restricted
+ * to RRs of a given type.
+ *
+ * The callback functions are called "actions" and take
+ * two arguments: a void pointer for passing arbitrary
+ * context information, and a pointer to the current RRset
+ * or RR. By convention, their names end in "_action".
+ */
+
+/*
+ * XXXRTH We might want to make this public somewhere in libdns.
+ */
+
+/*%
+ * Function type for foreach_rrset() iterator actions.
+ */
+typedef isc_result_t rrset_func(void *data, dns_rdataset_t *rrset);
+
+/*%
+ * Function type for foreach_rr() iterator actions.
+ */
+typedef isc_result_t rr_func(void *data, rr_t *rr);
+
+/*%
+ * Internal context struct for foreach_node_rr().
+ */
+typedef struct {
+ rr_func * rr_action;
+ void * rr_action_data;
+} foreach_node_rr_ctx_t;
+
+/*%
+ * Internal helper function for foreach_node_rr().
+ */
+static isc_result_t
+foreach_node_rr_action(void *data, dns_rdataset_t *rdataset) {
+ isc_result_t result;
+ foreach_node_rr_ctx_t *ctx = data;
+ for (result = dns_rdataset_first(rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(rdataset))
+ {
+ rr_t rr = { 0, DNS_RDATA_INIT };
+
+ dns_rdataset_current(rdataset, &rr.rdata);
+ rr.ttl = rdataset->ttl;
+ result = (*ctx->rr_action)(ctx->rr_action_data, &rr);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ }
+ if (result != ISC_R_NOMORE)
+ return (result);
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * For each rdataset of 'name' in 'ver' of 'db', call 'action'
+ * with the rdataset and 'action_data' as arguments. If the name
+ * does not exist, do nothing.
+ *
+ * If 'action' returns an error, abort iteration and return the error.
+ */
+static isc_result_t
+foreach_rrset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ rrset_func *action, void *action_data)
+{
+ isc_result_t result;
+ dns_dbnode_t *node;
+ dns_rdatasetiter_t *iter;
+
+ node = NULL;
+ result = dns_db_findnode(db, name, ISC_FALSE, &node);
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ iter = NULL;
+ result = dns_db_allrdatasets(db, node, ver,
+ (isc_stdtime_t) 0, &iter);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_node;
+
+ for (result = dns_rdatasetiter_first(iter);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(iter))
+ {
+ dns_rdataset_t rdataset;
+
+ dns_rdataset_init(&rdataset);
+ dns_rdatasetiter_current(iter, &rdataset);
+
+ result = (*action)(action_data, &rdataset);
+
+ dns_rdataset_disassociate(&rdataset);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_iterator;
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ cleanup_iterator:
+ dns_rdatasetiter_destroy(&iter);
+
+ cleanup_node:
+ dns_db_detachnode(db, &node);
+
+ return (result);
+}
+
+/*%
+ * For each RR of 'name' in 'ver' of 'db', call 'action'
+ * with the RR and 'action_data' as arguments. If the name
+ * does not exist, do nothing.
+ *
+ * If 'action' returns an error, abort iteration
+ * and return the error.
+ */
+static isc_result_t
+foreach_node_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ rr_func *rr_action, void *rr_action_data)
+{
+ foreach_node_rr_ctx_t ctx;
+ ctx.rr_action = rr_action;
+ ctx.rr_action_data = rr_action_data;
+ return (foreach_rrset(db, ver, name,
+ foreach_node_rr_action, &ctx));
+}
+
+
+/*%
+ * For each of the RRs specified by 'db', 'ver', 'name', 'type',
+ * (which can be dns_rdatatype_any to match any type), and 'covers', call
+ * 'action' with the RR and 'action_data' as arguments. If the name
+ * does not exist, or if no RRset of the given type exists at the name,
+ * do nothing.
+ *
+ * If 'action' returns an error, abort iteration and return the error.
+ */
+static isc_result_t
+foreach_rr(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ dns_rdatatype_t type, dns_rdatatype_t covers, rr_func *rr_action,
+ void *rr_action_data)
+{
+
+ isc_result_t result;
+ dns_dbnode_t *node;
+ dns_rdataset_t rdataset;
+
+ if (type == dns_rdatatype_any)
+ return (foreach_node_rr(db, ver, name,
+ rr_action, rr_action_data));
+
+ node = NULL;
+ if (type == dns_rdatatype_nsec3 ||
+ (type == dns_rdatatype_rrsig && covers == dns_rdatatype_nsec3))
+ result = dns_db_findnsec3node(db, name, ISC_FALSE, &node);
+ else
+ result = dns_db_findnode(db, name, ISC_FALSE, &node);
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, ver, type, covers,
+ (isc_stdtime_t) 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ result = ISC_R_SUCCESS;
+ goto cleanup_node;
+ }
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_node;
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset))
+ {
+ rr_t rr = { 0, DNS_RDATA_INIT };
+ dns_rdataset_current(&rdataset, &rr.rdata);
+ rr.ttl = rdataset.ttl;
+ result = (*rr_action)(rr_action_data, &rr);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_rdataset;
+ }
+ if (result != ISC_R_NOMORE)
+ goto cleanup_rdataset;
+ result = ISC_R_SUCCESS;
+
+ cleanup_rdataset:
+ dns_rdataset_disassociate(&rdataset);
+ cleanup_node:
+ dns_db_detachnode(db, &node);
+
+ return (result);
+}
+
+/**************************************************************************/
+/*
+ * Various tests on the database contents (for prerequisites, etc).
+ */
+
+/*%
+ * Function type for predicate functions that compare a database RR 'db_rr'
+ * against an update RR 'update_rr'.
+ */
+typedef isc_boolean_t rr_predicate(dns_rdata_t *update_rr, dns_rdata_t *db_rr);
+
+/*%
+ * Helper function for rrset_exists().
+ */
+static isc_result_t
+rrset_exists_action(void *data, rr_t *rr) {
+ UNUSED(data);
+ UNUSED(rr);
+ return (ISC_R_EXISTS);
+}
+
+/*%
+ * Utility macro for RR existence checking functions.
+ *
+ * If the variable 'result' has the value ISC_R_EXISTS or
+ * ISC_R_SUCCESS, set *exists to ISC_TRUE or ISC_FALSE,
+ * respectively, and return success.
+ *
+ * If 'result' has any other value, there was a failure.
+ * Return the failure result code and do not set *exists.
+ *
+ * This would be more readable as "do { if ... } while(0)",
+ * but that form generates tons of warnings on Solaris 2.6.
+ */
+#define RETURN_EXISTENCE_FLAG \
+ return ((result == ISC_R_EXISTS) ? \
+ (*exists = ISC_TRUE, ISC_R_SUCCESS) : \
+ ((result == ISC_R_SUCCESS) ? \
+ (*exists = ISC_FALSE, ISC_R_SUCCESS) : \
+ result))
+
+/*%
+ * Set '*exists' to true iff an rrset of the given type exists,
+ * to false otherwise.
+ */
+static isc_result_t
+rrset_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ dns_rdatatype_t type, dns_rdatatype_t covers,
+ isc_boolean_t *exists)
+{
+ isc_result_t result;
+ result = foreach_rr(db, ver, name, type, covers,
+ rrset_exists_action, NULL);
+ RETURN_EXISTENCE_FLAG;
+}
+
+/*%
+ * Set '*visible' to true if the RRset exists and is part of the
+ * visible zone. Otherwise '*visible' is set to false unless a
+ * error occurs.
+ */
+static isc_result_t
+rrset_visible(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ dns_rdatatype_t type, isc_boolean_t *visible)
+{
+ isc_result_t result;
+ dns_fixedname_t fixed;
+
+ dns_fixedname_init(&fixed);
+ result = dns_db_find(db, name, ver, type, DNS_DBFIND_NOWILD,
+ (isc_stdtime_t) 0, NULL,
+ dns_fixedname_name(&fixed), NULL, NULL);
+ switch (result) {
+ case ISC_R_SUCCESS:
+ *visible = ISC_TRUE;
+ break;
+ /*
+ * Glue, obscured, deleted or replaced records.
+ */
+ case DNS_R_DELEGATION:
+ case DNS_R_DNAME:
+ case DNS_R_CNAME:
+ case DNS_R_NXDOMAIN:
+ case DNS_R_NXRRSET:
+ case DNS_R_EMPTYNAME:
+ case DNS_R_COVERINGNSEC:
+ *visible = ISC_FALSE;
+ result = ISC_R_SUCCESS;
+ break;
+ default:
+ break;
+ }
+ return (result);
+}
+
+/*%
+ * Context struct and helper function for name_exists().
+ */
+
+static isc_result_t
+name_exists_action(void *data, dns_rdataset_t *rrset) {
+ UNUSED(data);
+ UNUSED(rrset);
+ return (ISC_R_EXISTS);
+}
+
+/*%
+ * Set '*exists' to true iff the given name exists, to false otherwise.
+ */
+static isc_result_t
+name_exists(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ isc_boolean_t *exists)
+{
+ isc_result_t result;
+ result = foreach_rrset(db, ver, name,
+ name_exists_action, NULL);
+ RETURN_EXISTENCE_FLAG;
+}
+
+/**************************************************************************/
+/*
+ * Checking of "RRset exists (value dependent)" prerequisites.
+ *
+ * In the RFC2136 section 3.2.5, this is the pseudocode involving
+ * a variable called "temp", a mapping of <name, type> tuples to rrsets.
+ *
+ * Here, we represent the "temp" data structure as (non-minimal) "dns_diff_t"
+ * where each tuple has op==DNS_DIFFOP_EXISTS.
+ */
+
+/*%
+ * A comparison function defining the sorting order for the entries
+ * in the "temp" data structure. The major sort key is the owner name,
+ * followed by the type and rdata.
+ */
+static int
+temp_order(const void *av, const void *bv) {
+ dns_difftuple_t const * const *ap = av;
+ dns_difftuple_t const * const *bp = bv;
+ dns_difftuple_t const *a = *ap;
+ dns_difftuple_t const *b = *bp;
+ int r;
+ r = dns_name_compare(&a->name, &b->name);
+ if (r != 0)
+ return (r);
+ r = (b->rdata.type - a->rdata.type);
+ if (r != 0)
+ return (r);
+ r = dns_rdata_casecompare(&a->rdata, &b->rdata);
+ return (r);
+}
+
+/**************************************************************************/
+/*
+ * Conditional deletion of RRs.
+ */
+
+/*%
+ * Context structure for delete_if().
+ */
+
+typedef struct {
+ rr_predicate *predicate;
+ dns_db_t *db;
+ dns_dbversion_t *ver;
+ dns_diff_t *diff;
+ dns_name_t *name;
+ dns_rdata_t *update_rr;
+} conditional_delete_ctx_t;
+
+/*%
+ * Predicate functions for delete_if().
+ */
+
+/*%
+ * Return true always.
+ */
+static isc_boolean_t
+true_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
+ UNUSED(update_rr);
+ UNUSED(db_rr);
+ return (ISC_TRUE);
+}
+
+/*%
+ * Return true if the record is a RRSIG.
+ */
+static isc_boolean_t
+rrsig_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
+ UNUSED(update_rr);
+ return ((db_rr->type == dns_rdatatype_rrsig) ?
+ ISC_TRUE : ISC_FALSE);
+}
+
+/*%
+ * Internal helper function for delete_if().
+ */
+static isc_result_t
+delete_if_action(void *data, rr_t *rr) {
+ conditional_delete_ctx_t *ctx = data;
+ if ((*ctx->predicate)(ctx->update_rr, &rr->rdata)) {
+ isc_result_t result;
+ result = update_one_rr(ctx->db, ctx->ver, ctx->diff,
+ DNS_DIFFOP_DEL, ctx->name,
+ rr->ttl, &rr->rdata);
+ return (result);
+ } else {
+ return (ISC_R_SUCCESS);
+ }
+}
+
+/*%
+ * Conditionally delete RRs. Apply 'predicate' to the RRs
+ * specified by 'db', 'ver', 'name', and 'type' (which can
+ * be dns_rdatatype_any to match any type). Delete those
+ * RRs for which the predicate returns true, and log the
+ * deletions in 'diff'.
+ */
+static isc_result_t
+delete_if(rr_predicate *predicate, dns_db_t *db, dns_dbversion_t *ver,
+ dns_name_t *name, dns_rdatatype_t type, dns_rdatatype_t covers,
+ dns_rdata_t *update_rr, dns_diff_t *diff)
+{
+ conditional_delete_ctx_t ctx;
+ ctx.predicate = predicate;
+ ctx.db = db;
+ ctx.ver = ver;
+ ctx.diff = diff;
+ ctx.name = name;
+ ctx.update_rr = update_rr;
+ return (foreach_rr(db, ver, name, type, covers,
+ delete_if_action, &ctx));
+}
+
+/**************************************************************************/
+/*
+ * Incremental updating of NSECs and RRSIGs.
+ */
+
+#define MAXZONEKEYS 32 /*%< Maximum number of zone keys supported. */
+
+/*%
+ * We abuse the dns_diff_t type to represent a set of domain names
+ * affected by the update.
+ */
+static isc_result_t
+namelist_append_name(dns_diff_t *list, dns_name_t *name) {
+ isc_result_t result;
+ dns_difftuple_t *tuple = NULL;
+ static dns_rdata_t dummy_rdata = DNS_RDATA_INIT;
+
+ CHECK(dns_difftuple_create(list->mctx, DNS_DIFFOP_EXISTS, name, 0,
+ &dummy_rdata, &tuple));
+ dns_diff_append(list, &tuple);
+ failure:
+ return (result);
+}
+
+static isc_result_t
+namelist_append_subdomain(dns_db_t *db, dns_name_t *name, dns_diff_t *affected)
+{
+ isc_result_t result;
+ dns_fixedname_t fixedname;
+ dns_name_t *child;
+ dns_dbiterator_t *dbit = NULL;
+
+ dns_fixedname_init(&fixedname);
+ child = dns_fixedname_name(&fixedname);
+
+ CHECK(dns_db_createiterator(db, DNS_DB_NONSEC3, &dbit));
+
+ for (result = dns_dbiterator_seek(dbit, name);
+ result == ISC_R_SUCCESS;
+ result = dns_dbiterator_next(dbit))
+ {
+ dns_dbnode_t *node = NULL;
+ CHECK(dns_dbiterator_current(dbit, &node, child));
+ dns_db_detachnode(db, &node);
+ if (! dns_name_issubdomain(child, name))
+ break;
+ CHECK(namelist_append_name(affected, child));
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ failure:
+ if (dbit != NULL)
+ dns_dbiterator_destroy(&dbit);
+ return (result);
+}
+
+
+
+/*%
+ * Helper function for non_nsec_rrset_exists().
+ */
+static isc_result_t
+is_non_nsec_action(void *data, dns_rdataset_t *rrset) {
+ UNUSED(data);
+ if (!(rrset->type == dns_rdatatype_nsec ||
+ rrset->type == dns_rdatatype_nsec3 ||
+ (rrset->type == dns_rdatatype_rrsig &&
+ (rrset->covers == dns_rdatatype_nsec ||
+ rrset->covers == dns_rdatatype_nsec3))))
+ return (ISC_R_EXISTS);
+ return (ISC_R_SUCCESS);
+}
+
+/*%
+ * Check whether there is an rrset other than a NSEC or RRSIG NSEC,
+ * i.e., anything that justifies the continued existence of a name
+ * after a secure update.
+ *
+ * If such an rrset exists, set '*exists' to ISC_TRUE.
+ * Otherwise, set it to ISC_FALSE.
+ */
+static isc_result_t
+non_nsec_rrset_exists(dns_db_t *db, dns_dbversion_t *ver,
+ dns_name_t *name, isc_boolean_t *exists)
+{
+ isc_result_t result;
+ result = foreach_rrset(db, ver, name, is_non_nsec_action, NULL);
+ RETURN_EXISTENCE_FLAG;
+}
+
+/*%
+ * A comparison function for sorting dns_diff_t:s by name.
+ */
+static int
+name_order(const void *av, const void *bv) {
+ dns_difftuple_t const * const *ap = av;
+ dns_difftuple_t const * const *bp = bv;
+ dns_difftuple_t const *a = *ap;
+ dns_difftuple_t const *b = *bp;
+ return (dns_name_compare(&a->name, &b->name));
+}
+
+static isc_result_t
+uniqify_name_list(dns_diff_t *list) {
+ isc_result_t result;
+ dns_difftuple_t *p, *q;
+
+ CHECK(dns_diff_sort(list, name_order));
+
+ p = ISC_LIST_HEAD(list->tuples);
+ while (p != NULL) {
+ do {
+ q = ISC_LIST_NEXT(p, link);
+ if (q == NULL || ! dns_name_equal(&p->name, &q->name))
+ break;
+ ISC_LIST_UNLINK(list->tuples, q, link);
+ dns_difftuple_free(&q);
+ } while (1);
+ p = ISC_LIST_NEXT(p, link);
+ }
+ failure:
+ return (result);
+}
+
+static isc_result_t
+is_active(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ isc_boolean_t *flag, isc_boolean_t *cut, isc_boolean_t *unsecure)
+{
+ isc_result_t result;
+ dns_fixedname_t foundname;
+ dns_fixedname_init(&foundname);
+ result = dns_db_find(db, name, ver, dns_rdatatype_any,
+ DNS_DBFIND_GLUEOK | DNS_DBFIND_NOWILD,
+ (isc_stdtime_t) 0, NULL,
+ dns_fixedname_name(&foundname),
+ NULL, NULL);
+ if (result == ISC_R_SUCCESS || result == DNS_R_EMPTYNAME) {
+ *flag = ISC_TRUE;
+ *cut = ISC_FALSE;
+ if (unsecure != NULL)
+ *unsecure = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+ } else if (result == DNS_R_ZONECUT) {
+ *flag = ISC_TRUE;
+ *cut = ISC_TRUE;
+ if (unsecure != NULL) {
+ /*
+ * We are at the zonecut. Check to see if there
+ * is a DS RRset.
+ */
+ if (dns_db_find(db, name, ver, dns_rdatatype_ds, 0,
+ (isc_stdtime_t) 0, NULL,
+ dns_fixedname_name(&foundname),
+ NULL, NULL) == DNS_R_NXRRSET)
+ *unsecure = ISC_TRUE;
+ else
+ *unsecure = ISC_FALSE;
+ }
+ return (ISC_R_SUCCESS);
+ } else if (result == DNS_R_GLUE || result == DNS_R_DNAME ||
+ result == DNS_R_DELEGATION || result == DNS_R_NXDOMAIN) {
+ *flag = ISC_FALSE;
+ *cut = ISC_FALSE;
+ if (unsecure != NULL)
+ *unsecure = ISC_FALSE;
+ return (ISC_R_SUCCESS);
+ } else {
+ /*
+ * Silence compiler.
+ */
+ *flag = ISC_FALSE;
+ *cut = ISC_FALSE;
+ if (unsecure != NULL)
+ *unsecure = ISC_FALSE;
+ return (result);
+ }
+}
+
+/*%
+ * Find the next/previous name that has a NSEC record.
+ * In other words, skip empty database nodes and names that
+ * have had their NSECs removed because they are obscured by
+ * a zone cut.
+ */
+static isc_result_t
+next_active(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
+ dns_dbversion_t *ver, dns_name_t *oldname, dns_name_t *newname,
+ isc_boolean_t forward)
+{
+ isc_result_t result;
+ dns_dbiterator_t *dbit = NULL;
+ isc_boolean_t has_nsec = ISC_FALSE;
+ unsigned int wraps = 0;
+ isc_boolean_t secure = dns_db_issecure(db);
+
+ CHECK(dns_db_createiterator(db, 0, &dbit));
+
+ CHECK(dns_dbiterator_seek(dbit, oldname));
+ do {
+ dns_dbnode_t *node = NULL;
+
+ if (forward)
+ result = dns_dbiterator_next(dbit);
+ else
+ result = dns_dbiterator_prev(dbit);
+ if (result == ISC_R_NOMORE) {
+ /*
+ * Wrap around.
+ */
+ if (forward)
+ CHECK(dns_dbiterator_first(dbit));
+ else
+ CHECK(dns_dbiterator_last(dbit));
+ wraps++;
+ if (wraps == 2) {
+ update_log(log, zone, ISC_LOG_ERROR,
+ "secure zone with no NSECs");
+ result = DNS_R_BADZONE;
+ goto failure;
+ }
+ }
+ CHECK(dns_dbiterator_current(dbit, &node, newname));
+ dns_db_detachnode(db, &node);
+
+ /*
+ * The iterator may hold the tree lock, and
+ * rrset_exists() calls dns_db_findnode() which
+ * may try to reacquire it. To avoid deadlock
+ * we must pause the iterator first.
+ */
+ CHECK(dns_dbiterator_pause(dbit));
+ if (secure) {
+ CHECK(rrset_exists(db, ver, newname,
+ dns_rdatatype_nsec, 0, &has_nsec));
+ } else {
+ dns_fixedname_t ffound;
+ dns_name_t *found;
+ dns_fixedname_init(&ffound);
+ found = dns_fixedname_name(&ffound);
+ result = dns_db_find(db, newname, ver,
+ dns_rdatatype_soa,
+ DNS_DBFIND_NOWILD, 0, NULL, found,
+ NULL, NULL);
+ if (result == ISC_R_SUCCESS ||
+ result == DNS_R_EMPTYNAME ||
+ result == DNS_R_NXRRSET ||
+ result == DNS_R_CNAME ||
+ (result == DNS_R_DELEGATION &&
+ dns_name_equal(newname, found))) {
+ has_nsec = ISC_TRUE;
+ result = ISC_R_SUCCESS;
+ } else if (result != DNS_R_NXDOMAIN)
+ break;
+ }
+ } while (! has_nsec);
+ failure:
+ if (dbit != NULL)
+ dns_dbiterator_destroy(&dbit);
+
+ return (result);
+}
+
+/*%
+ * Add a NSEC record for "name", recording the change in "diff".
+ * The existing NSEC is removed.
+ */
+static isc_result_t
+add_nsec(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
+ dns_dbversion_t *ver, dns_name_t *name, dns_ttl_t nsecttl,
+ dns_diff_t *diff)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ unsigned char buffer[DNS_NSEC_BUFFERSIZE];
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_difftuple_t *tuple = NULL;
+ dns_fixedname_t fixedname;
+ dns_name_t *target;
+
+ dns_fixedname_init(&fixedname);
+ target = dns_fixedname_name(&fixedname);
+
+ /*
+ * Find the successor name, aka NSEC target.
+ */
+ CHECK(next_active(log, zone, db, ver, name, target, ISC_TRUE));
+
+ /*
+ * Create the NSEC RDATA.
+ */
+ CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
+ dns_rdata_init(&rdata);
+ CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata));
+ dns_db_detachnode(db, &node);
+
+ /*
+ * Delete the old NSEC and record the change.
+ */
+ CHECK(delete_if(true_p, db, ver, name, dns_rdatatype_nsec, 0,
+ NULL, diff));
+ /*
+ * Add the new NSEC and record the change.
+ */
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
+ nsecttl, &rdata, &tuple));
+ CHECK(do_one_tuple(&tuple, db, ver, diff));
+ INSIST(tuple == NULL);
+
+ failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+/*%
+ * Add a placeholder NSEC record for "name", recording the change in "diff".
+ */
+static isc_result_t
+add_placeholder_nsec(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ dns_diff_t *diff)
+{
+ isc_result_t result;
+ dns_difftuple_t *tuple = NULL;
+ isc_region_t r;
+ unsigned char data[1] = { 0 }; /* The root domain, no bits. */
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+
+ r.base = data;
+ r.length = sizeof(data);
+ dns_rdata_fromregion(&rdata, dns_db_class(db), dns_rdatatype_nsec, &r);
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name, 0,
+ &rdata, &tuple));
+ CHECK(do_one_tuple(&tuple, db, ver, diff));
+ failure:
+ return (result);
+}
+
+static isc_result_t
+find_zone_keys(dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *ver,
+ isc_mem_t *mctx, unsigned int maxkeys,
+ dst_key_t **keys, unsigned int *nkeys)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ const char *directory = dns_zone_getkeydirectory(zone);
+ CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
+ CHECK(dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
+ directory, mctx, maxkeys, keys, nkeys));
+ failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+/*%
+ * Add RRSIG records for an RRset, recording the change in "diff".
+ */
+static isc_result_t
+add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
+ dns_dbversion_t *ver, dns_name_t *name, dns_rdatatype_t type,
+ dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
+ isc_stdtime_t inception, isc_stdtime_t expire,
+ isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t sig_rdata = DNS_RDATA_INIT;
+ isc_buffer_t buffer;
+ unsigned char data[1024]; /* XXX */
+ unsigned int i, j;
+ isc_boolean_t added_sig = ISC_FALSE;
+ isc_mem_t *mctx = diff->mctx;
+
+ dns_rdataset_init(&rdataset);
+ isc_buffer_init(&buffer, data, sizeof(data));
+
+ /* Get the rdataset to sign. */
+ if (type == dns_rdatatype_nsec3)
+ CHECK(dns_db_findnsec3node(db, name, ISC_FALSE, &node));
+ else
+ CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
+ CHECK(dns_db_findrdataset(db, node, ver, type, 0,
+ (isc_stdtime_t) 0, &rdataset, NULL));
+ dns_db_detachnode(db, &node);
+
+#define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
+#define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
+#define ALG(x) dst_key_alg(x)
+
+ /*
+ * If we are honoring KSK flags then we need to check that we
+ * have both KSK and non-KSK keys that are not revoked per
+ * algorithm.
+ */
+ for (i = 0; i < nkeys; i++) {
+ isc_boolean_t both = ISC_FALSE;
+
+ if (!dst_key_isprivate(keys[i]))
+ continue;
+
+ if (check_ksk && !REVOKE(keys[i])) {
+ isc_boolean_t have_ksk, have_nonksk;
+ if (KSK(keys[i])) {
+ have_ksk = ISC_TRUE;
+ have_nonksk = ISC_FALSE;
+ } else {
+ have_ksk = ISC_FALSE;
+ have_nonksk = ISC_TRUE;
+ }
+ for (j = 0; j < nkeys; j++) {
+ if (j == i || ALG(keys[i]) != ALG(keys[j]))
+ continue;
+ if (REVOKE(keys[j]))
+ continue;
+ if (KSK(keys[j]))
+ have_ksk = ISC_TRUE;
+ else
+ have_nonksk = ISC_TRUE;
+ both = have_ksk && have_nonksk;
+ if (both)
+ break;
+ }
+ }
+
+ if (both) {
+ if (type == dns_rdatatype_dnskey) {
+ if (!KSK(keys[i]) && keyset_kskonly)
+ continue;
+ } else if (KSK(keys[i]))
+ continue;
+ } else if (REVOKE(keys[i]) && type != dns_rdatatype_dnskey)
+ continue;
+
+ /* Calculate the signature, creating a RRSIG RDATA. */
+ CHECK(dns_dnssec_sign(name, &rdataset, keys[i],
+ &inception, &expire,
+ mctx, &buffer, &sig_rdata));
+
+ /* Update the database and journal with the RRSIG. */
+ /* XXX inefficient - will cause dataset merging */
+ CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, name,
+ rdataset.ttl, &sig_rdata));
+ dns_rdata_reset(&sig_rdata);
+ isc_buffer_init(&buffer, data, sizeof(data));
+ added_sig = ISC_TRUE;
+ }
+ if (!added_sig) {
+ update_log(log, zone, ISC_LOG_ERROR,
+ "found no active private keys, "
+ "unable to generate any signatures");
+ result = ISC_R_NOTFOUND;
+ }
+
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+/*
+ * Delete expired RRsigs and any RRsigs we are about to re-sign.
+ * See also zone.c:del_sigs().
+ */
+static isc_result_t
+del_keysigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned int i;
+ dns_rdata_rrsig_t rrsig;
+ isc_boolean_t found;
+
+ dns_rdataset_init(&rdataset);
+
+ result = dns_db_findnode(db, name, ISC_FALSE, &node);
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+ result = dns_db_findrdataset(db, node, ver, dns_rdatatype_rrsig,
+ dns_rdatatype_dnskey, (isc_stdtime_t) 0,
+ &rdataset, NULL);
+ dns_db_detachnode(db, &node);
+
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset)) {
+ dns_rdataset_current(&rdataset, &rdata);
+ result = dns_rdata_tostruct(&rdata, &rrsig, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ found = ISC_FALSE;
+ for (i = 0; i < nkeys; i++) {
+ if (rrsig.keyid == dst_key_id(keys[i])) {
+ found = ISC_TRUE;
+ if (!dst_key_isprivate(keys[i])) {
+ /*
+ * The re-signing code in zone.c
+ * will mark this as offline.
+ * Just skip the record for now.
+ */
+ break;
+ }
+ result = update_one_rr(db, ver, diff,
+ DNS_DIFFOP_DEL, name,
+ rdataset.ttl, &rdata);
+ break;
+ }
+ }
+ /*
+ * If there is not a matching DNSKEY then delete the RRSIG.
+ */
+ if (!found)
+ result = update_one_rr(db, ver, diff, DNS_DIFFOP_DEL,
+ name, rdataset.ttl, &rdata);
+ dns_rdata_reset(&rdata);
+ if (result != ISC_R_SUCCESS)
+ break;
+ }
+ dns_rdataset_disassociate(&rdataset);
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+static isc_result_t
+add_exposed_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
+ dns_dbversion_t *ver, dns_name_t *name, isc_boolean_t cut,
+ dns_diff_t *diff, dst_key_t **keys, unsigned int nkeys,
+ isc_stdtime_t inception, isc_stdtime_t expire,
+ isc_boolean_t check_ksk, isc_boolean_t keyset_kskonly)
+{
+ isc_result_t result;
+ dns_dbnode_t *node;
+ dns_rdatasetiter_t *iter;
+
+ node = NULL;
+ result = dns_db_findnode(db, name, ISC_FALSE, &node);
+ if (result == ISC_R_NOTFOUND)
+ return (ISC_R_SUCCESS);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+
+ iter = NULL;
+ result = dns_db_allrdatasets(db, node, ver,
+ (isc_stdtime_t) 0, &iter);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_node;
+
+ for (result = dns_rdatasetiter_first(iter);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(iter))
+ {
+ dns_rdataset_t rdataset;
+ dns_rdatatype_t type;
+ isc_boolean_t flag;
+
+ dns_rdataset_init(&rdataset);
+ dns_rdatasetiter_current(iter, &rdataset);
+ type = rdataset.type;
+ dns_rdataset_disassociate(&rdataset);
+
+ /*
+ * We don't need to sign unsigned NSEC records at the cut
+ * as they are handled elsewhere.
+ */
+ if ((type == dns_rdatatype_rrsig) ||
+ (cut && type != dns_rdatatype_ds))
+ continue;
+ result = rrset_exists(db, ver, name, dns_rdatatype_rrsig,
+ type, &flag);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_iterator;
+ if (flag)
+ continue;;
+ result = add_sigs(log, zone, db, ver, name, type, diff,
+ keys, nkeys, inception, expire,
+ check_ksk, keyset_kskonly);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_iterator;
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+
+ cleanup_iterator:
+ dns_rdatasetiter_destroy(&iter);
+
+ cleanup_node:
+ dns_db_detachnode(db, &node);
+
+ return (result);
+}
+
+/*%
+ * Update RRSIG, NSEC and NSEC3 records affected by an update. The original
+ * update, including the SOA serial update but excluding the RRSIG & NSEC
+ * changes, is in "diff" and has already been applied to "newver" of "db".
+ * The database version prior to the update is "oldver".
+ *
+ * The necessary RRSIG, NSEC and NSEC3 changes will be applied to "newver"
+ * and added (as a minimal diff) to "diff".
+ *
+ * The RRSIGs generated will be valid for 'sigvalidityinterval' seconds.
+ */
+isc_result_t
+dns_update_signatures(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
+ dns_dbversion_t *oldver, dns_dbversion_t *newver,
+ dns_diff_t *diff, isc_uint32_t sigvalidityinterval)
+{
+ isc_result_t result;
+ dns_difftuple_t *t;
+ dns_diff_t diffnames;
+ dns_diff_t affected;
+ dns_diff_t sig_diff;
+ dns_diff_t nsec_diff;
+ dns_diff_t nsec_mindiff;
+ isc_boolean_t flag, build_nsec, build_nsec3;
+ dst_key_t *zone_keys[MAXZONEKEYS];
+ unsigned int nkeys = 0;
+ unsigned int i;
+ isc_stdtime_t now, inception, expire;
+ dns_ttl_t nsecttl;
+ dns_rdata_soa_t soa;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t rdataset;
+ dns_dbnode_t *node = NULL;
+ isc_boolean_t check_ksk, keyset_kskonly;
+ isc_boolean_t unsecure;
+ isc_boolean_t cut;
+ dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone);
+
+ dns_diff_init(diff->mctx, &diffnames);
+ dns_diff_init(diff->mctx, &affected);
+
+ dns_diff_init(diff->mctx, &sig_diff);
+ sig_diff.resign = dns_zone_getsigresigninginterval(zone);
+ dns_diff_init(diff->mctx, &nsec_diff);
+ dns_diff_init(diff->mctx, &nsec_mindiff);
+
+ result = find_zone_keys(zone, db, newver, diff->mctx,
+ MAXZONEKEYS, zone_keys, &nkeys);
+ if (result != ISC_R_SUCCESS) {
+ update_log(log, zone, ISC_LOG_ERROR,
+ "could not get zone keys for secure dynamic update");
+ goto failure;
+ }
+
+ isc_stdtime_get(&now);
+ inception = now - 3600; /* Allow for some clock skew. */
+ expire = now + sigvalidityinterval;
+
+ /*
+ * Do we look at the KSK flag on the DNSKEY to determining which
+ * keys sign which RRsets? First check the zone option then
+ * check the keys flags to make sure at least one has a ksk set
+ * and one doesn't.
+ */
+ check_ksk = ISC_TF((dns_zone_getoptions(zone) &
+ DNS_ZONEOPT_UPDATECHECKKSK) != 0);
+ keyset_kskonly = ISC_TF((dns_zone_getoptions(zone) &
+ DNS_ZONEOPT_DNSKEYKSKONLY) != 0);
+
+ /*
+ * Get the NSEC/NSEC3 TTL from the SOA MINIMUM field.
+ */
+ CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
+ dns_rdataset_init(&rdataset);
+ CHECK(dns_db_findrdataset(db, node, newver, dns_rdatatype_soa, 0,
+ (isc_stdtime_t) 0, &rdataset, NULL));
+ CHECK(dns_rdataset_first(&rdataset));
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(dns_rdata_tostruct(&rdata, &soa, NULL));
+ nsecttl = soa.minimum;
+ dns_rdataset_disassociate(&rdataset);
+ dns_db_detachnode(db, &node);
+
+ /*
+ * Find all RRsets directly affected by the update, and
+ * update their RRSIGs. Also build a list of names affected
+ * by the update in "diffnames".
+ */
+ CHECK(dns_diff_sort(diff, temp_order));
+
+ t = ISC_LIST_HEAD(diff->tuples);
+ while (t != NULL) {
+ dns_name_t *name = &t->name;
+ /* Now "name" is a new, unique name affected by the update. */
+
+ CHECK(namelist_append_name(&diffnames, name));
+
+ while (t != NULL && dns_name_equal(&t->name, name)) {
+ dns_rdatatype_t type;
+ type = t->rdata.type;
+
+ /*
+ * Now "name" and "type" denote a new unique RRset
+ * affected by the update.
+ */
+
+ /* Don't sign RRSIGs. */
+ if (type == dns_rdatatype_rrsig)
+ goto skip;
+
+ /*
+ * Delete all old RRSIGs covering this type, since they
+ * are all invalid when the signed RRset has changed.
+ * We may not be able to recreate all of them - tough.
+ * Special case changes to the zone's DNSKEY records
+ * to support offline KSKs.
+ */
+ if (type == dns_rdatatype_dnskey)
+ del_keysigs(db, newver, name, &sig_diff,
+ zone_keys, nkeys);
+ else
+ CHECK(delete_if(true_p, db, newver, name,
+ dns_rdatatype_rrsig, type,
+ NULL, &sig_diff));
+
+ /*
+ * If this RRset is still visible after the update,
+ * add a new signature for it.
+ */
+ CHECK(rrset_visible(db, newver, name, type, &flag));
+ if (flag) {
+ CHECK(add_sigs(log, zone, db, newver, name,
+ type, &sig_diff, zone_keys,
+ nkeys, inception, expire,
+ check_ksk, keyset_kskonly));
+ }
+ skip:
+ /* Skip any other updates to the same RRset. */
+ while (t != NULL &&
+ dns_name_equal(&t->name, name) &&
+ t->rdata.type == type)
+ {
+ t = ISC_LIST_NEXT(t, link);
+ }
+ }
+ }
+ update_log(log, zone, ISC_LOG_DEBUG(3), "updated data signatures");
+
+ /* Remove orphaned NSECs and RRSIG NSECs. */
+ for (t = ISC_LIST_HEAD(diffnames.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ CHECK(non_nsec_rrset_exists(db, newver, &t->name, &flag));
+ if (! flag) {
+ CHECK(delete_if(true_p, db, newver, &t->name,
+ dns_rdatatype_any, 0,
+ NULL, &sig_diff));
+ }
+ }
+ update_log(log, zone, ISC_LOG_DEBUG(3),
+ "removed any orphaned NSEC records");
+
+ /*
+ * See if we need to build NSEC or NSEC3 chains.
+ */
+ CHECK(dns_private_chains(db, newver, privatetype, &build_nsec,
+ &build_nsec3));
+ if (!build_nsec)
+ goto update_nsec3;
+
+ update_log(log, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC chain");
+
+ /*
+ * When a name is created or deleted, its predecessor needs to
+ * have its NSEC updated.
+ */
+ for (t = ISC_LIST_HEAD(diffnames.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ isc_boolean_t existed, exists;
+ dns_fixedname_t fixedname;
+ dns_name_t *prevname;
+
+ dns_fixedname_init(&fixedname);
+ prevname = dns_fixedname_name(&fixedname);
+
+ if (oldver != NULL)
+ CHECK(name_exists(db, oldver, &t->name, &existed));
+ else
+ existed = ISC_FALSE;
+ CHECK(name_exists(db, newver, &t->name, &exists));
+ if (exists == existed)
+ continue;
+
+ /*
+ * Find the predecessor.
+ * When names become obscured or unobscured in this update
+ * transaction, we may find the wrong predecessor because
+ * the NSECs have not yet been updated to reflect the delegation
+ * change. This should not matter because in this case,
+ * the correct predecessor is either the delegation node or
+ * a newly unobscured node, and those nodes are on the
+ * "affected" list in any case.
+ */
+ CHECK(next_active(log, zone, db, newver,
+ &t->name, prevname, ISC_FALSE));
+ CHECK(namelist_append_name(&affected, prevname));
+ }
+
+ /*
+ * Find names potentially affected by delegation changes
+ * (obscured by adding an NS or DNAME, or unobscured by
+ * removing one).
+ */
+ for (t = ISC_LIST_HEAD(diffnames.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ isc_boolean_t ns_existed, dname_existed;
+ isc_boolean_t ns_exists, dname_exists;
+
+ if (oldver != NULL)
+ CHECK(rrset_exists(db, oldver, &t->name,
+ dns_rdatatype_ns, 0, &ns_existed));
+ else
+ ns_existed = ISC_FALSE;
+ if (oldver != NULL)
+ CHECK(rrset_exists(db, oldver, &t->name,
+ dns_rdatatype_dname, 0,
+ &dname_existed));
+ else
+ dname_existed = ISC_FALSE;
+ CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_ns, 0,
+ &ns_exists));
+ CHECK(rrset_exists(db, newver, &t->name, dns_rdatatype_dname, 0,
+ &dname_exists));
+ if ((ns_exists || dname_exists) == (ns_existed || dname_existed))
+ continue;
+ /*
+ * There was a delegation change. Mark all subdomains
+ * of t->name as potentially needing a NSEC update.
+ */
+ CHECK(namelist_append_subdomain(db, &t->name, &affected));
+ }
+
+ ISC_LIST_APPENDLIST(affected.tuples, diffnames.tuples, link);
+ INSIST(ISC_LIST_EMPTY(diffnames.tuples));
+
+ CHECK(uniqify_name_list(&affected));
+
+ /*
+ * Determine which names should have NSECs, and delete/create
+ * NSECs to make it so. We don't know the final NSEC targets yet,
+ * so we just create placeholder NSECs with arbitrary contents
+ * to indicate that their respective owner names should be part of
+ * the NSEC chain.
+ */
+ for (t = ISC_LIST_HEAD(affected.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ isc_boolean_t exists;
+ dns_name_t *name = &t->name;
+
+ CHECK(name_exists(db, newver, name, &exists));
+ if (! exists)
+ continue;
+ CHECK(is_active(db, newver, name, &flag, &cut, NULL));
+ if (!flag) {
+ /*
+ * This name is obscured. Delete any
+ * existing NSEC record.
+ */
+ CHECK(delete_if(true_p, db, newver, name,
+ dns_rdatatype_nsec, 0,
+ NULL, &nsec_diff));
+ CHECK(delete_if(rrsig_p, db, newver, name,
+ dns_rdatatype_any, 0, NULL, diff));
+ } else {
+ /*
+ * This name is not obscured. It needs to have a
+ * NSEC unless it is the at the origin, in which
+ * case it should already exist if there is a complete
+ * NSEC chain and if there isn't a complete NSEC chain
+ * we don't want to add one as that would signal that
+ * there is a complete NSEC chain.
+ */
+ if (!dns_name_equal(name, dns_db_origin(db))) {
+ CHECK(rrset_exists(db, newver, name,
+ dns_rdatatype_nsec, 0,
+ &flag));
+ if (!flag)
+ CHECK(add_placeholder_nsec(db, newver,
+ name, diff));
+ }
+ CHECK(add_exposed_sigs(log, zone, db, newver, name,
+ cut, &sig_diff, zone_keys, nkeys,
+ inception, expire, check_ksk,
+ keyset_kskonly));
+ }
+ }
+
+ /*
+ * Now we know which names are part of the NSEC chain.
+ * Make them all point at their correct targets.
+ */
+ for (t = ISC_LIST_HEAD(affected.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ CHECK(rrset_exists(db, newver, &t->name,
+ dns_rdatatype_nsec, 0, &flag));
+ if (flag) {
+ /*
+ * There is a NSEC, but we don't know if it is correct.
+ * Delete it and create a correct one to be sure.
+ * If the update was unnecessary, the diff minimization
+ * will take care of eliminating it from the journal,
+ * IXFRs, etc.
+ *
+ * The RRSIG bit should always be set in the NSECs
+ * we generate, because they will all get RRSIG NSECs.
+ * (XXX what if the zone keys are missing?).
+ * Because the RRSIG NSECs have not necessarily been
+ * created yet, the correctness of the bit mask relies
+ * on the assumption that NSECs are only created if
+ * there is other data, and if there is other data,
+ * there are other RRSIGs.
+ */
+ CHECK(add_nsec(log, zone, db, newver, &t->name,
+ nsecttl, &nsec_diff));
+ }
+ }
+
+ /*
+ * Minimize the set of NSEC updates so that we don't
+ * have to regenerate the RRSIG NSECs for NSECs that were
+ * replaced with identical ones.
+ */
+ while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
+ ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
+ dns_diff_appendminimal(&nsec_mindiff, &t);
+ }
+
+ update_log(log, zone, ISC_LOG_DEBUG(3), "signing rebuilt NSEC chain");
+
+ /* Update RRSIG NSECs. */
+ for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ if (t->op == DNS_DIFFOP_DEL) {
+ CHECK(delete_if(true_p, db, newver, &t->name,
+ dns_rdatatype_rrsig, dns_rdatatype_nsec,
+ NULL, &sig_diff));
+ } else if (t->op == DNS_DIFFOP_ADD) {
+ CHECK(add_sigs(log, zone, db, newver, &t->name,
+ dns_rdatatype_nsec, &sig_diff,
+ zone_keys, nkeys, inception, expire,
+ check_ksk, keyset_kskonly));
+ } else {
+ INSIST(0);
+ }
+ }
+
+ update_nsec3:
+
+ /* Record our changes for the journal. */
+ while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
+ ISC_LIST_UNLINK(sig_diff.tuples, t, link);
+ dns_diff_appendminimal(diff, &t);
+ }
+ while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
+ ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
+ dns_diff_appendminimal(diff, &t);
+ }
+
+ INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
+ INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
+ INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
+
+ if (!build_nsec3) {
+ update_log(log, zone, ISC_LOG_DEBUG(3),
+ "no NSEC3 chains to rebuild");
+ goto failure;
+ }
+
+ update_log(log, zone, ISC_LOG_DEBUG(3), "rebuilding NSEC3 chains");
+
+ dns_diff_clear(&diffnames);
+ dns_diff_clear(&affected);
+
+ CHECK(dns_diff_sort(diff, temp_order));
+
+ /*
+ * Find names potentially affected by delegation changes
+ * (obscured by adding an NS or DNAME, or unobscured by
+ * removing one).
+ */
+ t = ISC_LIST_HEAD(diff->tuples);
+ while (t != NULL) {
+ dns_name_t *name = &t->name;
+
+ isc_boolean_t ns_existed, dname_existed;
+ isc_boolean_t ns_exists, dname_exists;
+ isc_boolean_t exists, existed;
+
+ if (t->rdata.type == dns_rdatatype_nsec ||
+ t->rdata.type == dns_rdatatype_rrsig) {
+ t = ISC_LIST_NEXT(t, link);
+ continue;
+ }
+
+ CHECK(namelist_append_name(&affected, name));
+
+ if (oldver != NULL)
+ CHECK(rrset_exists(db, oldver, name, dns_rdatatype_ns,
+ 0, &ns_existed));
+ else
+ ns_existed = ISC_FALSE;
+ if (oldver != NULL)
+ CHECK(rrset_exists(db, oldver, name,
+ dns_rdatatype_dname, 0,
+ &dname_existed));
+ else
+ dname_existed = ISC_FALSE;
+ CHECK(rrset_exists(db, newver, name, dns_rdatatype_ns, 0,
+ &ns_exists));
+ CHECK(rrset_exists(db, newver, name, dns_rdatatype_dname, 0,
+ &dname_exists));
+
+ exists = ns_exists || dname_exists;
+ existed = ns_existed || dname_existed;
+ if (exists == existed)
+ goto nextname;
+ /*
+ * There was a delegation change. Mark all subdomains
+ * of t->name as potentially needing a NSEC3 update.
+ */
+ CHECK(namelist_append_subdomain(db, name, &affected));
+
+ nextname:
+ while (t != NULL && dns_name_equal(&t->name, name))
+ t = ISC_LIST_NEXT(t, link);
+ }
+
+ for (t = ISC_LIST_HEAD(affected.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link)) {
+ dns_name_t *name = &t->name;
+
+ unsecure = ISC_FALSE; /* Silence compiler warning. */
+ CHECK(is_active(db, newver, name, &flag, &cut, &unsecure));
+
+ if (!flag) {
+ CHECK(delete_if(rrsig_p, db, newver, name,
+ dns_rdatatype_any, 0, NULL, diff));
+ CHECK(dns_nsec3_delnsec3sx(db, newver, name,
+ privatetype, &nsec_diff));
+ } else {
+ CHECK(add_exposed_sigs(log, zone, db, newver, name,
+ cut, &sig_diff, zone_keys, nkeys,
+ inception, expire, check_ksk,
+ keyset_kskonly));
+ CHECK(dns_nsec3_addnsec3sx(db, newver, name, nsecttl,
+ unsecure, privatetype,
+ &nsec_diff));
+ }
+ }
+
+ /*
+ * Minimize the set of NSEC3 updates so that we don't
+ * have to regenerate the RRSIG NSEC3s for NSEC3s that were
+ * replaced with identical ones.
+ */
+ while ((t = ISC_LIST_HEAD(nsec_diff.tuples)) != NULL) {
+ ISC_LIST_UNLINK(nsec_diff.tuples, t, link);
+ dns_diff_appendminimal(&nsec_mindiff, &t);
+ }
+
+ update_log(log, zone, ISC_LOG_DEBUG(3),
+ "signing rebuilt NSEC3 chain");
+
+ /* Update RRSIG NSEC3s. */
+ for (t = ISC_LIST_HEAD(nsec_mindiff.tuples);
+ t != NULL;
+ t = ISC_LIST_NEXT(t, link))
+ {
+ if (t->op == DNS_DIFFOP_DEL) {
+ CHECK(delete_if(true_p, db, newver, &t->name,
+ dns_rdatatype_rrsig,
+ dns_rdatatype_nsec3,
+ NULL, &sig_diff));
+ } else if (t->op == DNS_DIFFOP_ADD) {
+ CHECK(add_sigs(log, zone, db, newver, &t->name,
+ dns_rdatatype_nsec3,
+ &sig_diff, zone_keys, nkeys,
+ inception, expire, check_ksk,
+ keyset_kskonly));
+ } else {
+ INSIST(0);
+ }
+ }
+
+ /* Record our changes for the journal. */
+ while ((t = ISC_LIST_HEAD(sig_diff.tuples)) != NULL) {
+ ISC_LIST_UNLINK(sig_diff.tuples, t, link);
+ dns_diff_appendminimal(diff, &t);
+ }
+ while ((t = ISC_LIST_HEAD(nsec_mindiff.tuples)) != NULL) {
+ ISC_LIST_UNLINK(nsec_mindiff.tuples, t, link);
+ dns_diff_appendminimal(diff, &t);
+ }
+
+ INSIST(ISC_LIST_EMPTY(sig_diff.tuples));
+ INSIST(ISC_LIST_EMPTY(nsec_diff.tuples));
+ INSIST(ISC_LIST_EMPTY(nsec_mindiff.tuples));
+
+ failure:
+ dns_diff_clear(&sig_diff);
+ dns_diff_clear(&nsec_diff);
+ dns_diff_clear(&nsec_mindiff);
+
+ dns_diff_clear(&affected);
+ dns_diff_clear(&diffnames);
+
+ for (i = 0; i < nkeys; i++)
+ dst_key_free(&zone_keys[i]);
+
+ return (result);
+}
isc_uint32_t
dns_update_soaserial(isc_uint32_t serial, dns_updatemethod_t method) {
diff --git a/lib/dns/view.c b/lib/dns/view.c
index fafbae06..cd7a2be4 100644
--- a/lib/dns/view.c
+++ b/lib/dns/view.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: view.c,v 1.181 2011-08-02 20:36:12 each Exp $ */
+/* $Id: view.c,v 1.184 2011-09-06 22:29:33 smann Exp $ */
/*! \file */
@@ -181,7 +181,6 @@ dns_view_create(isc_mem_t *mctx, dns_rdataclass_t rdclass,
view->answeracl_exclude = NULL;
view->denyanswernames = NULL;
view->answernames_exclude = NULL;
- view->requestixfr = ISC_TRUE;
view->provideixfr = ISC_TRUE;
view->maxcachettl = 7 * 24 * 3600;
view->maxncachettl = 3 * 3600;
@@ -1418,6 +1417,7 @@ isc_result_t
dns_view_load(dns_view_t *view, isc_boolean_t stop) {
REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(view->zonetable != NULL);
return (dns_zt_load(view->zonetable, stop));
}
@@ -1426,9 +1426,20 @@ isc_result_t
dns_view_loadnew(dns_view_t *view, isc_boolean_t stop) {
REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(view->zonetable != NULL);
return (dns_zt_loadnew(view->zonetable, stop));
}
+
+isc_result_t
+dns_view_asyncload(dns_view_t *view, dns_zt_allloaded_t callback, void *arg) {
+ REQUIRE(DNS_VIEW_VALID(view));
+ REQUIRE(view->zonetable != NULL);
+
+ return (dns_zt_asyncload(view->zonetable, callback, arg));
+}
+
+
#endif /* BIND9 */
isc_result_t
@@ -1728,6 +1739,9 @@ isc_result_t
dns_view_issecuredomain(dns_view_t *view, dns_name_t *name,
isc_boolean_t *secure_domain) {
REQUIRE(DNS_VIEW_VALID(view));
+
+ if (view->secroots_priv == NULL)
+ return (ISC_R_NOTFOUND);
return (dns_keytable_issecuredomain(view->secroots_priv, name,
secure_domain));
}
diff --git a/lib/dns/win32/libdns.def b/lib/dns/win32/libdns.def
index 493ed6b2..6ced2e95 100644
--- a/lib/dns/win32/libdns.def
+++ b/lib/dns/win32/libdns.def
@@ -699,6 +699,7 @@ dns_tsigrcode_fromtext
dns_tsigrcode_totext
dns_ttl_fromtext
dns_ttl_totext
+dns_update_signatures
dns_update_soaserial
dns_validator_cancel
dns_validator_create
@@ -706,6 +707,7 @@ dns_validator_destroy
dns_validator_send
dns_view_adddelegationonly
dns_view_addzone
+dns_view_asyncload
dns_view_attach
dns_view_checksig
dns_view_create
@@ -801,6 +803,7 @@ dns_zone_getoptions
dns_zone_getorigin
dns_zone_getprivatetype
dns_zone_getqueryacl
+dns_zone_getraw
dns_zone_getrequeststats
dns_zone_getserial
dns_zone_getserial2
@@ -822,6 +825,7 @@ dns_zone_iattach
dns_zone_idetach
dns_zone_isdynamic
dns_zone_isforced
+dns_zone_link
dns_zone_load
dns_zone_loadandthaw
dns_zone_loadnew
@@ -881,6 +885,7 @@ dns_zone_setprivatetype
dns_zone_setqueryacl
dns_zone_setqueryonacl
dns_zone_setrefreshkeyinterval
+dns_zone_setrequestixfr
dns_zone_setrequeststats
dns_zone_setserialupdatemethod
dns_zone_setsignatures
diff --git a/lib/dns/xfrin.c b/lib/dns/xfrin.c
index 31d21891..e0a23ecc 100644
--- a/lib/dns/xfrin.c
+++ b/lib/dns/xfrin.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: xfrin.c,v 1.170 2011-03-11 06:11:25 marka Exp $ */
+/* $Id: xfrin.c,v 1.171 2011-08-30 05:16:14 marka Exp $ */
/*! \file */
@@ -630,7 +630,8 @@ dns_xfrin_create2(dns_zone_t *zone, dns_rdatatype_t xfrtype,
isc_sockaddr_t *masteraddr, isc_sockaddr_t *sourceaddr,
dns_tsigkey_t *tsigkey, isc_mem_t *mctx,
isc_timermgr_t *timermgr, isc_socketmgr_t *socketmgr,
- isc_task_t *task, dns_xfrindone_t done, dns_xfrin_ctx_t **xfrp)
+ isc_task_t *task, dns_xfrindone_t done,
+ dns_xfrin_ctx_t **xfrp)
{
dns_name_t *zonename = dns_zone_getorigin(zone);
dns_xfrin_ctx_t *xfr = NULL;
diff --git a/lib/dns/zone.c b/lib/dns/zone.c
index 930bbb21..e2ffeb9f 100644
--- a/lib/dns/zone.c
+++ b/lib/dns/zone.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.c,v 1.623 2011-08-09 02:24:28 marka Exp $ */
+/* $Id: zone.c,v 1.632 2011-09-06 22:29:33 smann Exp $ */
/*! \file */
@@ -79,6 +79,7 @@
#include <dns/update.h>
#include <dns/xfrin.h>
#include <dns/zone.h>
+#include <dns/zt.h>
#include <dst/dst.h>
@@ -138,6 +139,7 @@ typedef struct dns_notify dns_notify_t;
typedef struct dns_stub dns_stub_t;
typedef struct dns_load dns_load_t;
typedef struct dns_forward dns_forward_t;
+typedef ISC_LIST(dns_forward_t) dns_forwardlist_t;
typedef struct dns_io dns_io_t;
typedef ISC_LIST(dns_io_t) dns_iolist_t;
typedef struct dns_signing dns_signing_t;
@@ -145,6 +147,7 @@ typedef ISC_LIST(dns_signing_t) dns_signinglist_t;
typedef struct dns_nsec3chain dns_nsec3chain_t;
typedef ISC_LIST(dns_nsec3chain_t) dns_nsec3chainlist_t;
typedef struct dns_keyfetch dns_keyfetch_t;
+typedef struct dns_asyncload dns_asyncload_t;
#define DNS_ZONE_CHECKLOCK
#ifdef DNS_ZONE_CHECKLOCK
@@ -244,6 +247,7 @@ struct dns_zone {
unsigned int notifycnt;
isc_sockaddr_t notifyfrom;
isc_task_t *task;
+ isc_task_t *loadtask;
isc_sockaddr_t notifysrc4;
isc_sockaddr_t notifysrc6;
isc_sockaddr_t xfrsource4;
@@ -345,6 +349,19 @@ struct dns_zone {
* Serial number update method.
*/
dns_updatemethod_t updatemethod;
+
+ /*%
+ * whether ixfr is requested
+ */
+ isc_boolean_t requestixfr;
+
+ /*%
+ * Outstanding forwarded UPDATE requests.
+ */
+ dns_forwardlist_t forwards;
+
+ dns_zone_t *raw;
+ dns_zone_t *secure;
};
#define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
@@ -393,7 +410,7 @@ struct dns_zone {
#define DNS_ZONEFLG_NEEDCOMPACT 0x02000000U
#define DNS_ZONEFLG_REFRESHING 0x04000000U /*%< Refreshing keydata */
#define DNS_ZONEFLG_THAW 0x08000000U
-/* #define DNS_ZONEFLG_XXXXX 0x10000000U XXXMPA unused. */
+#define DNS_ZONEFLG_LOADPENDING 0x10000000U /*%< Loading scheduled */
#define DNS_ZONEFLG_NODELAY 0x20000000U
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
@@ -427,6 +444,7 @@ struct dns_zonemgr {
isc_timermgr_t * timermgr;
isc_socketmgr_t * socketmgr;
isc_taskpool_t * zonetasks;
+ isc_taskpool_t * loadtasks;
isc_task_t * task;
isc_ratelimiter_t * rl;
isc_rwlock_t rwlock;
@@ -510,6 +528,7 @@ struct dns_forward {
isc_sockaddr_t addr;
dns_updatecallback_t callback;
void *callback_arg;
+ ISC_LINK(dns_forward_t) link;
};
/*%
@@ -583,6 +602,15 @@ struct dns_keyfetch {
dns_fetch_t *fetch;
};
+/*%
+ * Hold state for an asynchronous load
+ */
+struct dns_asyncload {
+ dns_zone_t *zone;
+ dns_zt_zoneloaded_t loaded;
+ void *loaded_arg;
+};
+
#define HOUR 3600
#define DAY (24*HOUR)
#define MONTH (30*DAY)
@@ -811,6 +839,7 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->notifytype = dns_notifytype_yes;
zone->notifycnt = 0;
zone->task = NULL;
+ zone->loadtask = NULL;
zone->update_acl = NULL;
zone->forward_acl = NULL;
zone->notify_acl = NULL;
@@ -863,6 +892,9 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->privatetype = (dns_rdatatype_t)0xffffU;
zone->added = ISC_FALSE;
zone->rpz_zone = ISC_FALSE;
+ ISC_LIST_INIT(zone->forwards);
+ zone->raw = NULL;
+ zone->secure = NULL;
zone->magic = ZONE_MAGIC;
@@ -919,6 +951,8 @@ zone_free(dns_zone_t *zone) {
if (zone->task != NULL)
isc_task_detach(&zone->task);
+ if (zone->loadtask != NULL)
+ isc_task_detach(&zone->loadtask);
if (zone->zmgr != NULL)
dns_zonemgr_releasezone(zone->zmgr, zone);
@@ -1026,6 +1060,8 @@ dns_zone_setclass(dns_zone_t *zone, dns_rdataclass_t rdclass) {
zone_rdclass_tostr(zone, namebuf, sizeof namebuf);
zone->strrdclass = isc_mem_strdup(zone->mctx, namebuf);
+ if (zone->raw != NULL)
+ dns_zone_setclass(zone->raw, rdclass);
UNLOCK_ZONE(zone);
}
@@ -1217,10 +1253,12 @@ dns_zone_setview(dns_zone_t *zone, dns_view_t *view) {
zone_viewname_tostr(zone, namebuf, sizeof namebuf);
zone->strviewname = isc_mem_strdup(zone->mctx, namebuf);
+ if (zone->raw != NULL)
+ dns_zone_setview(zone->raw, view);
+
UNLOCK_ZONE(zone);
}
-
dns_view_t *
dns_zone_getview(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
@@ -1254,6 +1292,8 @@ dns_zone_setorigin(dns_zone_t *zone, const dns_name_t *origin) {
zone_name_tostr(zone, namebuf, sizeof namebuf);
zone->strname = isc_mem_strdup(zone->mctx, namebuf);
+ if (result == ISC_R_SUCCESS && zone->raw != NULL)
+ result = dns_zone_setorigin(zone->raw, origin);
UNLOCK_ZONE(zone);
return (result);
}
@@ -1424,6 +1464,12 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
LOCK_ZONE(zone);
TIME_NOW(&now);
+ if (zone->raw != NULL) {
+ result = zone_load(zone->raw, flags);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+ }
+
INSIST(zone->type != dns_zone_none);
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADING)) {
@@ -1433,7 +1479,6 @@ zone_load(dns_zone_t *zone, unsigned int flags) {
goto cleanup;
}
-
INSIST(zone->db_argc >= 1);
rbt = strcmp(zone->db_argv[0], "rbt") == 0 ||
@@ -1592,6 +1637,82 @@ dns_zone_loadnew(dns_zone_t *zone) {
return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT));
}
+static void
+zone_asyncload(isc_task_t *task, isc_event_t *event) {
+ dns_asyncload_t *asl = event->ev_arg;
+ dns_zone_t *zone = asl->zone;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ UNUSED(task);
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ if ((event->ev_attributes & ISC_EVENTATTR_CANCELED) != 0)
+ result = ISC_R_CANCELED;
+ isc_event_free(&event);
+ if (result == ISC_R_CANCELED ||
+ !DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING))
+ return;
+
+ zone_load(zone, 0);
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADPENDING);
+ UNLOCK_ZONE(zone);
+
+ /* Inform the zone table we've finished loading */
+ if (asl->loaded != NULL)
+ (asl->loaded)(asl->loaded_arg, zone, task);
+
+ isc_mem_put(zone->mctx, asl, sizeof (*asl));
+}
+
+isc_result_t
+dns_zone_asyncload(dns_zone_t *zone, dns_zt_zoneloaded_t done, void *arg) {
+ isc_event_t *e;
+ dns_asyncload_t *asl = NULL;
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ if (zone->zmgr == NULL)
+ return (ISC_R_FAILURE);
+
+ asl = isc_mem_get(zone->mctx, sizeof (*asl));
+ if (asl == NULL)
+ CHECK(ISC_R_NOMEMORY);
+
+ asl->zone = zone;
+ asl->loaded = done;
+ asl->loaded_arg = arg;
+
+ e = isc_event_allocate(zone->zmgr->mctx, zone->zmgr,
+ DNS_EVENT_ZONELOAD,
+ zone_asyncload, asl,
+ sizeof(isc_event_t));
+ if (e == NULL)
+ CHECK(ISC_R_NOMEMORY);
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADPENDING);
+ isc_task_send(zone->loadtask, &e);
+ UNLOCK_ZONE(zone);
+
+ return (ISC_R_SUCCESS);
+
+ failure:
+ if (asl != NULL)
+ isc_mem_put(zone->mctx, asl, sizeof (*asl));
+ return (result);
+}
+
+isc_boolean_t
+dns__zone_loadpending(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ return (ISC_TF(DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING)));
+}
+
isc_result_t
dns_zone_loadandthaw(dns_zone_t *zone) {
isc_result_t result;
@@ -1729,7 +1850,7 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS))
options |= DNS_MASTER_MANYERRORS;
- if (zone->zmgr != NULL && zone->db != NULL && zone->task != NULL) {
+ if (zone->zmgr != NULL && zone->db != NULL && zone->loadtask != NULL) {
load = isc_mem_get(zone->mctx, sizeof(*load));
if (load == NULL)
return (ISC_R_NOMEMORY);
@@ -1748,7 +1869,7 @@ zone_startload(dns_db_t *db, dns_zone_t *zone, isc_time_t loadtime) {
&load->callbacks.add_private);
if (result != ISC_R_SUCCESS)
goto cleanup;
- result = zonemgr_getio(zone->zmgr, ISC_TRUE, zone->task,
+ result = zonemgr_getio(zone->zmgr, ISC_TRUE, zone->loadtask,
zone_gotreadhandle, load,
&zone->readio);
if (result != ISC_R_SUCCESS) {
@@ -3105,7 +3226,9 @@ update_soa_serial(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff,
* Write all transactions in 'diff' to the zone journal file.
*/
static isc_result_t
-zone_journal(dns_zone_t *zone, dns_diff_t *diff, const char *caller) {
+zone_journal(dns_zone_t *zone, dns_diff_t *diff, isc_uint32_t *bitws,
+ const char *caller)
+{
const char me[] = "zone_journal";
const char *journalfile;
isc_result_t result = ISC_R_SUCCESS;
@@ -3115,13 +3238,15 @@ zone_journal(dns_zone_t *zone, dns_diff_t *diff, const char *caller) {
journalfile = dns_zone_getjournal(zone);
if (journalfile != NULL) {
result = dns_journal_open(zone->mctx, journalfile,
- ISC_TRUE, &journal);
+ DNS_JOURNAL_CREATE, &journal);
if (result != ISC_R_SUCCESS) {
dns_zone_log(zone, ISC_LOG_ERROR,
"%s:dns_journal_open -> %s\n",
caller, dns_result_totext(result));
return (result);
}
+ if (bitws != NULL)
+ dns_journal_set_bitws(journal, *bitws);
result = dns_journal_write_transaction(journal, diff);
dns_journal_destroy(&journal);
@@ -3314,7 +3439,7 @@ sync_keyzone(dns_zone_t *zone, dns_db_t *db) {
/* Write changes to journal file. */
CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
zone->updatemethod));
- CHECK(zone_journal(zone, &diff, "sync_keyzone"));
+ CHECK(zone_journal(zone, &diff, NULL, "sync_keyzone"));
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
zone_needdump(zone, 30);
@@ -3423,6 +3548,8 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
"journal rollforward failed: %s",
dns_result_totext(result));
goto cleanup;
+
+
}
if (result == ISC_R_NOTFOUND || result == ISC_R_RANGE) {
dns_zone_log(zone, ISC_LOG_ERROR,
@@ -3531,7 +3658,6 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
result = DNS_R_BADZONE;
goto cleanup;
}
-
if (zone->type == dns_zone_master &&
DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKDUPRR) &&
!zone_check_dup(zone, db)) {
@@ -3729,6 +3855,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s", serial,
dns_db_issecure(db) ? " (DNSSEC signed)" : "");
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_LOADPENDING);
return (result);
cleanup:
@@ -3749,6 +3876,7 @@ zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
} else if (zone->type == dns_zone_master ||
zone->type == dns_zone_redirect)
dns_zone_log(zone, ISC_LOG_ERROR, "not loaded due to errors.");
+
return (result);
}
@@ -4030,6 +4158,8 @@ dns_zone_attach(dns_zone_t *source, dns_zone_t **target) {
void
dns_zone_detach(dns_zone_t **zonep) {
dns_zone_t *zone;
+ dns_zone_t *raw = NULL;
+ dns_zone_t *secure = NULL;
unsigned int refs;
isc_boolean_t free_now = ISC_FALSE;
@@ -4067,12 +4197,21 @@ dns_zone_detach(dns_zone_t **zonep) {
*/
INSIST(zone->view == NULL);
free_now = ISC_TRUE;
+ raw = zone->raw;
+ zone->raw = NULL;
+ secure = zone->secure;
+ zone->secure = NULL;
}
UNLOCK_ZONE(zone);
}
*zonep = NULL;
- if (free_now)
+ if (free_now) {
+ if (raw != NULL)
+ dns_zone_detach(&raw);
+ if (secure != NULL)
+ dns_zone_idetach(&secure);
zone_free(zone);
+ }
}
void
@@ -4350,13 +4489,14 @@ clear_addresskeylist(isc_sockaddr_t **addrsp, dns_name_t ***keynamesp,
REQUIRE(countp != NULL && addrsp != NULL && keynamesp != NULL);
count = *countp;
+ *countp = 0;
addrs = *addrsp;
+ *addrsp = NULL;
keynames = *keynamesp;
+ *keynamesp = NULL;
- if (addrs != NULL) {
+ if (addrs != NULL)
isc_mem_put(mctx, addrs, count * sizeof(isc_sockaddr_t));
- addrs = *addrsp = NULL;
- }
if (keynames != NULL) {
unsigned int i;
@@ -4369,10 +4509,7 @@ clear_addresskeylist(isc_sockaddr_t **addrsp, dns_name_t ***keynamesp,
}
}
isc_mem_put(mctx, keynames, count * sizeof(dns_name_t *));
- keynames = *keynamesp = NULL;
}
-
- count = *countp = 0;
}
static isc_result_t
@@ -5185,7 +5322,7 @@ zone_resigninc(dns_zone_t *zone) {
}
/* Write changes to journal file. */
- CHECK(zone_journal(zone, &sig_diff, "zone_resigninc"));
+ CHECK(zone_journal(zone, &sig_diff, NULL, "zone_resigninc"));
/* Everything has succeeded. Commit the changes. */
dns_db_closeversion(db, &version, ISC_TRUE);
@@ -6561,7 +6698,7 @@ zone_nsec3chain(dns_zone_t *zone) {
}
/* Write changes to journal file. */
- CHECK(zone_journal(zone, &sig_diff, "zone_nsec3chain"));
+ CHECK(zone_journal(zone, &sig_diff, NULL, "zone_nsec3chain"));
LOCK_ZONE(zone);
zone_needdump(zone, DNS_DUMP_DELAY);
@@ -7131,7 +7268,7 @@ zone_sign(dns_zone_t *zone) {
/*
* Write changes to journal file.
*/
- CHECK(zone_journal(zone, &sig_diff, "zone_sign"));
+ CHECK(zone_journal(zone, &sig_diff, NULL, "zone_sign"));
pauseall:
/*
@@ -7888,7 +8025,7 @@ keyfetch_done(isc_task_t *task, isc_event_t *event) {
/* Write changes to journal file. */
CHECK(update_soa_serial(kfetch->db, ver, &diff, mctx,
zone->updatemethod));
- CHECK(zone_journal(zone, &diff, "keyfetch_done"));
+ CHECK(zone_journal(zone, &diff, NULL, "keyfetch_done"));
commit = ISC_TRUE;
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
@@ -8046,7 +8183,7 @@ zone_refreshkeys(dns_zone_t *zone) {
if (!ISC_LIST_EMPTY(diff.tuples)) {
CHECK(update_soa_serial(db, ver, &diff, zone->mctx,
zone->updatemethod));
- CHECK(zone_journal(zone, &diff, "sync_keyzone"));
+ CHECK(zone_journal(zone, &diff, NULL, "sync_keyzone"));
commit = ISC_TRUE;
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED);
zone_needdump(zone, 30);
@@ -8074,11 +8211,17 @@ zone_maintenance(dns_zone_t *zone) {
ENTER;
/*
+ * Are we pending load/reload?
+ */
+ if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADPENDING))
+ return;
+
+ /*
* Configuring the view of this zone may have
* failed, for example because the config file
* had a syntax error. In that case, the view
- * adb or resolver, and we had better not try
- * to do maintenance on it.
+ * adb or resolver will be NULL, and we had better not try
+ * to do further maintenance on it.
*/
if (zone->view == NULL || zone->view->adb == NULL)
return;
@@ -8199,6 +8342,7 @@ zone_maintenance(dns_zone_t *zone) {
set_key_expiry_warning(zone, zone->key_expiry,
isc_time_seconds(&now));
break;
+
default:
break;
}
@@ -8396,6 +8540,21 @@ dump_done(void *arg, isc_result_t result) {
tresult = dns_db_getsoaserial(db, version, &serial);
/*
+ * If there is a secure version of this zone
+ * use its serial if it is less than ours.
+ */
+ if (tresult == ISC_R_SUCCESS &&
+ zone->secure != NULL && zone->secure->db != NULL) {
+ isc_uint32_t sserial;
+ isc_result_t mresult;
+
+ mresult = dns_db_getsoaserial(zone->secure->db,
+ NULL, &sserial);
+ if (mresult == ISC_R_SUCCESS &&
+ isc_serial_lt(sserial, serial))
+ serial = sserial;
+ }
+ /*
* Note: we are task locked here so we can test
* zone->xfr safely.
*/
@@ -8616,6 +8775,24 @@ notify_cancel(dns_zone_t *zone) {
}
static void
+forward_cancel(dns_zone_t *zone) {
+ dns_forward_t *forward;
+
+ /*
+ * 'zone' locked by caller.
+ */
+
+ REQUIRE(LOCKED_ZONE(zone));
+
+ for (forward = ISC_LIST_HEAD(zone->forwards);
+ forward != NULL;
+ forward = ISC_LIST_NEXT(forward, link)) {
+ if (forward->request != NULL)
+ dns_request_cancel(forward->request);
+ }
+}
+
+static void
zone_unload(dns_zone_t *zone) {
/*
@@ -9612,7 +9789,7 @@ refresh_callback(isc_task_t *task, isc_event_t *event) {
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_rdata_soa_t soa;
isc_result_t result;
- isc_uint32_t serial, oldserial;
+ isc_uint32_t serial, oldserial = 0;
unsigned int j;
zone = revent->ev_arg;
@@ -10552,11 +10729,13 @@ static void
zone_shutdown(isc_task_t *task, isc_event_t *event) {
dns_zone_t *zone = (dns_zone_t *) event->ev_arg;
isc_boolean_t free_needed, linked = ISC_FALSE;
+ dns_zone_t *raw = NULL, *secure = NULL;
UNUSED(task);
REQUIRE(DNS_ZONE_VALID(zone));
INSIST(event->ev_type == DNS_EVENT_ZONECONTROL);
INSIST(isc_refcount_current(&zone->erefs) == 0);
+
zone_debuglog(zone, "zone_shutdown", 3, "shutting down");
/*
@@ -10615,6 +10794,8 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
notify_cancel(zone);
+ forward_cancel(zone);
+
if (zone->timer != NULL) {
isc_timer_detach(&zone->timer);
INSIST(zone->irefs > 0);
@@ -10631,7 +10812,19 @@ zone_shutdown(isc_task_t *task, isc_event_t *event) {
*/
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_SHUTDOWN);
free_needed = exit_check(zone);
+ if (zone->raw != NULL) {
+ raw = zone->raw;
+ zone->raw = NULL;
+ }
+ if (zone->secure != NULL) {
+ secure = zone->secure;
+ zone->secure = NULL;
+ }
UNLOCK_ZONE(zone);
+ if (raw != NULL)
+ dns_zone_detach(&raw);
+ if (secure != NULL)
+ dns_zone_idetach(&secure);
if (free_needed)
zone_free(zone);
}
@@ -10991,9 +11184,17 @@ dns_zone_notifyreceive(dns_zone_t *zone, isc_sockaddr_t *from,
isc_sockaddr_format(from, fromtext, sizeof(fromtext));
/*
- * We only handle NOTIFY (SOA) at the present.
+ * Notify messages are processed by the raw zone.
*/
LOCK_ZONE(zone);
+ if (zone->raw != NULL) {
+ result = dns_zone_notifyreceive(zone->raw, from, msg);
+ UNLOCK_ZONE(zone);
+ return (result);
+ }
+ /*
+ * We only handle NOTIFY (SOA) at the present.
+ */
if (isc_sockaddr_pf(from) == PF_INET)
inc_stats(zone, dns_zonestatscounter_notifyinv4);
else
@@ -11394,6 +11595,10 @@ zone_namerd_tostr(dns_zone_t *zone, char *buf, size_t length) {
isc_buffer_putstr(&buffer, "/");
isc_buffer_putstr(&buffer, zone->view->name);
}
+ if (zone->raw != NULL && 9U < isc_buffer_availablelength(&buffer))
+ isc_buffer_putstr(&buffer, " (signed)");
+ if (zone->secure != NULL && 11U < isc_buffer_availablelength(&buffer))
+ isc_buffer_putstr(&buffer, " (unsigned)");
buf[isc_buffer_usedlength(&buffer)] = '\0';
}
@@ -11711,6 +11916,333 @@ notify_done(isc_task_t *task, isc_event_t *event) {
dns_message_destroy(&message);
}
+struct secure_serial {
+ isc_event_t e;
+ isc_uint32_t serial;
+};
+
+static void
+update_log_cb(void *arg, dns_zone_t *zone, int level, const char *message) {
+ UNUSED(arg);
+ dns_zone_log(zone, level, "%s", message);
+}
+
+static void
+receive_secure_serial(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ dns_journal_t *rjournal = NULL, *sjournal = NULL;
+ isc_uint32_t start, end;
+ dns_zone_t *zone;
+ int n_soa = 0;
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *newver = NULL, *oldver = NULL;
+ isc_uint32_t oldserial, newserial;
+ dns_diffop_t op = DNS_DIFFOP_ADD;
+ dns_diff_t diff;
+ dns_difftuple_t *tuple = NULL, *soatuple = NULL;
+ dns_update_log_t log = { update_log_cb, NULL };
+ isc_time_t timenow;
+
+ zone = event->ev_arg;
+ end = ((struct secure_serial *)event)->serial;
+
+ dns_diff_init(zone->mctx, &diff);
+
+ UNUSED(task);
+ CHECK(dns_journal_open(zone->raw->mctx, zone->raw->journal,
+ DNS_JOURNAL_WRITE, &rjournal));
+ result = dns_journal_open(zone->raw->mctx, zone->journal,
+ DNS_JOURNAL_READ, &sjournal);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND)
+ goto failure;
+
+ start = dns_journal_get_bitws(rjournal);
+ if (sjournal != NULL) {
+ isc_uint32_t serial = dns_journal_get_bitws(sjournal);
+ /*
+ * We write the secure journal first so if that exists
+ * use its value provided it is greater that from the
+ * raw journal.
+ */
+ if (isc_serial_gt(serial, start))
+ start = serial;
+ dns_journal_destroy(&sjournal);
+ }
+
+ if (start == end)
+ goto failure;
+ CHECK(dns_journal_iter_init(rjournal, start, end));
+
+ dns_db_attach(zone->db, &db);
+ dns_db_currentversion(db, &oldver);
+ CHECK(dns_db_newversion(db, &newver));
+
+ for (result = dns_journal_first_rr(rjournal);
+ result == ISC_R_SUCCESS;
+ result = dns_journal_next_rr(rjournal)) {
+ dns_name_t *name = NULL;
+ isc_uint32_t ttl;
+ dns_rdata_t *rdata = NULL;
+ dns_journal_current_rr(rjournal, &name, &ttl, &rdata);
+
+ if (rdata->type == dns_rdatatype_soa) {
+ n_soa++;
+ if (n_soa == 2) {
+ /*
+ * Save the lastest raw SOA record.
+ */
+ if (soatuple != NULL)
+ dns_difftuple_free(&soatuple);
+ CHECK(dns_difftuple_create(diff.mctx,
+ DNS_DIFFOP_ADD,
+ name, ttl, rdata,
+ &soatuple));
+ }
+ if (n_soa == 3)
+ n_soa = 1;
+ continue;
+ }
+
+ /* Sanity. */
+ if (n_soa == 0) {
+ dns_zone_log(zone->raw, ISC_LOG_ERROR,
+ "corrupt journal file: '%s'\n",
+ zone->raw->journal);
+ goto failure;
+ }
+
+ if (zone->privatetype != 0 &&
+ rdata->type == zone->privatetype)
+ continue;
+
+ if (rdata->type == dns_rdatatype_nsec ||
+ rdata->type == dns_rdatatype_rrsig ||
+ rdata->type == dns_rdatatype_nsec3 ||
+ rdata->type == dns_rdatatype_dnskey ||
+ rdata->type == dns_rdatatype_nsec3param)
+ continue;
+
+ op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD;
+
+ CHECK(dns_difftuple_create(diff.mctx, op, name, ttl, rdata,
+ &tuple));
+ dns_diff_appendminimal(&diff, &tuple);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ CHECK(result);
+
+ CHECK(dns_diff_apply(&diff, db, newver));
+
+ if (soatuple != NULL) {
+ isc_uint32_t desired;
+
+ CHECK(dns_db_createsoatuple(db, oldver, diff.mctx,
+ DNS_DIFFOP_DEL, &tuple));
+ oldserial = dns_soa_getserial(&tuple->rdata);
+ newserial = desired = dns_soa_getserial(&soatuple->rdata);
+ if (!isc_serial_gt(newserial, oldserial)) {
+ newserial = oldserial + 1;
+ if (newserial == 0)
+ newserial++;
+ dns_soa_setserial(newserial, &soatuple->rdata);
+ }
+ CHECK(do_one_tuple(&tuple, db, newver, &diff));
+ CHECK(do_one_tuple(&soatuple, db, newver, &diff));
+ dns_zone_log(zone, ISC_LOG_INFO, "serial %u (unsigned %u)",
+ newserial, desired);
+ } else
+ CHECK(update_soa_serial(db, newver, &diff, zone->mctx,
+ zone->updatemethod));
+
+ CHECK(dns_update_signatures(&log, zone, db, oldver, newver,
+ &diff, zone->sigvalidityinterval));
+
+ CHECK(zone_journal(zone, &diff, &end, "receive_secure_serial"));
+
+ dns_journal_set_bitws(rjournal, end);
+ dns_journal_commit(rjournal);
+
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+
+ zone_needdump(zone, DNS_DUMP_DELAY);
+
+ TIME_NOW(&timenow);
+ zone_settimer(zone, &timenow);
+
+ UNLOCK_ZONE(zone);
+
+ dns_db_closeversion(db, &oldver, ISC_FALSE);
+ dns_db_closeversion(db, &newver, ISC_TRUE);
+
+ failure:
+ if (tuple != NULL)
+ dns_difftuple_free(&tuple);
+ if (soatuple != NULL)
+ dns_difftuple_free(&soatuple);
+ if (db != NULL) {
+ if (oldver != NULL)
+ dns_db_closeversion(db, &oldver, ISC_FALSE);
+ if (newver != NULL)
+ dns_db_closeversion(db, &newver, ISC_FALSE);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ dns_db_detach(&db);
+ }
+ if (rjournal != NULL)
+ dns_journal_destroy(&rjournal);
+ if (sjournal != NULL)
+ dns_journal_destroy(&sjournal);
+ dns_diff_clear(&diff);
+ isc_event_free(&event);
+}
+
+static isc_result_t
+zone_send_secureserial(dns_zone_t *zone, isc_uint32_t serial) {
+ isc_event_t *e;
+
+ e = isc_event_allocate(zone->secure->mctx, zone,
+ DNS_EVENT_ZONESECURESERIAL,
+ receive_secure_serial, zone->secure,
+ sizeof(struct secure_serial));
+ if (e == NULL)
+ return (ISC_R_NOMEMORY);
+ ((struct secure_serial *)e)->serial = serial;
+
+ isc_task_send(zone->secure->task, &e);
+ return (ISC_R_SUCCESS);
+}
+
+struct secure_db {
+ isc_event_t e;
+ dns_db_t *db;
+};
+
+static void
+receive_secure_db(isc_task_t *task, isc_event_t *event) {
+ isc_result_t result;
+ dns_zone_t *zone;
+ dns_db_t *rawdb, *db = NULL;
+ dns_dbnode_t *rawnode = NULL, *node = NULL;
+ dns_fixedname_t fname;
+ dns_name_t *name;
+ dns_dbiterator_t *dbiterator = NULL;
+ dns_rdatasetiter_t *rdsit = NULL;
+ dns_rdataset_t rdataset;
+ dns_dbversion_t *version = NULL;
+ isc_time_t loadtime;
+
+ UNUSED(task);
+
+ zone = event->ev_arg;
+ rawdb = ((struct secure_db *)event)->db;
+ dns_fixedname_init(&fname);
+ name = dns_fixedname_name(&fname);
+ dns_rdataset_init(&rdataset);
+
+ TIME_NOW(&loadtime);
+
+ result = dns_db_create(zone->mctx, zone->db_argv[0],
+ &zone->origin, dns_dbtype_zone, zone->rdclass,
+ zone->db_argc - 1, zone->db_argv + 1, &db);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_db_newversion(db, &version);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_db_createiterator(rawdb, 0, &dbiterator);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ for (result = dns_dbiterator_first(dbiterator);
+ result == ISC_R_SUCCESS;
+ result = dns_dbiterator_next(dbiterator)) {
+ result = dns_dbiterator_current(dbiterator, &rawnode, name);
+ if (result != ISC_R_SUCCESS)
+ continue;
+
+ result = dns_db_findnode(db, name, ISC_TRUE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_db_allrdatasets(rawdb, rawnode, NULL, 0, &rdsit);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ for (result = dns_rdatasetiter_first(rdsit);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(rdsit)) {
+ dns_rdatasetiter_current(rdsit, &rdataset);
+ if (rdataset.type == dns_rdatatype_nsec ||
+ rdataset.type == dns_rdatatype_rrsig ||
+ rdataset.type == dns_rdatatype_nsec3 ||
+ rdataset.type == dns_rdatatype_dnskey ||
+ rdataset.type == dns_rdatatype_nsec3param) {
+ dns_rdataset_disassociate(&rdataset);
+ continue;
+ }
+
+ result = dns_db_addrdataset(db, node, version, 0,
+ &rdataset, 0, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ dns_rdataset_disassociate(&rdataset);
+ }
+ dns_rdatasetiter_destroy(&rdsit);
+ dns_db_detachnode(rawdb, &rawnode);
+ dns_db_detachnode(db, &node);
+ }
+
+ dns_db_closeversion(db, &version, ISC_TRUE);
+ LOCK_ZONE(zone);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+ result = zone_postload(zone, db, loadtime, ISC_R_SUCCESS);
+ zone_needdump(zone, 0); /* XXXMPA */
+ UNLOCK_ZONE(zone);
+
+ failure:
+ if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_ERROR, "receive_secure_db: %s",
+ dns_result_totext(result));
+
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (db != NULL) {
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ dns_db_detach(&db);
+ }
+ if (rawnode != NULL)
+ dns_db_detachnode(rawdb, &rawnode);
+ dns_db_detach(&rawdb);
+ if (dbiterator != NULL)
+ dns_dbiterator_destroy(&dbiterator);
+ isc_event_free(&event);
+}
+
+static isc_result_t
+zone_send_securedb(dns_zone_t *zone, dns_db_t *db) {
+ isc_event_t *e;
+ dns_db_t *dummy = NULL;
+
+ e = isc_event_allocate(zone->secure->mctx, zone,
+ DNS_EVENT_ZONESECUREDB,
+ receive_secure_db, zone->secure,
+ sizeof(struct secure_db));
+ if (e == NULL)
+ return (ISC_R_NOMEMORY);
+ dns_db_attach(db, &dummy);
+ ((struct secure_db *)e)->db = dummy;
+
+ isc_task_send(zone->secure->task, &e);
+ return (ISC_R_SUCCESS);
+}
+
isc_result_t
dns_zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
isc_result_t result;
@@ -11831,6 +12363,10 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
break;
}
}
+#if 0
+ if (zone->secure != NULL)
+ zone_send_secureserial(zone, serial);
+#endif
} else {
if (dump && zone->masterfile != NULL) {
/*
@@ -11881,6 +12417,8 @@ zone_replacedb(dns_zone_t *zone, dns_db_t *db, isc_boolean_t dump) {
zone->journal, strbuf);
}
}
+ if (zone->secure != NULL)
+ zone_send_securedb(zone, db);
}
dns_db_closeversion(db, &ver, ISC_FALSE);
@@ -12032,6 +12570,8 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
dns_zone_log(zone, ISC_LOG_INFO,
"transferred serial %u%s",
serial, buf);
+ if (zone->secure != NULL)
+ zone_send_secureserial(zone, serial);
}
/*
@@ -12289,7 +12829,7 @@ queue_xfrin(dns_zone_t *zone) {
*/
static void
got_transfer_quota(isc_task_t *task, isc_event_t *event) {
- isc_result_t result;
+ isc_result_t result = ISC_R_SUCCESS;
dns_peer_t *peer = NULL;
char master[ISC_SOCKADDR_FORMATSIZE];
char source[ISC_SOCKADDR_FORMATSIZE];
@@ -12337,14 +12877,6 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
"no database exists yet, requesting AXFR of "
"initial version from %s", master);
xfrtype = dns_rdatatype_axfr;
- } else if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_IXFRFROMDIFFS)) {
- dns_zone_log(zone, ISC_LOG_DEBUG(1), "ixfr-from-differences "
- "set, requesting %sAXFR from %s", soa_before,
- master);
- if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_SOABEFOREAXFR))
- xfrtype = dns_rdatatype_soa;
- else
- xfrtype = dns_rdatatype_axfr;
} else if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_FORCEXFER)) {
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"forced reload, requesting AXFR of "
@@ -12360,13 +12892,10 @@ got_transfer_quota(isc_task_t *task, isc_event_t *event) {
UNLOCK_ZONE(zone);
} else {
isc_boolean_t use_ixfr = ISC_TRUE;
- if (peer != NULL &&
- dns_peer_getrequestixfr(peer, &use_ixfr) ==
- ISC_R_SUCCESS) {
- ; /* Using peer setting */
- } else {
- use_ixfr = zone->view->requestixfr;
- }
+ if (peer != NULL)
+ result = dns_peer_getrequestixfr(peer, &use_ixfr);
+ if (peer == NULL || result != ISC_R_SUCCESS)
+ use_ixfr = zone->requestixfr;
if (use_ixfr == ISC_FALSE) {
dns_zone_log(zone, ISC_LOG_DEBUG(1),
"IXFR disabled, requesting %sAXFR from %s",
@@ -12454,8 +12983,13 @@ forward_destroy(dns_forward_t *forward) {
dns_request_destroy(&forward->request);
if (forward->msgbuf != NULL)
isc_buffer_free(&forward->msgbuf);
- if (forward->zone != NULL)
+ if (forward->zone != NULL) {
+ LOCK(&forward->zone->lock);
+ if (ISC_LINK_LINKED(forward, link))
+ ISC_LIST_UNLINK(forward->zone->forwards, forward, link);
+ UNLOCK(&forward->zone->lock);
dns_zone_idetach(&forward->zone);
+ }
isc_mem_putanddetach(&forward->mctx, forward, sizeof(*forward));
}
@@ -12465,6 +12999,12 @@ sendtomaster(dns_forward_t *forward) {
isc_sockaddr_t src;
LOCK_ZONE(forward->zone);
+
+ if (DNS_ZONE_FLAG(forward->zone, DNS_ZONEFLG_EXITING)) {
+ UNLOCK_ZONE(forward->zone);
+ return (ISC_R_CANCELED);
+ }
+
if (forward->which >= forward->zone->masterscnt) {
UNLOCK_ZONE(forward->zone);
return (ISC_R_NOMORE);
@@ -12495,6 +13035,11 @@ sendtomaster(dns_forward_t *forward) {
forward->zone->task,
forward_callback, forward,
&forward->request);
+ if (result == ISC_R_SUCCESS) {
+ if (!ISC_LINK_LINKED(forward, link))
+ ISC_LIST_APPEND(forward->zone->forwards, forward, link);
+ }
+
unlock:
UNLOCK_ZONE(forward->zone);
return (result);
@@ -12621,6 +13166,7 @@ dns_zone_forwardupdate(dns_zone_t *zone, dns_message_t *msg,
forward->mctx = 0;
forward->callback = callback;
forward->callback_arg = callback_arg;
+ ISC_LINK_INIT(forward, link);
forward->magic = FORWARD_MAGIC;
mr = dns_message_getrawmessage(msg);
@@ -12694,6 +13240,7 @@ dns_zonemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
zmgr->timermgr = timermgr;
zmgr->socketmgr = socketmgr;
zmgr->zonetasks = NULL;
+ zmgr->loadtasks = NULL;
zmgr->task = NULL;
zmgr->rl = NULL;
ISC_LIST_INIT(zmgr->zones);
@@ -12769,6 +13316,7 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
REQUIRE(zone->zmgr == NULL);
isc_taskpool_gettask(zmgr->zonetasks, &zone->task);
+ isc_taskpool_gettask(zmgr->loadtasks, &zone->loadtask);
/*
* Set the task name. The tag will arbitrarily point to one
@@ -12776,6 +13324,7 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
* to be managed last).
*/
isc_task_setname(zone->task, "zone", zone);
+ isc_task_setname(zone->loadtask, "loadzone", zone);
result = isc_timer_create(zmgr->timermgr, isc_timertype_inactive,
NULL, NULL,
@@ -12783,7 +13332,7 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
&zone->timer);
if (result != ISC_R_SUCCESS)
- goto cleanup_task;
+ goto cleanup_tasks;
/*
* The timer "holds" a iref.
@@ -12797,7 +13346,8 @@ dns_zonemgr_managezone(dns_zonemgr_t *zmgr, dns_zone_t *zone) {
goto unlock;
- cleanup_task:
+ cleanup_tasks:
+ isc_task_detach(&zone->loadtask);
isc_task_detach(&zone->task);
unlock:
@@ -12903,6 +13453,8 @@ dns_zonemgr_resumexfrs(dns_zonemgr_t *zmgr) {
void
dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
+ dns_zone_t *zone;
+
REQUIRE(DNS_ZONEMGR_VALID(zmgr));
isc_ratelimiter_shutdown(zmgr->rl);
@@ -12911,6 +13463,20 @@ dns_zonemgr_shutdown(dns_zonemgr_t *zmgr) {
isc_task_destroy(&zmgr->task);
if (zmgr->zonetasks != NULL)
isc_taskpool_destroy(&zmgr->zonetasks);
+ if (zmgr->loadtasks != NULL)
+ isc_taskpool_destroy(&zmgr->loadtasks);
+
+ RWLOCK(&zmgr->rwlock, isc_rwlocktype_read);
+ for (zone = ISC_LIST_HEAD(zmgr->zones);
+ zone != NULL;
+ zone = ISC_LIST_NEXT(zone, link))
+ {
+ LOCK_ZONE(zone);
+ forward_cancel(zone);
+ UNLOCK_ZONE(zone);
+ }
+ RWUNLOCK(&zmgr->rwlock, isc_rwlocktype_read);
+
}
isc_result_t
@@ -12923,13 +13489,13 @@ dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) {
/*
* For anything fewer than 1000 zones we use 10 tasks in
- * the task pool. More than that, and we'll scale at one
+ * the task pools. More than that, and we'll scale at one
* task per 100 zones.
*/
if (ntasks < 10)
ntasks = 10;
- /* Create or resize the zone task pool. */
+ /* Create or resize the zone task pools. */
if (zmgr->zonetasks == NULL)
result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx,
ntasks, 2, &pool);
@@ -12939,6 +13505,33 @@ dns_zonemgr_setsize(dns_zonemgr_t *zmgr, int num_zones) {
if (result == ISC_R_SUCCESS)
zmgr->zonetasks = pool;
+ pool = NULL;
+ if (zmgr->loadtasks == NULL)
+ result = isc_taskpool_create(zmgr->taskmgr, zmgr->mctx,
+ ntasks, 2, &pool);
+ else
+ result = isc_taskpool_expand(&zmgr->loadtasks, ntasks, &pool);
+
+ if (result == ISC_R_SUCCESS)
+ zmgr->loadtasks = pool;
+
+#ifdef BIND9
+ /*
+ * We always set all tasks in the zone-load task pool to
+ * privileged. This prevents other tasks in the system from
+ * running while the server task manager is in privileged
+ * mode.
+ *
+ * NOTE: If we start using task privileges for any other
+ * part of the system than zone tasks, then this will need to be
+ * revisted. In that case we'd want to turn on privileges for
+ * zone tasks only when we were loading, and turn them off the
+ * rest of the time. For now, however, it's okay to just
+ * set it and forget it.
+ */
+ isc_taskpool_setprivilege(zmgr->loadtasks, ISC_TRUE);
+#endif
+
return (result);
}
@@ -13161,12 +13754,14 @@ zonemgr_getio(dns_zonemgr_t *zmgr, isc_boolean_t high,
io = isc_mem_get(zmgr->mctx, sizeof(*io));
if (io == NULL)
return (ISC_R_NOMEMORY);
+
io->event = isc_event_allocate(zmgr->mctx, task, DNS_EVENT_IOREADY,
action, arg, sizeof(*io->event));
if (io->event == NULL) {
isc_mem_put(zmgr->mctx, io, sizeof(*io));
return (ISC_R_NOMEMORY);
}
+
io->zmgr = zmgr;
io->high = high;
io->task = NULL;
@@ -13186,9 +13781,8 @@ zonemgr_getio(dns_zonemgr_t *zmgr, isc_boolean_t high,
UNLOCK(&zmgr->iolock);
*iop = io;
- if (!queue) {
+ if (!queue)
isc_task_send(io->task, &io->event);
- }
return (ISC_R_SUCCESS);
}
@@ -14364,7 +14958,8 @@ zone_rekey(dns_zone_t *zone) {
zone->updatemethod));
CHECK(add_chains(zone, db, ver, &diff));
CHECK(sign_apex(zone, db, ver, &diff, &sig_diff));
- CHECK(zone_journal(zone, &sig_diff, "zone_rekey"));
+ CHECK(zone_journal(zone, &sig_diff, NULL,
+ "zone_rekey"));
commit = ISC_TRUE;
}
}
@@ -14654,6 +15249,18 @@ dns_zone_setrefreshkeyinterval(dns_zone_t *zone, isc_uint32_t interval) {
}
void
+dns_zone_setrequestixfr(dns_zone_t *zone, isc_boolean_t bool) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ zone->requestixfr = bool;
+}
+
+isc_boolean_t
+dns_zone_getrequestixfr(dns_zone_t *zone) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ return (zone->requestixfr);
+}
+
+void
dns_zone_setserialupdatemethod(dns_zone_t *zone, dns_updatemethod_t method) {
REQUIRE(DNS_ZONE_VALID(zone));
zone->updatemethod = method;
@@ -14664,3 +15271,32 @@ dns_zone_getserialupdatemethod(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
return(zone->updatemethod);
}
+
+void
+dns_zone_link(dns_zone_t *zone, dns_zone_t *raw) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(DNS_ZONE_VALID(raw));
+
+ LOCK(&zone->lock);
+ if (zone->raw != NULL)
+ dns_zone_detach(&zone->raw);
+ dns_zone_attach(raw, &zone->raw);
+ UNLOCK(&zone->lock);
+
+ LOCK(&raw->lock);
+ if (raw->secure != NULL)
+ dns_zone_idetach(&raw->secure);
+ dns_zone_iattach(zone, &raw->secure);
+ UNLOCK(&raw->lock);
+}
+
+void
+dns_zone_getraw(dns_zone_t *zone, dns_zone_t **raw) {
+ REQUIRE(DNS_ZONE_VALID(zone));
+ REQUIRE(raw != NULL && *raw == NULL);
+
+ LOCK(&zone->lock);
+ if (zone->raw != NULL)
+ dns_zone_attach(zone->raw, raw);
+ UNLOCK(&zone->lock);
+}
diff --git a/lib/dns/zt.c b/lib/dns/zt.c
index 49f6c487..0995377a 100644
--- a/lib/dns/zt.c
+++ b/lib/dns/zt.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zt.c,v 1.50 2011-03-21 23:47:21 tbox Exp $ */
+/* $Id: zt.c,v 1.56 2011-09-07 00:50:06 marka Exp $ */
/*! \file */
@@ -25,6 +25,7 @@
#include <isc/magic.h>
#include <isc/mem.h>
#include <isc/string.h>
+#include <isc/task.h>
#include <isc/util.h>
#include <dns/log.h>
@@ -42,8 +43,11 @@ struct dns_zt {
isc_mem_t *mctx;
dns_rdataclass_t rdclass;
isc_rwlock_t rwlock;
+ dns_zt_allloaded_t loaddone;
+ void * loaddone_arg;
/* Locked by lock. */
isc_uint32_t references;
+ unsigned int loads_pending;
dns_rbt_t *table;
};
@@ -57,11 +61,17 @@ static isc_result_t
load(dns_zone_t *zone, void *uap);
static isc_result_t
+asyncload(dns_zone_t *zone, void *callback);
+
+static isc_result_t
loadnew(dns_zone_t *zone, void *uap);
static isc_result_t
freezezones(dns_zone_t *zone, void *uap);
+static isc_result_t
+doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task);
+
isc_result_t
dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp)
{
@@ -87,6 +97,9 @@ dns_zt_create(isc_mem_t *mctx, dns_rdataclass_t rdclass, dns_zt_t **ztp)
zt->references = 1;
zt->rdclass = rdclass;
zt->magic = ZTMAGIC;
+ zt->loaddone = NULL;
+ zt->loaddone_arg = NULL;
+ zt->loads_pending = 0;
*ztp = zt;
return (ISC_R_SUCCESS);
@@ -243,13 +256,63 @@ static isc_result_t
load(dns_zone_t *zone, void *uap) {
isc_result_t result;
UNUSED(uap);
+
result = dns_zone_load(zone);
if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE)
result = ISC_R_SUCCESS;
+
return (result);
}
isc_result_t
+dns_zt_asyncload(dns_zt_t *zt, dns_zt_allloaded_t alldone, void *arg) {
+ isc_result_t result, tresult;
+ static dns_zt_zoneloaded_t dl = doneloading;
+ int pending;
+
+ REQUIRE(VALID_ZT(zt));
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_read);
+
+ INSIST(zt->loads_pending == 0);
+
+ result = dns_zt_apply2(zt, ISC_FALSE, &tresult, asyncload, &dl);
+
+ pending = zt->loads_pending;
+ if (pending != 0) {
+ zt->loaddone = alldone;
+ zt->loaddone_arg = arg;
+ }
+
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
+
+ if (pending == 0)
+ alldone(arg);
+
+ return (result);
+}
+
+/*
+ * Initiates asynchronous loading of zone 'zone'. 'callback' is a
+ * pointer to a function which will be used to inform the caller when
+ * the zone loading is complete.
+ */
+static isc_result_t
+asyncload(dns_zone_t *zone, void *callback) {
+ isc_result_t result;
+ dns_zt_zoneloaded_t *loaded = callback;
+ dns_zt_t *zt;
+
+ REQUIRE(zone != NULL);
+ zt = dns_zone_getview(zone)->zonetable;
+
+ result = dns_zone_asyncload(zone, *loaded, zt);
+ if (result == ISC_R_SUCCESS)
+ zt->loads_pending++;
+ return (ISC_R_SUCCESS);
+}
+
+isc_result_t
dns_zt_loadnew(dns_zt_t *zt, isc_boolean_t stop) {
isc_result_t result;
@@ -265,6 +328,7 @@ static isc_result_t
loadnew(dns_zone_t *zone, void *uap) {
isc_result_t result;
UNUSED(uap);
+
result = dns_zone_loadnew(zone);
if (result == DNS_R_CONTINUE || result == DNS_R_UPTODATE ||
result == DNS_R_DYNAMIC)
@@ -281,6 +345,8 @@ dns_zt_freezezones(dns_zt_t *zt, isc_boolean_t freeze) {
RWLOCK(&zt->rwlock, isc_rwlocktype_read);
result = dns_zt_apply2(zt, ISC_FALSE, &tresult, freezezones, &freeze);
RWUNLOCK(&zt->rwlock, isc_rwlocktype_read);
+ if (tresult == ISC_R_NOTFOUND)
+ tresult = ISC_R_SUCCESS;
return ((result == ISC_R_SUCCESS) ? tresult : result);
}
@@ -364,6 +430,7 @@ dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub,
/*
* The tree is empty.
*/
+ tresult = result;
result = ISC_R_NOMORE;
}
while (result == DNS_R_NEWORIGIN || result == ISC_R_SUCCESS) {
@@ -393,6 +460,38 @@ dns_zt_apply2(dns_zt_t *zt, isc_boolean_t stop, isc_result_t *sub,
return (result);
}
+/*
+ * Decrement the loads_pending counter; when counter reaches
+ * zero, call the loaddone callback that was initially set by
+ * dns_zt_asyncload().
+ */
+static isc_result_t
+doneloading(dns_zt_t *zt, dns_zone_t *zone, isc_task_t *task) {
+ dns_zt_allloaded_t alldone = NULL;
+ void *arg = NULL;
+
+ UNUSED(zone);
+ UNUSED(task);
+
+ REQUIRE(VALID_ZT(zt));
+
+ RWLOCK(&zt->rwlock, isc_rwlocktype_write);
+ INSIST(zt->loads_pending != 0);
+ zt->loads_pending--;
+ if (zt->loads_pending == 0) {
+ alldone = zt->loaddone;
+ arg = zt->loaddone_arg;
+ zt->loaddone = NULL;
+ zt->loaddone_arg = NULL;
+ }
+ RWUNLOCK(&zt->rwlock, isc_rwlocktype_write);
+
+ if (alldone != NULL)
+ alldone(arg);
+
+ return (ISC_R_SUCCESS);
+}
+
/***
*** Private
***/
diff --git a/lib/isc/include/isc/list.h b/lib/isc/include/isc/list.h
index 69ba1c63..64dcc599 100644
--- a/lib/isc/include/isc/list.h
+++ b/lib/isc/include/isc/list.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2006, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2006, 2007, 2011 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1997-2002 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: list.h,v 1.24 2007-06-19 23:47:18 tbox Exp $ */
+/* $Id: list.h,v 1.26 2011-09-02 23:46:33 tbox Exp $ */
#ifndef ISC_LIST_H
#define ISC_LIST_H 1
@@ -169,6 +169,19 @@
(list2).tail = NULL; \
} while (0)
+#define ISC_LIST_PREPENDLIST(list1, list2, link) \
+ do { \
+ if (ISC_LIST_EMPTY(list1)) \
+ (list1) = (list2); \
+ else if (!ISC_LIST_EMPTY(list2)) { \
+ (list2).tail->link.next = (list1).head; \
+ (list1).head->link.prev = (list2).tail; \
+ (list1).head = (list2).head; \
+ } \
+ (list2).head = NULL; \
+ (list2).tail = NULL; \
+ } while (0)
+
#define ISC_LIST_ENQUEUE(list, elt, link) ISC_LIST_APPEND(list, elt, link)
#define __ISC_LIST_ENQUEUEUNSAFE(list, elt, link) \
__ISC_LIST_APPENDUNSAFE(list, elt, link)
diff --git a/lib/isc/include/isc/namespace.h b/lib/isc/include/isc/namespace.h
index 11f25285..6822443b 100644
--- a/lib/isc/include/isc/namespace.h
+++ b/lib/isc/include/isc/namespace.h
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: namespace.h,v 1.12 2011-08-23 17:02:53 each Exp $ */
+/* $Id: namespace.h,v 1.13 2011-09-02 21:15:38 each Exp $ */
#ifndef ISCAPI_NAMESPACE_H
#define ISCAPI_NAMESPACE_H 1
@@ -31,6 +31,7 @@
#define isc_app_run isc__app_run
#define isc_app_ctxrun isc__app_ctxrun
#define isc_app_shutdown isc__app_shutdown
+#define isc_app_ctxfinish isc__app_ctxfinish
#define isc_app_ctxshutdown isc__app_ctxshutdown
#define isc_app_ctxsuspend isc__app_ctxsuspend
#define isc_app_reload isc__app_reload
@@ -147,9 +148,13 @@
#define isc_task_gettag isc__task_gettag
#define isc_task_getcurrenttime isc__task_getcurrenttime
#define isc_taskmgr_create isc__taskmgr_create
+#define isc_taskmgr_setmode isc__taskmgr_setmode
+#define isc_taskmgr_mode isc__taskmgr_mode
#define isc_taskmgr_destroy isc__taskmgr_destroy
#define isc_task_beginexclusive isc__task_beginexclusive
#define isc_task_endexclusive isc__task_endexclusive
+#define isc_task_setprivilege isc__task_setprivilege
+#define isc_task_privilege isc__task_privilege
#define isc_timer_create isc__timer_create
#define isc_timer_reset isc__timer_reset
diff --git a/lib/isc/include/isc/task.h b/lib/isc/include/isc/task.h
index 64e531c0..c5ac5bf3 100644
--- a/lib/isc/include/isc/task.h
+++ b/lib/isc/include/isc/task.h
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: task.h,v 1.71 2011-02-03 12:18:12 tbox Exp $ */
+/* $Id: task.h,v 1.73 2011-09-02 23:46:33 tbox Exp $ */
#ifndef ISC_TASK_H
#define ISC_TASK_H 1
@@ -88,6 +88,7 @@
#define ISC_TASKEVENT_FIRSTEVENT (ISC_EVENTCLASS_TASK + 0)
#define ISC_TASKEVENT_SHUTDOWN (ISC_EVENTCLASS_TASK + 1)
+#define ISC_TASKEVENT_TEST (ISC_EVENTCLASS_TASK + 1)
#define ISC_TASKEVENT_LASTEVENT (ISC_EVENTCLASS_TASK + 65535)
/*****
@@ -100,9 +101,17 @@ ISC_LANG_BEGINDECLS
*** Types
***/
+typedef enum {
+ isc_taskmgrmode_normal = 0,
+ isc_taskmgrmode_privileged
+} isc_taskmgrmode_t;
+
/*% Task and task manager methods */
typedef struct isc_taskmgrmethods {
void (*destroy)(isc_taskmgr_t **managerp);
+ void (*setmode)(isc_taskmgr_t *manager,
+ isc_taskmgrmode_t mode);
+ isc_taskmgrmode_t (*mode)(isc_taskmgr_t *manager);
isc_result_t (*taskcreate)(isc_taskmgr_t *manager,
unsigned int quantum,
isc_task_t **taskp);
@@ -127,6 +136,8 @@ typedef struct isc_taskmethods {
void *tag);
isc_result_t (*beginexclusive)(isc_task_t *task);
void (*endexclusive)(isc_task_t *task);
+ void (*setprivilege)(isc_task_t *task, isc_boolean_t priv);
+ isc_boolean_t (*privilege)(isc_task_t *task);
} isc_taskmethods_t;
/*%
@@ -611,6 +622,32 @@ isc_task_exiting(isc_task_t *t);
*\li 'task' is a valid task.
*/
+void
+isc_task_setprivilege(isc_task_t *task, isc_boolean_t priv);
+/*%<
+ * Set or unset the task's "privileged" flag depending on the value of
+ * 'priv'.
+ *
+ * Under normal circumstances this flag has no effect on the task behavior,
+ * but when the task manager has been set to privileged exeuction mode via
+ * isc_taskmgr_setmode(), only tasks with the flag set will be executed,
+ * and all other tasks will wait until they're done. Once all privileged
+ * tasks have finished executing, the task manager will automatically
+ * return to normal execution mode and nonprivileged task can resume.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
+isc_boolean_t
+isc_task_privilege(isc_task_t *task);
+/*%<
+ * Returns the current value of the task's privilege flag.
+ *
+ * Requires:
+ *\li 'task' is a valid task.
+ */
+
/*****
***** Task Manager.
*****/
@@ -664,6 +701,31 @@ isc_taskmgr_create(isc_mem_t *mctx, unsigned int workers,
*/
void
+isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode);
+
+isc_taskmgrmode_t
+isc_taskmgr_mode(isc_taskmgr_t *manager);
+/*%<
+ * Set/get the current operating mode of the task manager. Valid modes are:
+ *
+ *\li isc_taskmgrmode_normal
+ *\li isc_taskmgrmode_privileged
+ *
+ * In privileged execution mode, only tasks that have had the "privilege"
+ * flag set via isc_task_setprivilege() can be executed. When all such
+ * tasks are complete, the manager automatically returns to normal mode
+ * and proceeds with running non-privileged ready tasks. This means it is
+ * necessary to have at least one privileged task waiting on the ready
+ * queue *before* setting the manager into privileged execution mode,
+ * which in turn means the task which calls this function should be in
+ * task-exclusive mode when it does so.
+ *
+ * Requires:
+ *
+ *\li 'manager' is a valid task manager.
+ */
+
+void
isc_taskmgr_destroy(isc_taskmgr_t **managerp);
/*%<
* Destroy '*managerp'.
diff --git a/lib/isc/include/isc/taskpool.h b/lib/isc/include/isc/taskpool.h
index ec3ebbcb..fcdddc53 100644
--- a/lib/isc/include/isc/taskpool.h
+++ b/lib/isc/include/isc/taskpool.h
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: taskpool.h,v 1.17 2011-07-07 23:47:50 tbox Exp $ */
+/* $Id: taskpool.h,v 1.18 2011-09-02 21:15:38 each Exp $ */
#ifndef ISC_TASKPOOL_H
#define ISC_TASKPOOL_H 1
@@ -139,6 +139,19 @@ isc_taskpool_destroy(isc_taskpool_t **poolp);
* \li '*poolp' is a valid task pool.
*/
+void
+isc_taskpool_setprivilege(isc_taskpool_t *pool, isc_boolean_t priv);
+/*%<
+ * Set the privilege flag on all tasks in 'pool' to 'priv'. If 'priv' is
+ * true, then when the task manager is set into privileged mode, only
+ * tasks wihin this pool will be able to execute. (Note: It is important
+ * to turn the pool tasks' privilege back off before the last task finishes
+ * executing.)
+ *
+ * Requires:
+ * \li 'pool' is a valid task pool.
+ */
+
ISC_LANG_ENDDECLS
#endif /* ISC_TASKPOOL_H */
diff --git a/lib/isc/include/isc/util.h b/lib/isc/include/isc/util.h
index 8bb334ed..e7ef3dfa 100644
--- a/lib/isc/include/isc/util.h
+++ b/lib/isc/include/isc/util.h
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: util.h,v 1.34 2011-03-12 04:59:49 tbox Exp $ */
+/* $Id: util.h,v 1.35 2011-09-05 18:00:22 each Exp $ */
#ifndef ISC_UTIL_H
#define ISC_UTIL_H 1
@@ -235,14 +235,4 @@
*/
#define TIME_NOW(tp) RUNTIME_CHECK(isc_time_now((tp)) == ISC_R_SUCCESS)
-/*%
- * Prevent Linux spurious warnings
- */
-#if defined(__GNUC__) && (__GNUC__ > 3)
-#define isc_util_fwrite(a, b, c, d) \
- __builtin_expect(fwrite((a), (b), (c), (d)), (c))
-#else
-#define isc_util_fwrite(a, b, c, d) fwrite((a), (b), (c), (d))
-#endif
-
#endif /* ISC_UTIL_H */
diff --git a/lib/isc/task.c b/lib/isc/task.c
index ffe57afb..dedaf09d 100644
--- a/lib/isc/task.c
+++ b/lib/isc/task.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: task.c,v 1.117 2011-02-03 12:18:12 tbox Exp $ */
+/* $Id: task.c,v 1.122 2011-09-03 16:27:51 each Exp $ */
/*! \file
* \author Principal Author: Bob Halley
@@ -64,9 +64,7 @@
#endif /* ISC_PLATFORM_USETHREADS */
#endif /* BIND9 */
-#ifndef USE_WORKER_THREADS
#include "task_p.h"
-#endif /* USE_WORKER_THREADS */
#ifdef ISC_TASK_TRACE
#define XTRACE(m) fprintf(stderr, "task %p thread %lu: %s\n", \
@@ -120,9 +118,11 @@ struct isc__task {
/* Locked by task manager lock. */
LINK(isc__task_t) link;
LINK(isc__task_t) ready_link;
+ LINK(isc__task_t) ready_priority_link;
};
#define TASK_F_SHUTTINGDOWN 0x01
+#define TASK_F_PRIVILEGED 0x02
#define TASK_SHUTTINGDOWN(t) (((t)->flags & TASK_F_SHUTTINGDOWN) \
!= 0)
@@ -145,11 +145,15 @@ struct isc__taskmgr {
unsigned int default_quantum;
LIST(isc__task_t) tasks;
isc__tasklist_t ready_tasks;
+ isc__tasklist_t ready_priority_tasks;
+ isc_taskmgrmode_t mode;
#ifdef ISC_PLATFORM_USETHREADS
isc_condition_t work_available;
isc_condition_t exclusive_granted;
+ isc_condition_t paused;
#endif /* ISC_PLATFORM_USETHREADS */
unsigned int tasks_running;
+ isc_boolean_t pause_requested;
isc_boolean_t exclusive_requested;
isc_boolean_t exiting;
#ifdef USE_SHARED_MANAGER
@@ -225,6 +229,23 @@ ISC_TASKFUNC_SCOPE isc_result_t
isc__task_beginexclusive(isc_task_t *task);
ISC_TASKFUNC_SCOPE void
isc__task_endexclusive(isc_task_t *task0);
+ISC_TASKFUNC_SCOPE void
+isc__task_setprivilege(isc_task_t *task0, isc_boolean_t priv);
+ISC_TASKFUNC_SCOPE isc_boolean_t
+isc__task_privilege(isc_task_t *task0);
+ISC_TASKFUNC_SCOPE void
+isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode);
+ISC_TASKFUNC_SCOPE isc_taskmgrmode_t
+isc__taskmgr_mode(isc_taskmgr_t *manager0);
+
+static inline isc_boolean_t
+empty_readyq(isc__taskmgr_t *manager);
+
+static inline isc__task_t *
+pop_readyq(isc__taskmgr_t *manager);
+
+static inline void
+push_readyq(isc__taskmgr_t *manager, isc__task_t *task);
static struct isc__taskmethods {
isc_taskmethods_t methods;
@@ -249,7 +270,9 @@ static struct isc__taskmethods {
isc__task_purge,
isc__task_purgerange,
isc__task_beginexclusive,
- isc__task_endexclusive
+ isc__task_endexclusive,
+ isc__task_setprivilege,
+ isc__task_privilege
}
#ifndef BIND9
,
@@ -261,6 +284,8 @@ static struct isc__taskmethods {
static isc_taskmgrmethods_t taskmgrmethods = {
isc__taskmgr_destroy,
+ isc__taskmgr_setmode,
+ isc__taskmgr_mode,
isc__task_create
};
@@ -333,6 +358,7 @@ isc__task_create(isc_taskmgr_t *manager0, unsigned int quantum,
task->tag = NULL;
INIT_LINK(task, link);
INIT_LINK(task, ready_link);
+ INIT_LINK(task, ready_priority_link);
exiting = ISC_FALSE;
LOCK(&manager->lock);
@@ -400,6 +426,7 @@ task_shutdown(isc__task_t *task) {
}
INSIST(task->state == task_state_ready ||
task->state == task_state_running);
+
/*
* Note that we post shutdown events LIFO.
*/
@@ -415,9 +442,17 @@ task_shutdown(isc__task_t *task) {
return (was_idle);
}
+/*
+ * Moves a task onto the appropriate run queue.
+ *
+ * Caller must NOT hold manager lock.
+ */
static inline void
task_ready(isc__task_t *task) {
isc__taskmgr_t *manager = task->manager;
+#ifdef USE_WORKER_THREADS
+ isc_boolean_t has_privilege = isc__task_privilege((isc_task_t *) task);
+#endif /* USE_WORKER_THREADS */
REQUIRE(VALID_MANAGER(manager));
REQUIRE(task->state == task_state_ready);
@@ -425,12 +460,11 @@ task_ready(isc__task_t *task) {
XTRACE("task_ready");
LOCK(&manager->lock);
-
- ENQUEUE(manager->ready_tasks, task, ready_link);
+ push_readyq(manager, task);
#ifdef USE_WORKER_THREADS
- SIGNAL(&manager->work_available);
+ if (manager->mode == isc_taskmgrmode_normal || has_privilege)
+ SIGNAL(&manager->work_available);
#endif /* USE_WORKER_THREADS */
-
UNLOCK(&manager->lock);
}
@@ -868,21 +902,81 @@ isc__task_getcurrenttime(isc_task_t *task0, isc_stdtime_t *t) {
REQUIRE(t != NULL);
LOCK(&task->lock);
-
*t = task->now;
-
UNLOCK(&task->lock);
}
/***
*** Task Manager.
***/
+
+/*
+ * Return ISC_TRUE if the current ready list for the manager, which is
+ * either ready_tasks or the ready_priority_tasks, depending on whether
+ * the manager is currently in normal or privileged execution mode.
+ *
+ * Caller must hold the task manager lock.
+ */
+static inline isc_boolean_t
+empty_readyq(isc__taskmgr_t *manager) {
+ isc__tasklist_t queue;
+
+ if (manager->mode == isc_taskmgrmode_normal)
+ queue = manager->ready_tasks;
+ else
+ queue = manager->ready_priority_tasks;
+
+ return (ISC_TF(EMPTY(queue)));
+}
+
+/*
+ * Dequeue and return a pointer to the first task on the current ready
+ * list for the manager.
+ * If the task is privileged, dequeue it from the other ready list
+ * as well.
+ *
+ * Caller must hold the task manager lock.
+ */
+static inline isc__task_t *
+pop_readyq(isc__taskmgr_t *manager) {
+ isc__task_t *task;
+
+ if (manager->mode == isc_taskmgrmode_normal)
+ task = HEAD(manager->ready_tasks);
+ else
+ task = HEAD(manager->ready_priority_tasks);
+
+ if (task != NULL) {
+ DEQUEUE(manager->ready_tasks, task, ready_link);
+ if (ISC_LINK_LINKED(task, ready_priority_link))
+ DEQUEUE(manager->ready_priority_tasks, task,
+ ready_priority_link);
+ }
+
+ return (task);
+}
+
+/*
+ * Push 'task' onto the ready_tasks queue. If 'task' has the privilege
+ * flag set, then also push it onto the ready_priority_tasks queue.
+ *
+ * Caller must hold the task manager lock.
+ */
+static inline void
+push_readyq(isc__taskmgr_t *manager, isc__task_t *task) {
+ ENQUEUE(manager->ready_tasks, task, ready_link);
+ if ((task->flags & TASK_F_PRIVILEGED) != 0)
+ ENQUEUE(manager->ready_priority_tasks, task,
+ ready_priority_link);
+}
+
static void
dispatch(isc__taskmgr_t *manager) {
isc__task_t *task;
#ifndef USE_WORKER_THREADS
unsigned int total_dispatch_count = 0;
- isc__tasklist_t ready_tasks;
+ isc__tasklist_t new_ready_tasks;
+ isc__tasklist_t new_priority_tasks;
#endif /* USE_WORKER_THREADS */
REQUIRE(VALID_MANAGER(manager));
@@ -938,9 +1032,11 @@ dispatch(isc__taskmgr_t *manager) {
*/
#ifndef USE_WORKER_THREADS
- ISC_LIST_INIT(ready_tasks);
+ ISC_LIST_INIT(new_ready_tasks);
+ ISC_LIST_INIT(new_priority_tasks);
#endif
LOCK(&manager->lock);
+
while (!FINISHED(manager)) {
#ifdef USE_WORKER_THREADS
/*
@@ -949,10 +1045,12 @@ dispatch(isc__taskmgr_t *manager) {
* the task while only holding the manager lock, and then
* change the task to running state while only holding the
* task lock.
+ *
+ * If a pause has been requested, don't do any work
+ * until it's been released.
*/
- while ((EMPTY(manager->ready_tasks) ||
- manager->exclusive_requested) &&
- !FINISHED(manager))
+ while ((empty_readyq(manager) || manager->pause_requested ||
+ manager->exclusive_requested) && !FINISHED(manager))
{
XTHREADTRACE(isc_msgcat_get(isc_msgcat,
ISC_MSGSET_GENERAL,
@@ -964,13 +1062,13 @@ dispatch(isc__taskmgr_t *manager) {
}
#else /* USE_WORKER_THREADS */
if (total_dispatch_count >= DEFAULT_TASKMGR_QUANTUM ||
- EMPTY(manager->ready_tasks))
+ empty_readyq(manager))
break;
#endif /* USE_WORKER_THREADS */
XTHREADTRACE(isc_msgcat_get(isc_msgcat, ISC_MSGSET_TASK,
ISC_MSG_WORKING, "working"));
- task = HEAD(manager->ready_tasks);
+ task = pop_readyq(manager);
if (task != NULL) {
unsigned int dispatch_count = 0;
isc_boolean_t done = ISC_FALSE;
@@ -985,7 +1083,6 @@ dispatch(isc__taskmgr_t *manager) {
* have a task to do. We must reacquire the manager
* lock before exiting the 'if (task != NULL)' block.
*/
- DEQUEUE(manager->ready_tasks, task, ready_link);
manager->tasks_running++;
UNLOCK(&manager->lock);
@@ -1106,6 +1203,9 @@ dispatch(isc__taskmgr_t *manager) {
if (manager->exclusive_requested &&
manager->tasks_running == 1) {
SIGNAL(&manager->exclusive_granted);
+ } else if (manager->pause_requested &&
+ manager->tasks_running == 0) {
+ SIGNAL(&manager->paused);
}
#endif /* USE_WORKER_THREADS */
if (requeue) {
@@ -1129,17 +1229,39 @@ dispatch(isc__taskmgr_t *manager) {
* might even hurt rather than help.
*/
#ifdef USE_WORKER_THREADS
- ENQUEUE(manager->ready_tasks, task,
- ready_link);
+ push_readyq(manager, task);
#else
- ENQUEUE(ready_tasks, task, ready_link);
+ ENQUEUE(new_ready_tasks, task, ready_link);
+ if ((task->flags & TASK_F_PRIVILEGED) != 0)
+ ENQUEUE(new_priority_tasks, task,
+ ready_priority_link);
#endif
}
}
+
+#ifdef USE_WORKER_THREADS
+ /*
+ * If we are in privileged execution mode and there are no
+ * tasks remaining on the current ready queue, then
+ * we're stuck. Automatically drop privileges at that
+ * point and continue with the regular ready queue.
+ */
+ if (manager->tasks_running == 0 && empty_readyq(manager)) {
+ manager->mode = isc_taskmgrmode_normal;
+ if (!empty_readyq(manager))
+ BROADCAST(&manager->work_available);
+ }
+#endif
}
+
#ifndef USE_WORKER_THREADS
- ISC_LIST_APPENDLIST(manager->ready_tasks, ready_tasks, ready_link);
+ ISC_LIST_APPENDLIST(manager->ready_tasks, new_ready_tasks, ready_link);
+ ISC_LIST_APPENDLIST(manager->ready_priority_tasks, new_priority_tasks,
+ ready_priority_link);
+ if (empty_readyq(manager))
+ manager->mode = isc_taskmgrmode_normal;
#endif
+
UNLOCK(&manager->lock);
}
@@ -1174,6 +1296,7 @@ manager_free(isc__taskmgr_t *manager) {
#ifdef USE_WORKER_THREADS
(void)isc_condition_destroy(&manager->exclusive_granted);
(void)isc_condition_destroy(&manager->work_available);
+ (void)isc_condition_destroy(&manager->paused);
isc_mem_free(manager->mctx, manager->threads);
#endif /* USE_WORKER_THREADS */
DESTROYLOCK(&manager->lock);
@@ -1224,6 +1347,7 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers,
manager->common.methods = &taskmgrmethods;
manager->common.impmagic = TASK_MANAGER_MAGIC;
manager->common.magic = ISCAPI_TASKMGR_MAGIC;
+ manager->mode = isc_taskmgrmode_normal;
manager->mctx = NULL;
result = isc_mutex_init(&manager->lock);
if (result != ISC_R_SUCCESS)
@@ -1253,14 +1377,24 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers,
result = ISC_R_UNEXPECTED;
goto cleanup_workavailable;
}
+ if (isc_condition_init(&manager->paused) != ISC_R_SUCCESS) {
+ UNEXPECTED_ERROR(__FILE__, __LINE__,
+ "isc_condition_init() %s",
+ isc_msgcat_get(isc_msgcat, ISC_MSGSET_GENERAL,
+ ISC_MSG_FAILED, "failed"));
+ result = ISC_R_UNEXPECTED;
+ goto cleanup_exclusivegranted;
+ }
#endif /* USE_WORKER_THREADS */
if (default_quantum == 0)
default_quantum = DEFAULT_DEFAULT_QUANTUM;
manager->default_quantum = default_quantum;
INIT_LIST(manager->tasks);
INIT_LIST(manager->ready_tasks);
+ INIT_LIST(manager->ready_priority_tasks);
manager->tasks_running = 0;
manager->exclusive_requested = ISC_FALSE;
+ manager->pause_requested = ISC_FALSE;
manager->exiting = ISC_FALSE;
isc_mem_attach(mctx, &manager->mctx);
@@ -1296,6 +1430,8 @@ isc__taskmgr_create(isc_mem_t *mctx, unsigned int workers,
return (ISC_R_SUCCESS);
#ifdef USE_WORKER_THREADS
+ cleanup_exclusivegranted:
+ (void)isc_condition_destroy(&manager->exclusive_granted);
cleanup_workavailable:
(void)isc_condition_destroy(&manager->work_available);
cleanup_threads:
@@ -1361,6 +1497,11 @@ isc__taskmgr_destroy(isc_taskmgr_t **managerp) {
manager->exiting = ISC_TRUE;
/*
+ * If privileged mode was on, turn it off.
+ */
+ manager->mode = isc_taskmgrmode_normal;
+
+ /*
* Post shutdown event(s) to every task (if they haven't already been
* posted).
*/
@@ -1369,7 +1510,7 @@ isc__taskmgr_destroy(isc_taskmgr_t **managerp) {
task = NEXT(task, link)) {
LOCK(&task->lock);
if (task_shutdown(task))
- ENQUEUE(manager->ready_tasks, task, ready_link);
+ push_readyq(manager, task);
UNLOCK(&task->lock);
}
#ifdef USE_WORKER_THREADS
@@ -1408,10 +1549,30 @@ isc__taskmgr_destroy(isc_taskmgr_t **managerp) {
*managerp = NULL;
}
+ISC_TASKFUNC_SCOPE void
+isc__taskmgr_setmode(isc_taskmgr_t *manager0, isc_taskmgrmode_t mode) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+
+ LOCK(&manager->lock);
+ manager->mode = mode;
+ UNLOCK(&manager->lock);
+}
+
+ISC_TASKFUNC_SCOPE isc_taskmgrmode_t
+isc__taskmgr_mode(isc_taskmgr_t *manager0) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+ isc_taskmgrmode_t mode;
+ LOCK(&manager->lock);
+ mode = manager->mode;
+ UNLOCK(&manager->lock);
+ return (mode);
+}
+
#ifndef USE_WORKER_THREADS
isc_boolean_t
isc__taskmgr_ready(isc_taskmgr_t *manager0) {
isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+ isc_boolean_t is_ready;
#ifdef USE_SHARED_MANAGER
if (manager == NULL)
@@ -1419,7 +1580,12 @@ isc__taskmgr_ready(isc_taskmgr_t *manager0) {
#endif
if (manager == NULL)
return (ISC_FALSE);
- return (ISC_TF(!ISC_LIST_EMPTY(manager->ready_tasks)));
+
+ LOCK(&manager->lock);
+ is_ready = !empty_readyq(manager);
+ UNLOCK(&manager->lock);
+
+ return (is_ready);
}
isc_result_t
@@ -1438,6 +1604,29 @@ isc__taskmgr_dispatch(isc_taskmgr_t *manager0) {
return (ISC_R_SUCCESS);
}
+#else
+ISC_TASKFUNC_SCOPE void
+isc__taskmgr_pause(isc_taskmgr_t *manager0) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+ LOCK(&manager->lock);
+ while (manager->tasks_running > 0) {
+ WAIT(&manager->paused, &manager->lock);
+ }
+ manager->pause_requested = ISC_TRUE;
+ UNLOCK(&manager->lock);
+}
+
+ISC_TASKFUNC_SCOPE void
+isc__taskmgr_resume(isc_taskmgr_t *manager0) {
+ isc__taskmgr_t *manager = (isc__taskmgr_t *)manager0;
+
+ LOCK(&manager->lock);
+ if (manager->pause_requested) {
+ manager->pause_requested = ISC_FALSE;
+ BROADCAST(&manager->work_available);
+ }
+ UNLOCK(&manager->lock);
+}
#endif /* USE_WORKER_THREADS */
ISC_TASKFUNC_SCOPE isc_result_t
@@ -1479,6 +1668,44 @@ isc__task_endexclusive(isc_task_t *task0) {
#endif
}
+ISC_TASKFUNC_SCOPE void
+isc__task_setprivilege(isc_task_t *task0, isc_boolean_t priv) {
+ isc__task_t *task = (isc__task_t *)task0;
+ isc__taskmgr_t *manager = task->manager;
+ isc_boolean_t oldpriv;
+
+ LOCK(&task->lock);
+ oldpriv = ISC_TF((task->flags & TASK_F_PRIVILEGED) != 0);
+ if (priv)
+ task->flags |= TASK_F_PRIVILEGED;
+ else
+ task->flags &= ~TASK_F_PRIVILEGED;
+ UNLOCK(&task->lock);
+
+ if (priv == oldpriv)
+ return;
+
+ LOCK(&manager->lock);
+ if (priv && ISC_LINK_LINKED(task, ready_link))
+ ENQUEUE(manager->ready_priority_tasks, task,
+ ready_priority_link);
+ else if (!priv && ISC_LINK_LINKED(task, ready_priority_link))
+ DEQUEUE(manager->ready_priority_tasks, task,
+ ready_priority_link);
+ UNLOCK(&manager->lock);
+}
+
+ISC_TASKFUNC_SCOPE isc_boolean_t
+isc__task_privilege(isc_task_t *task0) {
+ isc__task_t *task = (isc__task_t *)task0;
+ isc_boolean_t priv;
+
+ LOCK(&task->lock);
+ priv = ISC_TF((task->flags & TASK_F_PRIVILEGED) != 0);
+ UNLOCK(&task->lock);
+ return (priv);
+}
+
#ifdef USE_SOCKETIMPREGISTER
isc_result_t
isc__task_register() {
diff --git a/lib/isc/task_api.c b/lib/isc/task_api.c
index 4e03db24..c1907207 100644
--- a/lib/isc/task_api.c
+++ b/lib/isc/task_api.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2009, 2010 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2009-2011 Internet Systems Consortium, Inc. ("ISC")
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: task_api.c,v 1.7 2010-12-22 23:46:59 tbox Exp $ */
+/* $Id: task_api.c,v 1.9 2011-09-02 23:46:32 tbox Exp $ */
#include <config.h>
@@ -99,6 +99,20 @@ isc_taskmgr_destroy(isc_taskmgr_t **managerp) {
ENSURE(*managerp == NULL);
}
+void
+isc_taskmgr_setmode(isc_taskmgr_t *manager, isc_taskmgrmode_t mode) {
+ REQUIRE(ISCAPI_TASKMGR_VALID(manager));
+
+ manager->methods->setmode(manager, mode);
+}
+
+isc_taskmgrmode_t
+isc_taskmgr_mode(isc_taskmgr_t *manager) {
+ REQUIRE(ISCAPI_TASKMGR_VALID(manager));
+
+ return (manager->methods->mode(manager));
+}
+
isc_result_t
isc_task_create(isc_taskmgr_t *manager, unsigned int quantum,
isc_task_t **taskp)
@@ -201,6 +215,20 @@ isc_task_endexclusive(isc_task_t *task) {
task->methods->endexclusive(task);
}
+void
+isc_task_setprivilege(isc_task_t *task, isc_boolean_t priv) {
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ task->methods->setprivilege(task, priv);
+}
+
+isc_boolean_t
+isc_task_privilege(isc_task_t *task) {
+ REQUIRE(ISCAPI_TASK_VALID(task));
+
+ return (task->methods->privilege(task));
+}
+
/*%
* This is necessary for libisc's internal timer implementation. Other
diff --git a/lib/isc/task_p.h b/lib/isc/task_p.h
index 1bcdca65..ded69ddc 100644
--- a/lib/isc/task_p.h
+++ b/lib/isc/task_p.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007, 2009, 2011 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 2000, 2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,17 +15,25 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: task_p.h,v 1.13 2009-09-02 23:48:02 tbox Exp $ */
+/* $Id: task_p.h,v 1.15 2011-09-02 23:46:32 tbox Exp $ */
#ifndef ISC_TASK_P_H
#define ISC_TASK_P_H
/*! \file */
+#if defined(BIND9) && defined(ISC_PLATFORM_USETHREADS)
+void
+isc__taskmgr_pause(isc_taskmgr_t *taskmgr);
+
+void
+isc__taskmgr_resume(isc_taskmgr_t *taskmgr);
+#else
isc_boolean_t
isc__taskmgr_ready(isc_taskmgr_t *taskmgr);
isc_result_t
isc__taskmgr_dispatch(isc_taskmgr_t *taskmgr);
+#endif /* !BIND9 || !ISC_PLATFORM_USETHREADS */
#endif /* ISC_TASK_P_H */
diff --git a/lib/isc/taskpool.c b/lib/isc/taskpool.c
index f8991a97..69514d6d 100644
--- a/lib/isc/taskpool.c
+++ b/lib/isc/taskpool.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: taskpool.c,v 1.20 2011-07-07 23:47:49 tbox Exp $ */
+/* $Id: taskpool.c,v 1.21 2011-09-02 21:15:38 each Exp $ */
/*! \file */
@@ -163,9 +163,8 @@ isc_taskpool_destroy(isc_taskpool_t **poolp) {
unsigned int i;
isc_taskpool_t *pool = *poolp;
for (i = 0; i < pool->ntasks; i++) {
- if (pool->tasks[i] != NULL) {
+ if (pool->tasks[i] != NULL)
isc_task_detach(&pool->tasks[i]);
- }
}
isc_mem_put(pool->mctx, pool->tasks,
pool->ntasks * sizeof(isc_task_t *));
@@ -173,4 +172,14 @@ isc_taskpool_destroy(isc_taskpool_t **poolp) {
*poolp = NULL;
}
+void
+isc_taskpool_setprivilege(isc_taskpool_t *pool, isc_boolean_t priv) {
+ unsigned int i;
+
+ REQUIRE(pool != NULL);
+ for (i = 0; i < pool->ntasks; i++) {
+ if (pool->tasks[i] != NULL)
+ isc_task_setprivilege(pool->tasks[i], priv);
+ }
+}
diff --git a/lib/isc/tests/Makefile.in b/lib/isc/tests/Makefile.in
index 5db6e437..8c0a088b 100644
--- a/lib/isc/tests/Makefile.in
+++ b/lib/isc/tests/Makefile.in
@@ -12,7 +12,7 @@
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
-# $Id: Makefile.in,v 1.6 2011-08-23 01:29:38 each Exp $
+# $Id: Makefile.in,v 1.7 2011-09-02 21:15:38 each Exp $
srcdir = @srcdir@
VPATH = @srcdir@
@@ -35,10 +35,12 @@ ISCDEPLIBS = ../libisc.@A@
LIBS = @LIBS@ @ATFLIBS@
OBJS = isctest.@O@
-SRCS = isctest.c taskpool_test.c socket_test.c hash_test.c
+SRCS = isctest.c taskpool_test.c socket_test.c hash_test.c \
+ task_test.c
SUBDIRS =
-TARGETS = taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@
+TARGETS = taskpool_test@EXEEXT@ socket_test@EXEEXT@ hash_test@EXEEXT@ \
+ task_test@EXEEXT@
@BIND9_MAKE_RULES@
@@ -46,6 +48,10 @@ taskpool_test@EXEEXT@: taskpool_test.@O@ isctest.@O@ ${ISCDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
taskpool_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+task_test@EXEEXT@: task_test.@O@ isctest.@O@ ${ISCDEPLIBS}
+ ${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
+ task_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
+
socket_test@EXEEXT@: socket_test.@O@ isctest.@O@ ${ISCDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} ${LDFLAGS} -o $@ \
socket_test.@O@ isctest.@O@ ${ISCLIBS} ${LIBS}
diff --git a/lib/isc/tests/isctest.c b/lib/isc/tests/isctest.c
index b512492b..e01f7f35 100644
--- a/lib/isc/tests/isctest.c
+++ b/lib/isc/tests/isctest.c
@@ -14,12 +14,14 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: isctest.c,v 1.3 2011-07-28 04:04:37 each Exp $ */
+/* $Id: isctest.c,v 1.4 2011-09-02 21:15:38 each Exp $ */
/*! \file */
#include <config.h>
+#include <time.h>
+
#include <isc/app.h>
#include <isc/buffer.h>
#include <isc/entropy.h>
@@ -153,3 +155,24 @@ isc_test_end() {
isc_mem_destroy(&mctx);
}
+/*
+ * Sleep for 'usec' microseconds.
+ */
+void
+isc_test_nap(isc_uint32_t usec) {
+#ifdef HAVE_NANOSLEEP
+ struct timespec ts;
+
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ nanosleep(&ts, NULL);
+#elif HAVE_USLEEP
+ usleep(usec);
+#else
+ /*
+ * No fractional-second sleep function is available, so we
+ * round up to the nearest second and sleep instead
+ */
+ sleep((usec / 1000000) + 1);
+#endif
+}
diff --git a/lib/isc/tests/isctest.h b/lib/isc/tests/isctest.h
index 1d6d9645..2d5914f8 100644
--- a/lib/isc/tests/isctest.h
+++ b/lib/isc/tests/isctest.h
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: isctest.h,v 1.3 2011-07-28 04:04:37 each Exp $ */
+/* $Id: isctest.h,v 1.4 2011-09-02 21:15:38 each Exp $ */
/*! \file */
@@ -52,3 +52,5 @@ isc_test_begin(FILE *logfile, isc_boolean_t start_managers);
void
isc_test_end(void);
+void
+isc_test_nap(isc_uint32_t usec);
diff --git a/lib/isc/tests/socket_test.c b/lib/isc/tests/socket_test.c
index c6f8d4b1..266ea2fc 100644
--- a/lib/isc/tests/socket_test.c
+++ b/lib/isc/tests/socket_test.c
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: socket_test.c,v 1.3 2011-07-28 23:47:59 tbox Exp $ */
+/* $Id: socket_test.c,v 1.4 2011-09-02 21:15:38 each Exp $ */
/*! \file */
@@ -56,22 +56,6 @@ event_done(isc_task_t *task, isc_event_t *event) {
isc_event_free(&event);
}
-static void
-nap(isc_uint32_t usec) {
-#ifdef HAVE_NANOSLEEP
- struct timespec ts;
-
- ts.tv_sec = usec / 1000000;
- ts.tv_nsec = (usec % 1000000) * 1000;
- nanosleep(&ts, NULL);
-#elif HAVE_USLEEP
- usleep(usec);
-#else
- /* Round up to the nearest second and sleep, instead */
- sleep((usec / 1000000) + 1);
-#endif
-}
-
static isc_result_t
waitfor(completion_t *completion) {
int i = 0;
@@ -80,7 +64,7 @@ waitfor(completion_t *completion) {
while (isc__taskmgr_ready(taskmgr))
isc__taskmgr_dispatch(taskmgr);
#endif
- nap(1000);
+ isc_test_nap(1000);
}
if (completion->done)
return (ISC_R_SUCCESS);
diff --git a/lib/isc/tests/task_test.c b/lib/isc/tests/task_test.c
new file mode 100644
index 00000000..a8dfd89d
--- /dev/null
+++ b/lib/isc/tests/task_test.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* $Id: task_test.c,v 1.3 2011-09-02 23:46:33 tbox Exp $ */
+
+/*! \file */
+
+#include <config.h>
+
+#include <atf-c.h>
+
+#include <unistd.h>
+
+#include <isc/task.h>
+#include <isc/util.h>
+
+#include "../task_p.h"
+#include "isctest.h"
+
+/*
+ * Helper functions
+ */
+
+/* task event handler, sets a boolean to true */
+int counter = 0;
+isc_mutex_t set_lock;
+
+static void
+set(isc_task_t *task, isc_event_t *event) {
+ int *value = (int *) event->ev_arg;
+
+ UNUSED(task);
+
+ isc_event_free(&event);
+ LOCK(&set_lock);
+ *value = counter++;
+ UNLOCK(&set_lock);
+}
+
+static void
+set_and_drop(isc_task_t *task, isc_event_t *event) {
+ int *value = (int *) event->ev_arg;
+
+ UNUSED(task);
+
+ isc_event_free(&event);
+ LOCK(&set_lock);
+ *value = (int) isc_taskmgr_mode(taskmgr);
+ counter++;
+ UNLOCK(&set_lock);
+ isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_normal);
+}
+
+/*
+ * Individual unit tests
+ */
+
+/* Create a task */
+ATF_TC(create_task);
+ATF_TC_HEAD(create_task, tc) {
+ atf_tc_set_md_var(tc, "descr", "create and destroy a task");
+}
+ATF_TC_BODY(create_task, tc) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ isc_task_destroy(&task);
+ ATF_REQUIRE_EQ(task, NULL);
+
+ isc_test_end();
+}
+
+/* Process events */
+ATF_TC(all_events);
+ATF_TC_HEAD(all_events, tc) {
+ atf_tc_set_md_var(tc, "descr", "process task events");
+}
+ATF_TC_BODY(all_events, tc) {
+ isc_result_t result;
+ isc_task_t *task = NULL;
+ isc_event_t *event;
+ int a = 0, b = 0;
+ int i = 0;
+
+ UNUSED(tc);
+
+ counter = 1;
+
+ result = isc_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_task_create(taskmgr, 0, &task);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ /* First event */
+ event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST,
+ set, &a, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(a, 0);
+ isc_task_send(task, &event);
+
+ event = isc_event_allocate(mctx, task, ISC_TASKEVENT_TEST,
+ set, &b, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(b, 0);
+ isc_task_send(task, &event);
+
+ while (a == 0 && b == 0 && i++ < 5000) {
+#ifndef ISC_PLATFORM_USETHREADS
+ while (isc__taskmgr_ready(taskmgr))
+ isc__taskmgr_dispatch(taskmgr);
+#endif
+ isc_test_nap(1000);
+ }
+
+ ATF_CHECK(a != 0);
+ ATF_CHECK(b != 0);
+
+ isc_task_destroy(&task);
+ ATF_REQUIRE_EQ(task, NULL);
+
+ isc_test_end();
+}
+
+/* Privileged events */
+ATF_TC(privileged_events);
+ATF_TC_HEAD(privileged_events, tc) {
+ atf_tc_set_md_var(tc, "descr", "process privileged events");
+}
+ATF_TC_BODY(privileged_events, tc) {
+ isc_result_t result;
+ isc_task_t *task1 = NULL, *task2 = NULL;
+ isc_event_t *event;
+ int a = 0, b = 0, c = 0, d = 0, e = 0;
+ int i = 0;
+
+ UNUSED(tc);
+
+ counter = 1;
+ result = isc_mutex_init(&set_lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Pause the task manager so we can fill up the work queue
+ * without things happening while we do it.
+ */
+ isc__taskmgr_pause(taskmgr);
+#endif
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_task_setname(task1, "privileged", NULL);
+ ATF_CHECK(!isc_task_privilege(task1));
+ isc_task_setprivilege(task1, ISC_TRUE);
+ ATF_CHECK(isc_task_privilege(task1));
+
+ result = isc_task_create(taskmgr, 0, &task2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_task_setname(task2, "normal", NULL);
+ ATF_CHECK(!isc_task_privilege(task2));
+
+ /* First event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set, &a, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(a, 0);
+ isc_task_send(task1, &event);
+
+ /* Second event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set, &b, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(b, 0);
+ isc_task_send(task2, &event);
+
+ /* Third event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set, &c, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(c, 0);
+ isc_task_send(task1, &event);
+
+ /* Fourth event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set, &d, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(d, 0);
+ isc_task_send(task1, &event);
+
+ /* Fifth event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set, &e, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(e, 0);
+ isc_task_send(task2, &event);
+
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
+ isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ isc__taskmgr_resume(taskmgr);
+#endif
+
+ /* We're waiting for *all* variables to be set */
+ while ((a == 0 || b == 0 || c == 0 || d == 0 || e == 0) && i++ < 5000) {
+#ifndef ISC_PLATFORM_USETHREADS
+ while (isc__taskmgr_ready(taskmgr))
+ isc__taskmgr_dispatch(taskmgr);
+#endif
+ isc_test_nap(1000);
+ }
+
+ /*
+ * We can't guarantee what order the events fire, but
+ * we do know the privileged tasks that set a, c, and d
+ * would have fired first.
+ */
+ ATF_CHECK(a <= 3);
+ ATF_CHECK(c <= 3);
+ ATF_CHECK(d <= 3);
+
+ /* ...and the non-privileged tasks that set b and e, last */
+ ATF_CHECK(b >= 4);
+ ATF_CHECK(e >= 4);
+
+ ATF_CHECK_EQ(counter, 6);
+
+ isc_task_setprivilege(task1, ISC_FALSE);
+ ATF_CHECK(!isc_task_privilege(task1));
+
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
+
+ isc_task_destroy(&task1);
+ ATF_REQUIRE_EQ(task1, NULL);
+ isc_task_destroy(&task2);
+ ATF_REQUIRE_EQ(task2, NULL);
+
+ isc_test_end();
+}
+
+/*
+ * Edge case: this tests that the task manager behaves as expected when
+ * we explicitly set it into normal mode *while* running privileged.
+ */
+ATF_TC(privilege_drop);
+ATF_TC_HEAD(privilege_drop, tc) {
+ atf_tc_set_md_var(tc, "descr", "process privileged events");
+}
+ATF_TC_BODY(privilege_drop, tc) {
+ isc_result_t result;
+ isc_task_t *task1 = NULL, *task2 = NULL;
+ isc_event_t *event;
+ int a = 0, b = 0, c = 0, d = 0, e = 0;
+ int i = 0;
+
+ UNUSED(tc);
+
+ counter = 1;
+ result = isc_mutex_init(&set_lock);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ /*
+ * Pause the task manager so we can fill up the work queue
+ * without things happening while we do it.
+ */
+ isc__taskmgr_pause(taskmgr);
+#endif
+
+ result = isc_task_create(taskmgr, 0, &task1);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_task_setname(task1, "privileged", NULL);
+ ATF_CHECK(!isc_task_privilege(task1));
+ isc_task_setprivilege(task1, ISC_TRUE);
+ ATF_CHECK(isc_task_privilege(task1));
+
+ result = isc_task_create(taskmgr, 0, &task2);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ isc_task_setname(task2, "normal", NULL);
+ ATF_CHECK(!isc_task_privilege(task2));
+
+ /* First event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set_and_drop, &a, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(a, 0);
+ isc_task_send(task1, &event);
+
+ /* Second event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set_and_drop, &b, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(b, 0);
+ isc_task_send(task2, &event);
+
+ /* Third event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set_and_drop, &c, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(c, 0);
+ isc_task_send(task1, &event);
+
+ /* Fourth event: privileged */
+ event = isc_event_allocate(mctx, task1, ISC_TASKEVENT_TEST,
+ set_and_drop, &d, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(d, 0);
+ isc_task_send(task1, &event);
+
+ /* Fifth event: not privileged */
+ event = isc_event_allocate(mctx, task2, ISC_TASKEVENT_TEST,
+ set_and_drop, &e, sizeof (isc_event_t));
+ ATF_REQUIRE(event != NULL);
+
+ ATF_CHECK_EQ(e, 0);
+ isc_task_send(task2, &event);
+
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
+ isc_taskmgr_setmode(taskmgr, isc_taskmgrmode_privileged);
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_privileged);
+
+#ifdef ISC_PLATFORM_USETHREADS
+ isc__taskmgr_resume(taskmgr);
+#endif
+
+ /* We're waiting for *any* variable to be set */
+ while ((a == 0 && b == 0 && c == 0 && d == 0 && e == 0) && i++ < 5000) {
+#ifndef ISC_PLATFORM_USETHREADS
+ while (isc__taskmgr_ready(taskmgr))
+ isc__taskmgr_dispatch(taskmgr);
+#endif
+ isc_test_nap(1000);
+ }
+
+ /*
+ * We can't guarantee what order the events fire, but
+ * we do know *exactly one* of the privileged tasks will
+ * have run in privileged mode...
+ */
+ ATF_CHECK(a == isc_taskmgrmode_privileged ||
+ c == isc_taskmgrmode_privileged ||
+ d == isc_taskmgrmode_privileged);
+ ATF_CHECK(a + c + d == isc_taskmgrmode_privileged);
+
+ /* ...and neither of the non-privileged tasks did... */
+ ATF_CHECK(b == isc_taskmgrmode_normal || e == isc_taskmgrmode_normal);
+
+ /* ...but all five of them did run. */
+ ATF_CHECK_EQ(counter, 6);
+
+ ATF_CHECK_EQ(isc_taskmgr_mode(taskmgr), isc_taskmgrmode_normal);
+
+ isc_task_destroy(&task1);
+ ATF_REQUIRE_EQ(task1, NULL);
+ isc_task_destroy(&task2);
+ ATF_REQUIRE_EQ(task2, NULL);
+
+ isc_test_end();
+}
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+ ATF_TP_ADD_TC(tp, create_task);
+ ATF_TP_ADD_TC(tp, all_events);
+ ATF_TP_ADD_TC(tp, privileged_events);
+ ATF_TP_ADD_TC(tp, privilege_drop);
+
+ return (atf_no_error());
+}
+
diff --git a/lib/isc/tests/taskpool_test.c b/lib/isc/tests/taskpool_test.c
index a582afdf..3cb9ad47 100644
--- a/lib/isc/tests/taskpool_test.c
+++ b/lib/isc/tests/taskpool_test.c
@@ -14,7 +14,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: taskpool_test.c,v 1.3 2011-07-28 04:04:37 each Exp $ */
+/* $Id: taskpool_test.c,v 1.4 2011-09-02 21:15:38 each Exp $ */
/*! \file */
@@ -148,6 +148,55 @@ ATF_TC_BODY(get_tasks, tc) {
isc_test_end();
}
+/* Get tasks */
+ATF_TC(set_privilege);
+ATF_TC_HEAD(set_privilege, tc) {
+ atf_tc_set_md_var(tc, "descr", "create a taskpool");
+}
+ATF_TC_BODY(set_privilege, tc) {
+ isc_result_t result;
+ isc_taskpool_t *pool = NULL;
+ isc_task_t *task1 = NULL, *task2 = NULL, *task3 = NULL;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, ISC_TRUE);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ result = isc_taskpool_create(taskmgr, mctx, 2, 2, &pool);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+ ATF_REQUIRE_EQ(isc_taskpool_size(pool), 2);
+
+ isc_taskpool_setprivilege(pool, ISC_TRUE);
+
+ isc_taskpool_gettask(pool, &task1);
+ isc_taskpool_gettask(pool, &task2);
+ isc_taskpool_gettask(pool, &task3);
+
+ ATF_CHECK(ISCAPI_TASK_VALID(task1));
+ ATF_CHECK(ISCAPI_TASK_VALID(task2));
+ ATF_CHECK(ISCAPI_TASK_VALID(task3));
+
+ ATF_CHECK(isc_task_privilege(task1));
+ ATF_CHECK(isc_task_privilege(task2));
+ ATF_CHECK(isc_task_privilege(task3));
+
+ isc_taskpool_setprivilege(pool, ISC_FALSE);
+
+ ATF_CHECK(!isc_task_privilege(task1));
+ ATF_CHECK(!isc_task_privilege(task2));
+ ATF_CHECK(!isc_task_privilege(task3));
+
+ isc_task_destroy(&task1);
+ isc_task_destroy(&task2);
+ isc_task_destroy(&task3);
+
+ isc_taskpool_destroy(&pool);
+ ATF_REQUIRE_EQ(pool, NULL);
+
+ isc_test_end();
+}
+
/*
* Main
*/
@@ -155,6 +204,7 @@ ATF_TP_ADD_TCS(tp) {
ATF_TP_ADD_TC(tp, create_pool);
ATF_TP_ADD_TC(tp, expand_pool);
ATF_TP_ADD_TC(tp, get_tasks);
+ ATF_TP_ADD_TC(tp, set_privilege);
return (atf_no_error());
}
diff --git a/lib/isc/unix/socket.c b/lib/isc/unix/socket.c
index 54a6d256..5e97b902 100644
--- a/lib/isc/unix/socket.c
+++ b/lib/isc/unix/socket.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: socket.c,v 1.346 2011-08-24 23:17:52 marka Exp $ */
+/* $Id: socket.c,v 1.348 2011-08-25 11:37:13 marka Exp $ */
/*! \file */
@@ -3784,7 +3784,6 @@ static isc_threadresult_t
watcher(void *uap) {
isc__socketmgr_t *manager = uap;
isc_boolean_t done;
- int ctlfd;
int cc;
#ifdef USE_KQUEUE
const char *fnname = "kevent()";
@@ -3796,16 +3795,19 @@ watcher(void *uap) {
#elif defined (USE_SELECT)
const char *fnname = "select()";
int maxfd;
+ int ctlfd;
#endif
char strbuf[ISC_STRERRORSIZE];
#ifdef ISC_SOCKET_USE_POLLWATCH
pollstate_t pollstate = poll_idle;
#endif
+#if defined (USE_SELECT)
/*
* Get the control fd here. This will never change.
*/
ctlfd = manager->pipe_fds[0];
+#endif
done = ISC_FALSE;
while (!done) {
do {
diff --git a/lib/isc/win32/libisc.def b/lib/isc/win32/libisc.def
index 226e0142..fb084103 100644
--- a/lib/isc/win32/libisc.def
+++ b/lib/isc/win32/libisc.def
@@ -127,17 +127,21 @@ isc__task_getcurrenttime
isc__task_getname
isc__task_gettag
isc__task_onshutdown
+isc__task_privilege
isc__task_purge
isc__task_purgeevent
isc__task_purgerange
isc__task_send
isc__task_sendanddetach
isc__task_setname
+isc__task_setprivilege
isc__task_shutdown
isc__task_unsend
isc__task_unsendrange
isc__taskmgr_create
isc__taskmgr_destroy
+isc__taskmgr_mode
+isc__taskmgr_setmode
isc__timer_attach
isc__timer_create
isc__timer_detach
@@ -535,6 +539,7 @@ isc_taskpool_create
isc_taskpool_destroy
isc_taskpool_expand
isc_taskpool_gettask
+isc_taskpool_setprivilege
isc_taskpool_size
isc_thread_create
isc_thread_join
diff --git a/lib/isccfg/aclconf.c b/lib/isccfg/aclconf.c
index 33090c77..59d309c2 100644
--- a/lib/isccfg/aclconf.c
+++ b/lib/isccfg/aclconf.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: aclconf.c,v 1.31 2011-06-17 23:47:49 tbox Exp $ */
+/* $Id: aclconf.c,v 1.32 2011-08-26 04:49:14 marka Exp $ */
#include <config.h>
@@ -74,13 +74,11 @@ void
cfg_aclconfctx_detach(cfg_aclconfctx_t **actxp) {
cfg_aclconfctx_t *actx;
dns_acl_t *dacl, *next;
- isc_mem_t *mctx;
unsigned int refs;
REQUIRE(actxp != NULL && *actxp != NULL);
actx = *actxp;
- mctx = actx->mctx;
isc_refcount_decrement(&actx->references, &refs);
if (refs == 0) {
diff --git a/lib/isccfg/namedconf.c b/lib/isccfg/namedconf.c
index 52f1d8a1..b66b943b 100644
--- a/lib/isccfg/namedconf.c
+++ b/lib/isccfg/namedconf.c
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: namedconf.c,v 1.139 2011-07-01 02:25:48 marka Exp $ */
+/* $Id: namedconf.c,v 1.141 2011-09-06 22:29:33 smann Exp $ */
/*! \file */
@@ -1395,10 +1395,12 @@ zone_clauses[] = {
{ "notify-to-soa", &cfg_type_boolean, 0 },
{ "nsec3-test-zone", &cfg_type_boolean, CFG_CLAUSEFLAG_TESTONLY },
{ "serial-update-method", &cfg_type_updatemethod, 0 },
+ { "request-ixfr", &cfg_type_boolean, 0 },
{ "sig-signing-nodes", &cfg_type_uint32, 0 },
{ "sig-signing-signatures", &cfg_type_uint32, 0 },
{ "sig-signing-type", &cfg_type_uint32, 0 },
{ "sig-validity-interval", &cfg_type_validityinterval, 0 },
+ { "inline-signing", &cfg_type_boolean, 0 },
{ "transfer-source", &cfg_type_sockaddr4wild, 0 },
{ "transfer-source-v6", &cfg_type_sockaddr6wild, 0 },
{ "try-tcp-refresh", &cfg_type_boolean, 0 },
diff --git a/lib/lwres/getnameinfo.c b/lib/lwres/getnameinfo.c
index b27ac407..ab72b4a2 100644
--- a/lib/lwres/getnameinfo.c
+++ b/lib/lwres/getnameinfo.c
@@ -1,5 +1,5 @@
/*
- * Portions Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 2004, 2005, 2007, 2011 Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (C) 1999-2001, 2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -15,7 +15,7 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: getnameinfo.c,v 1.39 2007-06-19 23:47:22 tbox Exp $ */
+/* $Id: getnameinfo.c,v 1.41 2011-08-30 23:46:53 tbox Exp $ */
/*! \file */
@@ -62,51 +62,51 @@
* sockaddr sa which is salen bytes long. The hostname is of length
* hostlen and is returned via *host. The maximum length of the hostname
* is 1025 bytes: #NI_MAXHOST.
- *
+ *
* The name of the service associated with the port number in sa is
* returned in *serv. It is servlen bytes long. The maximum length of the
* service name is #NI_MAXSERV - 32 bytes.
- *
+ *
* The flags argument sets the following bits:
- *
+ *
* \li #NI_NOFQDN:
* A fully qualified domain name is not required for local hosts.
* The local part of the fully qualified domain name is returned
* instead.
- *
+ *
* \li #NI_NUMERICHOST
* Return the address in numeric form, as if calling inet_ntop(),
* instead of a host name.
- *
+ *
* \li #NI_NAMEREQD
* A name is required. If the hostname cannot be found in the DNS
* and this flag is set, a non-zero error code is returned. If the
* hostname is not found and the flag is not set, the address is
* returned in numeric form.
- *
+ *
* \li #NI_NUMERICSERV
* The service name is returned as a digit string representing the
* port number.
- *
+ *
* \li #NI_DGRAM
* Specifies that the service being looked up is a datagram
* service, and causes getservbyport() to be called with a second
* argument of "udp" instead of its default of "tcp". This is
* required for the few ports (512-514) that have different
* services for UDP and TCP.
- *
+ *
* \section getnameinfo_return Return Values
- *
+ *
* lwres_getnameinfo() returns 0 on success or a non-zero error code if
* an error occurs.
- *
+ *
* \section getname_see See Also
- *
- * RFC2133, getservbyport(),
+ *
+ * RFC2133, getservbyport(),
* lwres_getnamebyaddr(). lwres_net_ntop().
- *
+ *
* \section getnameinfo_bugs Bugs
- *
+ *
* RFC2133 fails to define what the nonzero return values of
* getnameinfo() are.
*/
@@ -219,6 +219,7 @@ lwres_getnameinfo(const struct sockaddr *sa, size_t salen, char *host,
default:
port = 0;
addr = NULL;
+ POST(port); POST(addr);
INSIST(0);
}
proto = (flags & NI_DGRAM) ? "udp" : "tcp";
diff --git a/lib/lwres/lwinetpton.c b/lib/lwres/lwinetpton.c
index 55c732c3..0710f1d1 100644
--- a/lib/lwres/lwinetpton.c
+++ b/lib/lwres/lwinetpton.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 2004, 2005, 2007, 2011 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1996-2001 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or distribute this software for any
@@ -19,7 +19,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static char rcsid[] = "$Id: lwinetpton.c,v 1.12 2007-06-19 23:47:22 tbox Exp $";
+static char rcsid[] = "$Id: lwinetpton.c,v 1.14 2011-08-29 23:46:44 tbox Exp $";
#endif /* LIBC_SCCS and not lint */
#include <config.h>
@@ -41,7 +41,7 @@ static char rcsid[] = "$Id: lwinetpton.c,v 1.12 2007-06-19 23:47:22 tbox Exp $";
static int inet_pton4(const char *src, unsigned char *dst);
static int inet_pton6(const char *src, unsigned char *dst);
-/*!
+/*!
* int
* lwres_net_pton(af, src, dst)
* convert from presentation format (which usually means ASCII printable)
@@ -103,7 +103,12 @@ inet_pton4(const char *src, unsigned char *dst) {
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return (0);
- *++tp = 0;
+ /*
+ * "clang --analyse" generates warnings using:
+ * *++tp = 0;
+ */
+ tp++;
+ *tp = 0;
saw_digit = 0;
} else
return (0);