+2349. [func] Provide incremental re-signing support for secure
+ dynamic zones. [RT #1091]
+
2348. [func] Use the EVP interface to OpenSSL. Add PKCS#11 support.
Documentation is in the new README.pkcs11 file.
[RT #16844]
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: query.c,v 1.303 2008/01/24 02:00:43 jinmei Exp $ */
+/* $Id: query.c,v 1.304 2008/04/01 01:37:24 marka Exp $ */
/*! \file */
result = dns_db_find(db, name, version, type, client->query.dboptions,
client->now, &node, fname, rdataset,
sigrdataset);
- if (result == ISC_R_SUCCESS)
+ if (result == ISC_R_SUCCESS) {
+ if (sigrdataset != NULL && !dns_db_issecure(db) &&
+ dns_rdataset_isassociated(sigrdataset))
+ dns_rdataset_disassociate(sigrdataset);
goto found;
+ }
if (dns_rdataset_isassociated(rdataset))
dns_rdataset_disassociate(rdataset);
eresult = DNS_R_SERVFAIL;
goto cleanup;
}
- if (WANTDNSSEC(client)) {
+ if (WANTDNSSEC(client) && dns_db_issecure(db)) {
sigrdataset = query_newrdataset(client);
if (sigrdataset == NULL) {
eresult = DNS_R_SERVFAIL;
eresult = DNS_R_SERVFAIL;
goto cleanup;
}
- if (WANTDNSSEC(client)) {
+ if (WANTDNSSEC(client) && dns_db_issecure(db)) {
sigrdataset = query_newrdataset(client);
if (sigrdataset == NULL) {
CTRACE("query_addns: query_newrdataset failed");
QUERY_ERROR(DNS_R_SERVFAIL);
goto cleanup;
}
- if (WANTDNSSEC(client)) {
+ if (WANTDNSSEC(client) && (!is_zone || dns_db_issecure(db))) {
sigrdataset = query_newrdataset(client);
if (sigrdataset == NULL) {
QUERY_ERROR(DNS_R_SERVFAIL);
result = dns_rdatasetiter_first(rdsiter);
while (result == ISC_R_SUCCESS) {
dns_rdatasetiter_current(rdsiter, rdataset);
- if ((qtype == dns_rdatatype_any ||
+ if (is_zone && qtype == dns_rdatatype_any &&
+ !dns_db_issecure(db) &&
+ dns_rdatatype_isdnssec(rdataset->type)) {
+ /*
+ * The zone is transitioning from insecure
+ * to secure. Hide the dnssec records from
+ * ANY queries.
+ */
+ dns_rdataset_disassociate(rdataset);
+ } else if ((qtype == dns_rdatatype_any ||
rdataset->type == qtype) && rdataset->type != 0) {
query_addrrset(client,
fname != NULL ? &fname : &tname,
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: update.c,v 1.142 2008/02/07 03:12:15 marka Exp $ */
+/* $Id: update.c,v 1.143 2008/04/01 01:37:24 marka Exp $ */
#include <config.h>
#include <isc/netaddr.h>
#include <isc/print.h>
+#include <isc/serial.h>
#include <isc/string.h>
#include <isc/taskpool.h>
#include <isc/util.h>
*
* RFC2136 does not mention NSEC or DNAME, but multiple NSECs or DNAMEs
* make little sense, so we replace those, too.
+ *
+ * Additionally replace RRSIG that have been generated by the same key
+ * for the same type. This simplifies refreshing a offline KSK by not
+ * requiring that the old RRSIG be deleted. It also simpifies key
+ * rollover by only requiring that the new RRSIG be added.
*/
static isc_boolean_t
replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
+ dns_rdata_rrsig_t updatesig, dbsig;
+ isc_result_t result;
+
if (db_rr->type != update_rr->type)
return (ISC_FALSE);
if (db_rr->type == dns_rdatatype_cname)
return (ISC_TRUE);
if (db_rr->type == dns_rdatatype_nsec)
return (ISC_TRUE);
+ if (db_rr->type == dns_rdatatype_rrsig) {
+ /*
+ * Replace existing RRSIG with the same keyid,
+ * covered and algorithm.
+ */
+ result = dns_rdata_tostruct(db_rr, &dbsig, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ result = dns_rdata_tostruct(update_rr, &updatesig, NULL);
+ RUNTIME_CHECK(result == ISC_R_SUCCESS);
+ if (dbsig.keyid == updatesig.keyid &&
+ dbsig.covered == updatesig.covered &&
+ dbsig.algorithm == updatesig.algorithm)
+ return (ISC_TRUE);
+ }
if (db_rr->type == dns_rdatatype_wks) {
/*
* Compare the address and protocol fields only. These
dns_dbiterator_t *dbit = NULL;
isc_boolean_t has_nsec;
unsigned int wraps = 0;
+ isc_boolean_t secure = dns_db_issecure(db);
CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
* we must pause the iterator first.
*/
CHECK(dns_dbiterator_pause(dbit));
- CHECK(rrset_exists(db, ver, newname,
- dns_rdatatype_nsec, 0, &has_nsec));
-
+ 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)
return (result);
}
+static isc_boolean_t
+has_opt_bit(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t rdataset;
+ isc_boolean_t has_bit = ISC_FALSE;
+
+ dns_rdataset_init(&rdataset);
+ CHECK(dns_db_findrdataset(db, node, version, dns_rdatatype_nsec,
+ dns_rdatatype_none, 0, &rdataset, NULL));
+ CHECK(dns_rdataset_first(&rdataset));
+ dns_rdataset_current(&rdataset, &rdata);
+ has_bit = dns_nsec_typepresent(&rdata, dns_rdatatype_opt);
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ return (has_bit);
+}
+
+static void
+set_bit(unsigned char *array, unsigned int index) {
+ unsigned int shift, mask;
+
+ shift = 7 - (index % 8);
+ mask = 1 << shift;
+
+ array[index / 8] |= mask;
+}
+
/*%
* Add a NSEC record for "name", recording the change in "diff".
* The existing NSEC is removed.
CHECK(dns_db_findnode(db, name, ISC_FALSE, &node));
dns_rdata_init(&rdata);
CHECK(dns_nsec_buildrdata(db, ver, node, target, buffer, &rdata));
+ /*
+ * Preserve the status of the OPT bit in the origin's NSEC record.
+ */
+ if (dns_name_equal(dns_db_origin(db), name) &&
+ has_opt_bit(db, ver, node))
+ {
+ isc_region_t region;
+ dns_name_t next;
+
+ dns_name_init(&next, NULL);
+ dns_rdata_toregion(&rdata, ®ion);
+ dns_name_fromregion(&next, ®ion);
+ isc_region_consume(®ion, next.length);
+ INSIST(region.length > (2 + dns_rdatatype_opt / 8) &&
+ region.base[0] == 0 &&
+ region.base[1] > dns_rdatatype_opt / 8);
+ set_bit(region.base + 2, dns_rdatatype_opt);
+ }
dns_db_detachnode(db, &node);
/*
/* Update the database and journal with the RRSIG. */
/* XXX inefficient - will cause dataset merging */
- CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADD, name,
+ CHECK(update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN, name,
rdataset.ttl, &sig_rdata));
dns_rdata_reset(&sig_rdata);
added_sig = ISC_TRUE;
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;
+
+fprintf(stderr, "del_keysigs\n");
+
+ 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);
+}
+
/*%
* Update RRSIG and NSEC records affected by an update. The original
* update, including the SOA serial update but exluding the RRSIG & NSEC
static isc_result_t
update_signatures(ns_client_t *client, dns_zone_t *zone, dns_db_t *db,
dns_dbversion_t *oldver, dns_dbversion_t *newver,
- dns_diff_t *diff, isc_uint32_t sigvalidityinterval)
+ dns_diff_t *diff, isc_uint32_t sigvalidityinterval,
+ isc_boolean_t *deleted_zsk)
{
isc_result_t result;
dns_difftuple_t *t;
*/
check_ksk = ISC_TF((dns_zone_getoptions(zone) &
DNS_ZONEOPT_UPDATECHECKKSK) != 0);
- if (check_ksk)
+ /*
+ * If we are not checking the ZSK flag then all DNSKEY's are
+ * already signing all RRsets so we don't need to trigger special
+ * changes.
+ */
+ if (*deleted_zsk && (!check_ksk || !ksk_sanity(db, oldver)))
+ *deleted_zsk = ISC_FALSE;
+
+ if (check_ksk) {
check_ksk = ksk_sanity(db, newver);
+ if (!check_ksk && ksk_sanity(db, oldver))
+ update_log(client, zone, ISC_LOG_WARNING,
+ "disabling update-check-ksk");
+ }
+
+ /*
+ * If we have deleted a ZSK and we we still have some ZSK's
+ * we don't need to convert the KSK's to a ZSK's.
+ */
+ if (*deleted_zsk && check_ksk)
+ *deleted_zsk = ISC_FALSE;
/*
* Get the NSEC's TTL from the SOA MINIMUM field.
* 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.
*/
- CHECK(delete_if(true_p, db, newver, name,
- dns_rdatatype_rrsig, type,
- NULL, &sig_diff));
+fprintf(stderr, "delete signatures %u\n", type);
+ 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 still exists after the update,
return (ok ? ISC_R_SUCCESS : DNS_R_REFUSED);
}
+static isc_result_t
+add_signing_records(dns_db_t *db, dns_name_t *name, dns_dbversion_t *ver,
+ dns_diff_t *diff)
+{
+ isc_result_t result = ISC_R_SUCCESS;
+ dns_difftuple_t *tuple, *newtuple = NULL;
+ dns_rdata_dnskey_t dnskey;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned char buf[4];
+ isc_region_t r;
+ isc_uint16_t keyid;
+
+ for (tuple = ISC_LIST_HEAD(diff->tuples);
+ tuple != NULL;
+ tuple = ISC_LIST_NEXT(tuple, link)) {
+ if (tuple->rdata.type != dns_rdatatype_dnskey ||
+ tuple->op != DNS_DIFFOP_ADD)
+ continue;
+
+ dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
+ if ((dnskey.flags &
+ (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
+ != DNS_KEYOWNER_ZONE)
+ continue;
+
+ dns_rdata_toregion(&tuple->rdata, &r);
+ keyid = dst_region_computeid(&r, dnskey.algorithm);
+
+ buf[0] = dnskey.algorithm;
+ buf[1] = (keyid & 0xff00) >> 8;
+ buf[2] = (keyid & 0xff);
+ buf[3] = 0;
+ rdata.data = buf;
+ rdata.length = sizeof(buf);
+ rdata.type = 0xFFFF; /* XXXMPA make user settable */
+ rdata.rdclass = tuple->rdata.rdclass;
+
+ CHECK(dns_difftuple_create(diff->mctx, DNS_DIFFOP_ADD, name,
+ 0, &rdata, &newtuple));
+ CHECK(do_one_tuple(&newtuple, db, ver, diff));
+ INSIST(newtuple == NULL);
+ }
+ failure:
+ return (result);
+}
+
static void
update_action(isc_task_t *task, isc_event_t *event) {
update_event_t *uev = (update_event_t *) event;
dns_fixedname_t tmpnamefixed;
dns_name_t *tmpname = NULL;
unsigned int options;
+ isc_boolean_t deleted_zsk;
+ dns_difftuple_t *tuple;
+ dns_rdata_dnskey_t dnskey;
INSIST(event->ev_type == DNS_EVENT_UPDATE);
* "Unlike traditional dynamic update, the client
* is forbidden from updating NSEC records."
*/
- if (dns_db_issecure(db)) {
+ if (dns_db_isdnssec(db)) {
if (rdata.type == dns_rdatatype_nsec) {
FAILC(DNS_R_REFUSED,
"explicit NSEC updates are not allowed "
"in secure zones");
}
- else if (rdata.type == dns_rdatatype_rrsig) {
+ else if (rdata.type == dns_rdatatype_rrsig &&
+ !dns_name_equal(name, zonename)) {
FAILC(DNS_R_REFUSED,
"explicit RRSIG updates are currently "
- "not supported in secure zones");
+ "not supported in secure zones except "
+ "at the apex.");
}
}
if (! ISC_LIST_EMPTY(diff.tuples)) {
char *journalfile;
dns_journal_t *journal;
+ isc_boolean_t has_dnskey;
/*
* Increment the SOA serial, but only if it was not
CHECK(remove_orphaned_ds(db, ver, &diff));
- if (dns_db_issecure(db)) {
+ CHECK(add_signing_records(db, zonename, ver, &diff));
+
+ CHECK(rrset_exists(db, ver, zonename, dns_rdatatype_dnskey,
+ 0, &has_dnskey));
+
+ if (has_dnskey && dns_db_isdnssec(db)) {
+ isc_uint32_t interval;
+ interval = dns_zone_getsigvalidityinterval(zone);
result = update_signatures(client, zone, db, oldver,
- ver, &diff,
- dns_zone_getsigvalidityinterval(zone));
+ ver, &diff, interval,
+ &deleted_zsk);
if (result != ISC_R_SUCCESS) {
update_log(client, zone,
ISC_LOG_ERROR,
*/
update_log(client, zone, LOGLEVEL_DEBUG,
"committing update transaction");
+
dns_db_closeversion(db, &ver, ISC_TRUE);
/*
* Notify slaves of the change we just made.
*/
dns_zone_notify(zone);
+
+ for (tuple = ISC_LIST_HEAD(diff.tuples);
+ tuple != NULL;
+ tuple = ISC_LIST_NEXT(tuple, link)) {
+ isc_region_t r;
+ dns_secalg_t algorithm;
+ isc_uint16_t keyid;
+
+ if (tuple->rdata.type != dns_rdatatype_dnskey ||
+ tuple->op != DNS_DIFFOP_ADD)
+ continue;
+
+ dns_rdata_tostruct(&tuple->rdata, &dnskey, NULL);
+ if ((dnskey.flags &
+ (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
+ != DNS_KEYOWNER_ZONE)
+ continue;
+
+ dns_rdata_toregion(&tuple->rdata, &r);
+ algorithm = dnskey.algorithm;
+ keyid = dst_region_computeid(&r, algorithm);
+
+ result = dns_zone_signwithkey(zone, algorithm, keyid);
+ if (result != ISC_R_SUCCESS) {
+ update_log(client, zone, ISC_LOG_ERROR,
+ "dns_zone_signwithkey failed: %s",
+ dns_result_totext(result));
+ }
+ }
} else {
update_log(client, zone, LOGLEVEL_DEBUG, "redundant request");
dns_db_closeversion(db, &ver, ISC_TRUE);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: nsupdate.c,v 1.157 2008/01/18 23:46:57 tbox Exp $ */
+/* $Id: nsupdate.c,v 1.158 2008/04/01 01:37:24 marka Exp $ */
/*! \file */
check_result(result, "isc_lex_openbuffer");
result = isc_buffer_allocate(mctx, &buf, MAXWIRE);
check_result(result, "isc_buffer_allocate");
- result = dns_rdata_fromtext(rdata, rdataclass, rdatatype, lex,
+ result = dns_rdata_fromtext(NULL, rdataclass, rdatatype, lex,
dns_rootname, 0, mctx, buf,
&callbacks);
isc_lex_destroy(&lex);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: check.c,v 1.89 2008/03/29 23:47:08 tbox Exp $ */
+/* $Id: check.c,v 1.90 2008/04/01 01:37:24 marka Exp $ */
/*! \file */
if (tresult != ISC_R_SUCCESS &&
result == ISC_R_SUCCESS)
result = tresult;
+ goto trust_anchor;
}
/*
* XXXMPA to be removed when multiple lookaside
if (result == ISC_R_SUCCESS)
result = ISC_R_FAILURE;
}
+ trust_anchor:
dlv = cfg_obj_asstring(cfg_tuple_get(obj,
"trust-anchor"));
isc_buffer_init(&b, dlv, strlen(dlv));
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: db.c,v 1.83 2007/06/18 23:47:40 tbox Exp $ */
+/* $Id: db.c,v 1.84 2008/04/01 01:37:24 marka Exp $ */
/*! \file */
return (ISC_FALSE);
}
+isc_boolean_t
+dns_db_isdnssec(dns_db_t *db) {
+
+ /*
+ * Is 'db' secure or partially secure?
+ */
+
+ REQUIRE(DNS_DB_VALID(db));
+ REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
+
+ if (db->methods->isdnssec != NULL)
+ return ((db->methods->isdnssec)(db));
+ return ((db->methods->issecure)(db));
+}
+
isc_boolean_t
dns_db_issecure(dns_db_t *db) {
return (ISC_R_NOTFOUND);
}
+
+isc_result_t
+dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
+ isc_stdtime_t resign)
+{
+ if (db->methods->setsigningtime != NULL)
+ return ((db->methods->setsigningtime)(db, rdataset, resign));
+ return (ISC_R_NOTIMPLEMENTED);
+}
+
+isc_result_t
+dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name)
+{
+ if (db->methods->getsigningtime != NULL)
+ return ((db->methods->getsigningtime)(db, rdataset, name));
+ return (ISC_R_NOTFOUND);
+}
+
+void
+dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)
+{
+ if (db->methods->resigned != NULL)
+ return ((db->methods->resigned)(db, rdataset, version));
+}
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: diff.c,v 1.14 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: diff.c,v 1.15 2008/04/01 01:37:24 marka Exp $ */
/*! \file */
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
+#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#include <dns/result.h>
ENSURE(*tuplep == NULL);
}
+static isc_stdtime_t
+setresign(dns_rdataset_t *modified, dns_diffop_t op) {
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_rrsig_t sig;
+ isc_stdtime_t when;
+ unsigned int delta;
+ isc_result_t result;
+
+ result = dns_rdataset_first(modified);
+ INSIST(result == ISC_R_SUCCESS);
+ dns_rdataset_current(modified, &rdata);
+ (void)dns_rdata_tostruct(&rdata, &sig, NULL);
+ if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
+ when = 0;
+ } else {
+ delta = (sig.timeexpire - sig.timesigned) * 3 / 4;
+ when = sig.timesigned + delta;
+ }
+ dns_rdata_reset(&rdata);
+
+ result = dns_rdataset_next(modified);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(modified, &rdata);
+ (void)dns_rdata_tostruct(&rdata, &sig, NULL);
+ if ((rdata.flags & DNS_RDATA_OFFLINE) != 0) {
+ goto next_rr;
+ }
+ delta = (sig.timeexpire - sig.timesigned)* 3 / 4;
+ switch (op) {
+ case DNS_DIFFOP_ADDRESIGN:
+ case DNS_DIFFOP_DELRESIGN:
+ if (when == 0 || sig.timesigned + delta < when)
+ when = sig.timesigned + delta;
+ break;
+ default:
+ INSIST(0);
+ }
+ next_rr:
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(modified);
+ }
+ INSIST(result == ISC_R_NOMORE);
+fprintf(stderr, "setresign %u %u\n", modified->covers, when);
+ return (when);
+}
+
static isc_result_t
diff_apply(dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
isc_boolean_t warn)
dns_diffop_t op;
dns_rdatalist_t rdl;
dns_rdataset_t rds;
+ dns_rdataset_t ardataset;
+ dns_rdataset_t *modified = NULL;
+ isc_boolean_t offline;
op = t->op;
type = t->rdata.type;
ISC_LIST_INIT(rdl.rdata);
ISC_LINK_INIT(&rdl, link);
+ offline = ISC_FALSE;
while (t != NULL &&
dns_name_equal(&t->name, name) &&
t->op == op &&
namebuf, typebuf, classbuf,
(unsigned long) t->ttl,
(unsigned long) rdl.ttl);
+ if (t->rdata.flags &DNS_RDATA_OFFLINE) {
+ fprintf(stderr, "diff_apply offline\n");
+ offline = ISC_TRUE;
+ }
ISC_LIST_APPEND(rdl.rdata, &t->rdata, link);
t = ISC_LIST_NEXT(t, link);
}
*/
dns_rdataset_init(&rds);
CHECK(dns_rdatalist_tordataset(&rdl, &rds));
+ if (rds.type == dns_rdatatype_rrsig)
+ switch (op) {
+ case DNS_DIFFOP_ADDRESIGN:
+ case DNS_DIFFOP_DELRESIGN:
+ modified = &ardataset;
+ dns_rdataset_init(modified);
+ break;
+ default:
+ break;
+ }
rds.trust = dns_trust_ultimate;
/*
* Merge the rdataset into the database.
*/
- if (op == DNS_DIFFOP_ADD) {
+ switch (op) {
+ case DNS_DIFFOP_ADD:
+ case DNS_DIFFOP_ADDRESIGN:
result = dns_db_addrdataset(db, node, ver,
0, &rds,
DNS_DBADD_MERGE|
DNS_DBADD_EXACT|
DNS_DBADD_EXACTTTL,
- NULL);
- } else if (op == DNS_DIFFOP_DEL) {
+ modified);
+ break;
+ case DNS_DIFFOP_DEL:
+ case DNS_DIFFOP_DELRESIGN:
result = dns_db_subtractrdataset(db, node, ver,
&rds,
DNS_DBSUB_EXACT,
- NULL);
- } else {
+ modified);
+ break;
+ default:
INSIST(0);
}
- if (result == DNS_R_UNCHANGED) {
+
+ if (result == ISC_R_SUCCESS) {
+ if (modified != NULL) {
+ isc_stdtime_t resign;
+ resign = setresign(modified, op);
+ dns_db_setsigningtime(db, modified,
+ resign);
+ }
+ } else if (result == DNS_R_UNCHANGED) {
/*
* This will not happen when executing a
* dynamic update, because that code will
isc_log_write(DIFF_COMMON_LOGARGS,
ISC_LOG_WARNING,
"update with no effect");
- } else if (result == ISC_R_SUCCESS ||
- result == DNS_R_NXRRSET) {
+ } else if (result == DNS_R_NXRRSET) {
/*
* OK.
*/
} else {
+ if (modified != NULL &&
+ dns_rdataset_isassociated(modified))
+ dns_rdataset_disassociate(modified);
CHECK(result);
}
+ if (modified != NULL &&
+ dns_rdataset_isassociated(modified))
+ dns_rdataset_disassociate(modified);
+ if (offline)
+ fprintf(stderr, "end offline\n");
}
dns_db_detachnode(db, &node);
}
dns_difftuple_t *t;
char *mem = NULL;
unsigned int size = 2048;
+ const char *op = NULL;
REQUIRE(DNS_DIFF_VALID(diff));
buf.used--;
isc_buffer_usedregion(&buf, &r);
+ switch (t->op) {
+ case DNS_DIFFOP_EXISTS: op = "exists"; break;
+ case DNS_DIFFOP_ADD: op = "add"; break;
+ case DNS_DIFFOP_DEL: op = "del"; break;
+ case DNS_DIFFOP_ADDRESIGN: op = "add re-sign"; break;
+ case DNS_DIFFOP_DELRESIGN: op = "del re-sign"; break;
+ }
if (file != NULL)
- fprintf(file, "%s %.*s\n",
- t->op == DNS_DIFFOP_ADD ? "add" : "del",
- (int) r.length, (char *) r.base);
+ fprintf(file, "%s %.*s\n", op, (int) r.length,
+ (char *) r.base);
else
isc_log_write(DIFF_COMMON_LOGARGS, ISC_LOG_DEBUG(7),
- "%s %.*s",
- t->op == DNS_DIFFOP_ADD ? "add" : "del",
- (int) r.length, (char *) r.base);
+ "%s %.*s", op, (int) r.length,
+ (char *) r.base);
}
result = ISC_R_SUCCESS;
cleanup:
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: db.h,v 1.89 2007/06/18 23:47:42 tbox Exp $ */
+/* $Id: db.h,v 1.90 2008/04/01 01:37:25 marka Exp $ */
#ifndef DNS_DB_H
#define DNS_DB_H 1
void (*settask)(dns_db_t *db, isc_task_t *);
isc_result_t (*getoriginnode)(dns_db_t *db, dns_dbnode_t **nodep);
void (*transfernode)(dns_db_t *db, dns_dbnode_t **sourcep,
- dns_dbnode_t **targetp);
+ dns_dbnode_t **targetp);
+ isc_result_t (*setsigningtime)(dns_db_t *db,
+ dns_rdataset_t *rdataset,
+ isc_stdtime_t resign);
+ isc_result_t (*getsigningtime)(dns_db_t *db,
+ dns_rdataset_t *rdataset,
+ dns_name_t *name);
+ void (*resigned)(dns_db_t *db, dns_rdataset_t *rdataset,
+ dns_dbversion_t *version);
+ isc_boolean_t (*isdnssec)(dns_db_t *db);
} dns_dbmethods_t;
typedef isc_result_t
* \li #ISC_FALSE 'db' is not secure.
*/
+isc_boolean_t
+dns_db_isdnssec(dns_db_t *db);
+/*%<
+ * Is 'db' secure or partially secure?
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database with zone semantics.
+ *
+ * Returns:
+ * \li #ISC_TRUE 'db' is secure or is partially.
+ * \li #ISC_FALSE 'db' is not secure.
+ */
+
dns_name_t *
dns_db_origin(dns_db_t *db);
/*%<
*
* \li #ISC_R_SUCCESS
* \li #ISC_R_NOTFOUND If !create and name not found.
- * \li #ISC_R_NOMEMORY Can only happen if create is ISC_TRUE.
+ * \li #ISC_R_NOMEMORY Can only happen if create is ISC_TRUE.
*
* \li Other results are possible, depending upon the database
* implementation used.
void
dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep,
- dns_dbnode_t **targetp);
+ dns_dbnode_t **targetp);
/*%<
* Transfer a node between pointer.
*
* \li #ISC_R_NOTFOUND - the DB implementation does not support this feature.
*/
+isc_result_t
+dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
+ isc_stdtime_t resign);
+/*%<
+ * Sets the re-signing time associated with 'rdataset' to 'resign'.
+ *
+ * Requires:
+ * \li 'db' is a valid zone database.
+ * \li 'rdataset' to be associated with 'db'.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOMEMORY
+ * \li #ISC_R_NOTIMPLEMENTED - Not supported by this DB implementation.
+ */
+
+isc_result_t
+dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name);
+/*%<
+ * Return the rdataset with the earliest signing time in the zone.
+ * Note: the rdataset is version agnostic.
+ *
+ * Requires:
+ * \li 'db' is a valid zone database.
+ * \li 'rdataset' to be initialized but not associated.
+ * \li 'name' to be NULL or have a buffer associated with it.
+ *
+ * Returns:
+ * \li #ISC_R_SUCCESS
+ * \li #ISC_R_NOTFOUND - No dataset exists.
+ */
+
+void
+dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset,
+ dns_dbversion_t *version);
+/*%<
+ * Mark 'rdataset' as not being available to be returned by
+ * dns_db_getsigningtime(). If the changes associated with 'version'
+ * are committed this will be permanent. If the version is not committed
+ * this change will be rolled back when the version is closed.
+ *
+ * Requires:
+ * \li 'db' is a valid zone database.
+ * \li 'rdataset' to be associated with 'db'.
+ * \li 'version' to be open for writing.
+ */
+
+
ISC_LANG_ENDDECLS
#endif /* DNS_DB_H */
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: diff.h,v 1.12 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: diff.h,v 1.13 2008/04/01 01:37:25 marka Exp $ */
#ifndef DNS_DIFF_H
#define DNS_DIFF_H 1
* individual RRs of a "RRset exists (value dependent)"
* prerequisite set. In this case, op==DNS_DIFFOP_EXISTS,
* and the TTL is ignored.
+ *
+ * DNS_DIFFOP_*RESIGN will cause the 'resign' attribute to be recomputed.
*/
typedef enum {
- DNS_DIFFOP_ADD, /*%< Add an RR. */
- DNS_DIFFOP_DEL, /*%< Delete an RR. */
- DNS_DIFFOP_EXISTS /*%< Assert RR existence. */
+ DNS_DIFFOP_ADD = 0, /*%< Add an RR. */
+ DNS_DIFFOP_DEL = 1, /*%< Delete an RR. */
+ DNS_DIFFOP_EXISTS = 2, /*%< Assert RR existence. */
+ DNS_DIFFOP_ADDRESIGN = 4, /*%< ADD + RESIGN. */
+ DNS_DIFFOP_DELRESIGN = 5, /*%< DEL + RESIGN. */
} dns_diffop_t;
typedef struct dns_difftuple dns_difftuple_t;
#define DNS_DIFFTUPLE_VALID(t) ISC_MAGIC_VALID(t, DNS_DIFFTUPLE_MAGIC)
struct dns_difftuple {
- unsigned int magic;
+ unsigned int magic;
isc_mem_t *mctx;
dns_diffop_t op;
dns_name_t name;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: journal.h,v 1.31 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: journal.h,v 1.32 2008/04/01 01:37:25 marka Exp $ */
#ifndef DNS_JOURNAL_H
#define DNS_JOURNAL_H 1
#include <dns/rdata.h>
#include <dns/types.h>
+/***
+ *** Defines.
+ ***/
+#define DNS_JOURNALOPT_RESIGN 0x00000001
+
/***
*** Types
***/
*/
isc_result_t
-dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename);
+dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, unsigned int options,
+ const char *filename);
/*%<
* Roll forward (play back) the journal file "filename" into the
* database "db". This should be called when the server starts
* after a shutdown or crash.
*
* Requires:
- *\li 'mctx' is a valid memory context.
+ *\li 'mctx' is a valid memory context.
*\li 'db' is a valid database which does not have a version
* open for writing.
- * \li 'filename' is the name of the journal file belonging to 'db'.
+ *\li 'filename' is the name of the journal file belonging to 'db'.
*
* Returns:
*\li DNS_R_NOJOURNAL when journal does not exist.
isc_result_t
dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
- isc_uint32_t target_size);
+ isc_uint32_t target_size);
/*%<
* Attempt to compact the journal if it is greater that 'target_size'.
* Changes from 'serial' onwards will be preserved. If the journal
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: master.h,v 1.48 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: master.h,v 1.49 2008/04/01 01:37:25 marka Exp $ */
#ifndef DNS_MASTER_H
#define DNS_MASTER_H 1
#define DNS_MASTER_CHECKMX 0x00000800
#define DNS_MASTER_CHECKMXFAIL 0x00001000
+#define DNS_MASTER_RESIGN 0x00002000
+
ISC_LANG_BEGINDECLS
/*
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: masterdump.h,v 1.39 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: masterdump.h,v 1.40 2008/04/01 01:37:25 marka Exp $ */
#ifndef DNS_MASTERDUMP_H
#define DNS_MASTERDUMP_H 1
/*% Print negative caching entries. */
#define DNS_STYLEFLAG_NCACHE 0x00800000U
-/*% Never print the TTL */
+/*% Never print the TTL. */
#define DNS_STYLEFLAG_NO_TTL 0x01000000U
-
-/*% Never print the CLASS */
+
+/*% Never print the CLASS. */
#define DNS_STYLEFLAG_NO_CLASS 0x02000000U
+/*% Report re-signing time. */
+#define DNS_STYLEFLAG_RESIGN 0x04000000U
+
ISC_LANG_BEGINDECLS
/***
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdata.h,v 1.67 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: rdata.h,v 1.68 2008/04/01 01:37:25 marka Exp $ */
#ifndef DNS_RDATA_H
#define DNS_RDATA_H 1
#define DNS_RDATA_INIT { NULL, 0, 0, 0, 0, {(void*)(-1), (void *)(-1)}}
-#define DNS_RDATA_UPDATE 0x0001 /*%< update pseudo record */
+#define DNS_RDATA_UPDATE 0x0001 /*%< update pseudo record. */
+#define DNS_RDATA_OFFLINE 0x0002 /*%< RRSIG has a offline key. */
+#define DNS_RDATA_WARNMASK 0x001c /*%< RRSIG(DNSKEY) expired
+ warnings number mask. */
+#define DNS_RDATA_WARNSHIFT 2 /*%< How many bits to shift
+ to find remaining
+ expired warning number. */
/*
* Flags affecting rdata formatting style. Flags 0xFFFF0000
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdataset.h,v 1.62 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: rdataset.h,v 1.63 2008/04/01 01:37:25 marka Exp $ */
#ifndef DNS_RDATASET_H
#define DNS_RDATASET_H 1
* increment the counter.
*/
isc_uint32_t count;
+ /*
+ * This RRSIG RRset should be re-generated around this time.
+ * Only valid if DNS_RDATASETATTR_RESIGN is set in attributes.
+ */
+ isc_stdtime_t resign;
/*@{*/
/*%
* These are for use by the rdataset implementation, and MUST NOT
void * private5;
void * private6;
/*@}*/
+
};
/*!
#define DNS_RDATASETATTR_CHECKNAMES 0x00008000 /*%< Used by resolver. */
#define DNS_RDATASETATTR_REQUIREDGLUE 0x00010000
#define DNS_RDATASETATTR_LOADORDER 0x00020000
+#define DNS_RDATASETATTR_RESIGN 0x00040000
/*%
* _OMITDNSSEC:
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdataslab.h,v 1.31 2007/06/19 23:47:17 tbox Exp $ */
+/* $Id: rdataslab.h,v 1.32 2008/04/01 01:37:25 marka Exp $ */
#ifndef DNS_RDATASLAB_H
#define DNS_RDATASLAB_H 1
#define DNS_RDATASLAB_FORCE 0x1
#define DNS_RDATASLAB_EXACT 0x2
+#define DNS_RDATASLAB_OFFLINE 0x01 /* RRSIG is for offline DNSKEY */
+#define DNS_RDATASLAB_WARNMASK 0x0E /*%< RRSIG(DNSKEY) expired
+ * warnings number mask. */
+#define DNS_RDATASLAB_WARNSHIFT 1 /*%< How many bits to shift to find
+ * remaining expired warning number. */
+
+
/***
*** Functions
***/
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.h,v 1.155 2008/01/24 23:47:00 tbox Exp $ */
+/* $Id: zone.h,v 1.156 2008/04/01 01:37:25 marka Exp $ */
#ifndef DNS_ZONE_H
#define DNS_ZONE_H 1
dns_zone_getupdatedisabled(dns_zone_t *zone);
/*%<
* Return update disabled.
+ * Transient unless called when running in isc_task_exclusive() mode.
*/
void
dns_zone_setupdatedisabled(dns_zone_t *zone, isc_boolean_t state);
/*%<
* Set update disabled.
+ * Should only be called only when running in isc_task_exclusive() mode.
+ * Failure to do so may result in updates being committed after the
+ * call has been made.
*/
isc_boolean_t
* delivered to 'myview'.
*/
+isc_result_t
+dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid);
+
#ifdef HAVE_LIBXML2
isc_result_t
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: journal.c,v 1.99 2007/09/07 05:14:33 marka Exp $ */
+/* $Id: journal.c,v 1.100 2008/04/01 01:37:24 marka Exp $ */
#include <config.h>
dns_difftuple_t const *a = *ap;
dns_difftuple_t const *b = *bp;
int r;
+ int bop = 0, aop = 0;
+
+ switch (a->op) {
+ case DNS_DIFFOP_DEL:
+ case DNS_DIFFOP_DELRESIGN:
+ aop = 1;
+ break;
+ case DNS_DIFFOP_ADD:
+ case DNS_DIFFOP_ADDRESIGN:
+ aop = 0;
+ break;
+ default:
+ INSIST(0);
+ }
+
+ switch (b->op) {
+ case DNS_DIFFOP_DEL:
+ case DNS_DIFFOP_DELRESIGN:
+ bop = 1;
+ break;
+ case DNS_DIFFOP_ADD:
+ case DNS_DIFFOP_ADDRESIGN:
+ bop = 0;
+ break;
+ default:
+ INSIST(0);
+ }
- r = (b->op == DNS_DIFFOP_DEL) - (a->op == DNS_DIFFOP_DEL);
+ r = bop - aop;
if (r != 0)
return (r);
/* XXX Share code with incoming IXFR? */
static isc_result_t
-roll_forward(dns_journal_t *j, dns_db_t *db) {
+roll_forward(dns_journal_t *j, dns_db_t *db, unsigned int options) {
isc_buffer_t source; /* Transaction data from disk */
isc_buffer_t target; /* Ditto after _fromwire check */
isc_uint32_t db_serial; /* Database SOA serial */
dns_diff_t diff;
unsigned int n_soa = 0;
unsigned int n_put = 0;
+ dns_diffop_t op;
REQUIRE(DNS_JOURNAL_VALID(j));
REQUIRE(DNS_DB_VALID(db));
"initial SOA", j->filename);
FAIL(ISC_R_UNEXPECTED);
}
- CHECK(dns_difftuple_create(diff.mctx, n_soa == 1 ?
- DNS_DIFFOP_DEL : DNS_DIFFOP_ADD,
- name, ttl, rdata, &tuple));
+ if ((options & DNS_JOURNALOPT_RESIGN) != 0)
+ op = (n_soa == 1) ? DNS_DIFFOP_DELRESIGN :
+ DNS_DIFFOP_ADDRESIGN;
+ else
+ op = (n_soa == 1) ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD;
+
+ CHECK(dns_difftuple_create(diff.mctx, op, name, ttl, rdata,
+ &tuple));
dns_diff_append(&diff, &tuple);
if (++n_put > 100) {
}
isc_result_t
-dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename) {
+dns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db,
+ unsigned int options, const char *filename)
+{
dns_journal_t *j;
isc_result_t result;
if (JOURNAL_EMPTY(&j->header))
result = DNS_R_UPTODATE;
else
- result = roll_forward(j, db);
+ result = roll_forward(j, db, options);
dns_journal_destroy(&j);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: master.c,v 1.169 2008/01/18 23:46:58 tbox Exp $ */
+/* $Id: master.c,v 1.170 2008/04/01 01:37:24 marka Exp $ */
/*! \file */
char namebuf[DNS_NAME_FORMATSIZE];
dns_name_format(ictx->current, namebuf,
sizeof(namebuf));
- (*callbacks->error)(callbacks,
- "%s:%lu: SOA "
+ (*callbacks->error)(callbacks, "%s:%lu: SOA "
"record not at top of zone (%s)",
source, line, namebuf);
result = DNS_R_NOTZONETOP;
return (new);
}
+static isc_uint32_t
+resign_fromlist(dns_rdatalist_t *this) {
+ dns_rdata_t *rdata;
+ dns_rdata_rrsig_t sig;
+ isc_uint32_t when, delta;
+
+ rdata = ISC_LIST_HEAD(this->rdata);
+ INSIST(rdata != NULL);
+ (void)dns_rdata_tostruct(rdata, &sig, NULL);
+ delta = (sig.timeexpire - sig.timesigned)* 3 / 4;
+ when = sig.timesigned + delta;
+
+ rdata = ISC_LIST_NEXT(rdata, link);
+ while (rdata != NULL) {
+ (void)dns_rdata_tostruct(rdata, &sig, NULL);
+ delta = (sig.timeexpire - sig.timesigned)* 3 / 4;
+ if (sig.timesigned + delta < when)
+ when = sig.timesigned + delta;
+ rdata = ISC_LIST_NEXT(rdata, link);
+ }
+ return (when);
+}
+
/*
* Convert each element from a rdatalist_t to rdataset then call commit.
* Unlink each element as we go.
RUNTIME_CHECK(dns_rdatalist_tordataset(this, &dataset)
== ISC_R_SUCCESS);
dataset.trust = dns_trust_ultimate;
+ /*
+ * If this is a secure dynamic zone set the re-signing time.
+ */
+ if (dataset.type == dns_rdatatype_rrsig &&
+ (lctx->options & DNS_MASTER_RESIGN) != 0) {
+ dataset.attributes |= DNS_RDATASETATTR_RESIGN;
+ dns_name_format(owner, namebuf, sizeof(namebuf));
+ dataset.resign = resign_fromlist(this);
+ }
result = ((*callbacks->add)(callbacks->add_private, owner,
&dataset));
if (result == ISC_R_NOMEMORY) {
(*error)(callbacks, "dns_master_load: %s",
dns_result_totext(result));
} else if (result != ISC_R_SUCCESS) {
- dns_name_format(owner, namebuf,
- sizeof(namebuf));
+ dns_name_format(owner, namebuf, sizeof(namebuf));
if (source != NULL) {
(*error)(callbacks, "%s: %s:%lu: %s: %s",
"dns_master_load", source, line,
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: masterdump.c,v 1.89 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: masterdump.c,v 1.90 2008/04/01 01:37:24 marka Exp $ */
/*! \file */
LIBDNS_EXTERNAL_DATA const dns_master_style_t
dns_master_style_full = {
- DNS_STYLEFLAG_COMMENT,
+ DNS_STYLEFLAG_COMMENT |
+ DNS_STYLEFLAG_RESIGN,
46, 46, 46, 64, 120, 8
};
if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
name = NULL;
}
+ if (ctx->style.flags & DNS_STYLEFLAG_RESIGN &&
+ rds->attributes & DNS_RDATASETATTR_RESIGN) {
+ isc_buffer_t b;
+ char buf[sizeof("YYYYMMDDHHMMSS")];
+ memset(buf, 0, sizeof(buf));
+ isc_buffer_init(&b, buf, sizeof(buf) - 1);
+ dns_time64_totext((isc_uint64_t)rds->resign, &b);
+ fprintf(f, "; resign=%s\n", buf);
+ }
dns_rdataset_disassociate(rds);
}
dns_db_t *
dns_dumpctx_db(dns_dumpctx_t *dctx) {
- REQUIRE(DNS_DCTX_VALID(dctx));
+ REQUIRE(DNS_DCTX_VALID(dctx));
return (dctx->db);
}
isc_result_t
dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags,
- unsigned int ttl_column, unsigned int class_column,
- unsigned int type_column, unsigned int rdata_column,
- unsigned int line_length, unsigned int tab_width,
- isc_mem_t *mctx)
+ unsigned int ttl_column, unsigned int class_column,
+ unsigned int type_column, unsigned int rdata_column,
+ unsigned int line_length, unsigned int tab_width,
+ isc_mem_t *mctx)
{
dns_master_style_t *style;
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rbtdb.c,v 1.252 2008/02/01 23:46:58 tbox Exp $ */
+/* $Id: rbtdb.c,v 1.253 2008/04/01 01:37:24 marka Exp $ */
/*! \file */
#include <config.h>
-#include <isc/heap.h>
#include <isc/event.h>
+#include <isc/heap.h>
#include <isc/mem.h>
+#include <isc/mutex.h>
#include <isc/platform.h>
#include <isc/print.h>
-#include <isc/mutex.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <isc/rwlock.h>
+#include <isc/serial.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/time.h>
#include <dns/lib.h>
#include <dns/log.h>
#include <dns/masterdump.h>
+#include <dns/nsec.h>
#include <dns/rbt.h>
#include <dns/rdata.h>
#include <dns/rdataset.h>
/*%<
* Used for TTL-based cache cleaning.
*/
+ isc_stdtime_t resign;
} rdatasetheader_t;
typedef ISC_LIST(rdatasetheader_t) rdatasetheaderlist_t;
#define RDATASET_ATTR_IGNORE 0x0004
#define RDATASET_ATTR_RETAIN 0x0008
#define RDATASET_ATTR_NXDOMAIN 0x0010
+#define RDATASET_ATTR_RESIGN 0x0020
#define RDATASET_ATTR_CACHE 0x1000 /* for debug */
#define RDATASET_ATTR_CANCELED 0x2000 /* for debug */
(((header)->attributes & RDATASET_ATTR_RETAIN) != 0)
#define NXDOMAIN(header) \
(((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
+#define RESIGN(header) \
+ (((header)->attributes & RDATASET_ATTR_RESIGN) != 0)
#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */
#define DEFAULT_CACHE_NODE_LOCK_COUNT 1009 /*%< Should be prime. */
isc_boolean_t writer;
isc_boolean_t commit_ok;
rbtdb_changedlist_t changed_list;
+ rdatasetheaderlist_t resigned_list;
ISC_LINK(struct rbtdb_version) link;
} rbtdb_version_t;
};
#endif
+typedef enum {
+ dns_db_insecure,
+ dns_db_partial,
+ dns_db_secure
+} dns_db_secure_t;
+
typedef struct {
/* Unlocked. */
dns_db_t common;
/* Locked by tree_lock. */
dns_rbt_t * tree;
- isc_boolean_t secure;
+ dns_db_secure_t secure;
/* Unlocked */
unsigned int quantum;
isc_stdtime_t now);
static void check_stale_cache(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode,
isc_stdtime_t now, isc_boolean_t tree_locked);
+static isc_result_t resign_insert(dns_rbtdb_t *rbtdb, int idx,
+ rdatasetheader_t *newheader);
static dns_rdatasetmethods_t rdataset_methods = {
rdataset_disassociate,
oldttl = header->rdh_ttl;
header->rdh_ttl = newttl;
+ if (!IS_CACHE(rbtdb))
+ return;
+
/*
* It's possible the rbtdb is not a cache. If this is the case,
* we will not have a heap, and we move on. If we do, though,
}
/*%
- * This function allows the heap code to rank the priority of each
+ * These functions allows the heap code to rank the priority of each
* element. It returns ISC_TRUE if v1 happens "sooner" than v2.
*/
static isc_boolean_t
return (ISC_FALSE);
}
+static isc_boolean_t
+resign_sooner(void *v1, void *v2) {
+ rdatasetheader_t *h1 = v1;
+ rdatasetheader_t *h2 = v2;
+
+ if (h1->resign < h2->resign)
+ return (ISC_TRUE);
+ return (ISC_FALSE);
+}
+
/*%
* This function sets the heap index into the header.
*/
static void
-ttl_set_index(void *what, unsigned int index) {
+set_index(void *what, unsigned int index) {
rdatasetheader_t *h = what;
h->heap_index = index;
}
/*
- * Clean up LRU cache objects.
+ * Clean up LRU / re-signing order lists.
*/
if (rbtdb->rdatasets != NULL) {
for (i = 0; i < rbtdb->node_lock_count; i++)
rbtdb->node_lock_count * sizeof(rbtnodelist_t));
}
/*
- * Clean up TTL heap cache objects.
+ * Clean up heap objects.
*/
if (rbtdb->heaps != NULL) {
for (i = 0; i < rbtdb->node_lock_count; i++)
version->writer = writer;
version->commit_ok = ISC_FALSE;
ISC_LIST_INIT(version->changed_list);
+ ISC_LIST_INIT(version->resigned_list);
ISC_LINK_INIT(version, link);
return (version);
free_rdataset(dns_rbtdb_t *rbtdb, isc_mem_t *mctx, rdatasetheader_t *rdataset)
{
unsigned int size;
+ int idx;
#ifdef LRU_DEBUG
/*
}
#endif
- if (IS_CACHE(rbtdb) && ISC_LINK_LINKED(rdataset, lru_link)) {
- int idx = rdataset->node->locknum;
+ idx = rdataset->node->locknum;
+ if (ISC_LINK_LINKED(rdataset, lru_link))
ISC_LIST_UNLINK(rbtdb->rdatasets[idx], rdataset, lru_link);
- if (rdataset->heap_index != 0) {
- isc_heap_delete(rbtdb->heaps[idx],
- rdataset->heap_index);
- }
- rdataset->heap_index = 0;
- }
+ if (rdataset->heap_index != 0)
+ isc_heap_delete(rbtdb->heaps[idx], rdataset->heap_index);
+ rdataset->heap_index = 0;
if (rdataset->noqname != NULL)
free_noqname(mctx, &rdataset->noqname);
}
}
-static isc_boolean_t
+static dns_db_secure_t
iszonesecure(dns_db_t *db, dns_dbnode_t *origin) {
dns_rdataset_t keyset;
dns_rdataset_t nsecset, signsecset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
isc_boolean_t haszonekey = ISC_FALSE;
isc_boolean_t hasnsec = ISC_FALSE;
+ isc_boolean_t hasoptbit = ISC_FALSE;
isc_result_t result;
dns_rdataset_init(&keyset);
dns_rdataset_disassociate(&keyset);
}
if (!haszonekey)
- return (ISC_FALSE);
+ return (dns_db_insecure);
dns_rdataset_init(&nsecset);
dns_rdataset_init(&signsecset);
if (result == ISC_R_SUCCESS) {
if (dns_rdataset_isassociated(&signsecset)) {
hasnsec = ISC_TRUE;
+ result = dns_rdataset_first(&nsecset);
+ if (result == ISC_R_SUCCESS) {
+ dns_rdataset_current(&nsecset, &rdata);
+ hasoptbit = dns_nsec_typepresent(&rdata,
+ dns_rdatatype_opt);
+ }
dns_rdataset_disassociate(&signsecset);
}
dns_rdataset_disassociate(&nsecset);
}
- return (hasnsec);
+
+ if (hasnsec && hasoptbit)
+ return (dns_db_partial);
+ return (hasnsec ? dns_db_secure : dns_db_insecure);
}
static void
rbtdb_version_t *version, *cleanup_version, *least_greater;
isc_boolean_t rollback = ISC_FALSE;
rbtdb_changedlist_t cleanup_list;
+ rdatasetheaderlist_t resigned_list;
rbtdb_changed_t *changed, *next_changed;
rbtdb_serial_t serial, least_serial;
dns_rbtnode_t *rbtnode;
unsigned int refs;
+ rdatasetheader_t *header;
isc_boolean_t writer;
REQUIRE(VALID_RBTDB(rbtdb));
cleanup_version = NULL;
ISC_LIST_INIT(cleanup_list);
+ ISC_LIST_INIT(resigned_list);
isc_refcount_decrement(&version->references, &refs);
if (refs > 0) { /* typical and easy case first */
INSIST(cur_ref == 1);
PREPEND(rbtdb->open_versions,
rbtdb->current_version, link);
+ resigned_list = version->resigned_list;
+ ISC_LIST_INIT(version->resigned_list);
} else {
/*
* We're rolling back this transaction.
*/
cleanup_list = version->changed_list;
ISC_LIST_INIT(version->changed_list);
+ resigned_list = version->resigned_list;
+ ISC_LIST_INIT(version->resigned_list);
rollback = ISC_TRUE;
cleanup_version = version;
rbtdb->future_version = NULL;
sizeof(*cleanup_version));
}
+ /*
+ * Commit/rollback re-signed headers.
+ */
+ for (header = HEAD(resigned_list);
+ header != NULL;
+ header = HEAD(resigned_list)) {
+ ISC_LIST_UNLINK(resigned_list, header, lru_link);
+ if (rollback) {
+ nodelock_t *lock;
+ lock = &rbtdb->node_locks[header->node->locknum].lock;
+ NODE_LOCK(lock, isc_rwlocktype_write);
+ resign_insert(rbtdb, header->node->locknum, header);
+ NODE_UNLOCK(lock, isc_rwlocktype_write);
+ }
+ decrement_reference(rbtdb, header->node, least_serial,
+ isc_rwlocktype_write,
+ isc_rwlocktype_none);
+ }
+
if (!EMPTY(cleanup_list)) {
/*
* We acquire a tree write lock here in order to make sure
rdataset->private6 = header->noqname;
if (rdataset->private6 != NULL)
rdataset->attributes |= DNS_RDATASETATTR_NOQNAME;
+ /*
+ * Copy out re-signing information.
+ */
+ if (RESIGN(header)) {
+ rdataset->attributes |= DNS_RDATASETATTR_RESIGN;
+ rdataset->resign = header->resign;
+ } else
+ rdataset->resign = 0;
}
static inline isc_result_t
* If we're here, then the name does not exist, is not
* beneath a zonecut, and there's no matching wildcard.
*/
- if (search.rbtdb->secure ||
+ if (search.rbtdb->secure == dns_db_secure ||
(search.options & DNS_DBFIND_FORCENSEC) != 0)
{
result = find_closest_nsec(&search, nodep, foundname,
- rdataset, sigrdataset,
- search.rbtdb->secure);
+ rdataset, sigrdataset,
+ ISC_TRUE);
if (result == ISC_R_SUCCESS)
result = active ? DNS_R_EMPTYNAME :
DNS_R_NXDOMAIN;
* The desired type doesn't exist.
*/
result = DNS_R_NXRRSET;
- if (search.rbtdb->secure &&
+ if (search.rbtdb->secure == dns_db_secure &&
(nsecheader == NULL || nsecsig == NULL)) {
/*
* The zone is secure but there's no NSEC,
NODE_UNLOCK(lock, isc_rwlocktype_read);
result = find_closest_nsec(&search, nodep, foundname,
rdataset, sigrdataset,
- search.rbtdb->secure);
+ search.rbtdb->secure ==
+ dns_db_secure);
if (result == ISC_R_SUCCESS)
result = DNS_R_EMPTYWILD;
goto tree_exit;
new_reference(search.rbtdb, node);
*nodep = node;
}
- if (search.rbtdb->secure ||
+ if (search.rbtdb->secure == dns_db_secure ||
(search.options & DNS_DBFIND_FORCENSEC) != 0)
{
bind_rdataset(search.rbtdb, node, nsecheader,
first = ISC_FALSE;
fprintf(out,
"\tserial = %lu, ttl = %u, "
- "trust = %u, attributes = %u\n",
+ "trust = %u, attributes = %u, "
+ "resign = %u\n",
(unsigned long)current->serial,
current->rdh_ttl,
current->trust,
- current->attributes);
+ current->attributes,
+ current->resign);
current = current->down;
} while (current != NULL);
}
}
#endif
+static isc_result_t
+resign_insert(dns_rbtdb_t *rbtdb, int idx, rdatasetheader_t *newheader) {
+ isc_result_t result;
+
+ INSIST(newheader->heap_index == 0);
+ INSIST(!ISC_LINK_LINKED(newheader, lru_link));
+ result = isc_heap_insert(rbtdb->heaps[idx], newheader);
+ return (result);
+}
+
static isc_result_t
add(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, rbtdb_version_t *rbtversion,
rdatasetheader_t *newheader, unsigned int options, isc_boolean_t loading,
dns_rdatatype_t rdtype, covers;
rbtdb_rdatatype_t negtype;
dns_trust_t trust;
+ int idx;
/*
* Add an rdatasetheader_t to a node.
free_rdataset(rbtdb, rbtdb->common.mctx,
newheader);
newheader = (rdatasetheader_t *)merged;
+ if (loading && RESIGN(newheader) &&
+ RESIGN(header) &&
+ header->resign < newheader->resign)
+ newheader->resign = header->resign;
} else {
free_rdataset(rbtdb, rbtdb->common.mctx,
newheader);
set_ttl(rbtdb, header, 0);
header->attributes |= RDATASET_ATTR_STALE;
}
+ idx = newheader->node->locknum;
if (IS_CACHE(rbtdb)) {
- int idx = newheader->node->locknum;
-
ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
newheader, lru_link);
-
/*
* XXXMLG We don't check the return value
* here. If it fails, we will not do TTL
* will not leak... for long.
*/
isc_heap_insert(rbtdb->heaps[idx], newheader);
- }
#ifdef LRU_DEBUG
- cachestat_update(rbtdb, newheader);
+ cachestat_update(rbtdb, newheader);
#endif
- }
- } else {
- /*
- * No non-IGNORED rdatasets of the given type exist at
- * this node.
- */
+ } else if (RESIGN(newheader))
+ resign_insert(rbtdb, idx, newheader);
+ }
+ } else {
+ /*
+ * No non-IGNORED rdatasets of the given type exist at
+ * this node.
+ */
/*
* If we're trying to delete the type, don't bother.
newheader->down = NULL;
rbtnode->data = newheader;
}
+ idx = newheader->node->locknum;
if (IS_CACHE(rbtdb)) {
- int idx = newheader->node->locknum;
ISC_LIST_PREPEND(rbtdb->rdatasets[idx],
newheader, lru_link);
isc_heap_insert(rbtdb->heaps[idx], newheader);
- }
#ifdef LRU_DEBUG
- cachestat_update(rbtdb, newheader);
+ cachestat_update(rbtdb, newheader);
#endif
+ } else if (RESIGN(newheader)) {
+ resign_insert(rbtdb, idx, newheader);
+ }
}
/*
if (rbtversion != NULL) {
newheader->serial = rbtversion->serial;
now = 0;
+ if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
+ newheader->attributes |= RDATASET_ATTR_RESIGN;
+ newheader->resign = rdataset->resign;
+ } else
+ newheader->resign = 0;
} else {
newheader->serial = 1;
+ newheader->resign = 0;
if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
newheader->attributes |= RDATASET_ATTR_NXDOMAIN;
if ((rdataset->attributes & DNS_RDATASETATTR_NOQNAME) != 0) {
newheader->additional_glue = NULL;
newheader->last_used = 0;
newheader->node = rbtnode;
+ if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
+ newheader->attributes |= RDATASET_ATTR_RESIGN;
+ newheader->resign = rdataset->resign;
+ } else
+ newheader->resign = 0;
NODE_LOCK(&rbtdb->node_locks[rbtnode->locknum].lock,
isc_rwlocktype_write);
if (result == ISC_R_SUCCESS) {
free_rdataset(rbtdb, rbtdb->common.mctx, newheader);
newheader = (rdatasetheader_t *)subresult;
+ init_rdataset(rbtdb, newheader);
/*
* We have to set the serial since the rdataslab
* subtraction routine copies the reserved portion of
newheader->count = init_count++;
newheader->additional_auth = NULL;
newheader->additional_glue = NULL;
- /* won't be used, but initialize anyway */
newheader->last_used = 0;
newheader->node = node;
+ if ((rdataset->attributes & DNS_RDATASETATTR_RESIGN) != 0) {
+ newheader->attributes |= RDATASET_ATTR_RESIGN;
+ newheader->resign = rdataset->resign;
+ } else
+ newheader->resign = 0;
result = add(rbtdb, node, rbtdb->current_version, newheader,
DNS_DBADD_MERGE, ISC_TRUE, NULL, 0);
REQUIRE(VALID_RBTDB(rbtdb));
RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
- secure = rbtdb->secure;
+ secure = ISC_TF(rbtdb->secure == dns_db_secure);
RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
return (secure);
}
+static isc_boolean_t
+isdnssec(dns_db_t *db) {
+ dns_rbtdb_t *rbtdb;
+ isc_boolean_t dnssec;
+
+ rbtdb = (dns_rbtdb_t *)db;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ RWLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+ dnssec = ISC_TF(rbtdb->secure != dns_db_insecure);
+ RWUNLOCK(&rbtdb->tree_lock, isc_rwlocktype_read);
+
+ return (dnssec);
+}
+
static unsigned int
nodecount(dns_db_t *db) {
dns_rbtdb_t *rbtdb;
return (result);
}
+static isc_result_t
+setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) {
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ isc_stdtime_t oldresign;
+ isc_result_t result = ISC_R_SUCCESS;
+ rdatasetheader_t *header;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(!IS_CACHE(rbtdb));
+ REQUIRE(rdataset != NULL);
+
+ header = rdataset->private3;
+ header--;
+
+ NODE_LOCK(&rbtdb->node_locks[header->node->locknum].lock,
+ isc_rwlocktype_write);
+
+ oldresign = header->resign;
+ header->resign = resign;
+ if (header->heap_index != 0) {
+ INSIST(RESIGN(header));
+ if (resign == 0) {
+ isc_heap_delete(rbtdb->heaps[header->node->locknum],
+ header->heap_index);
+ header->heap_index = 0;
+ } else if (resign < oldresign)
+ isc_heap_increased(rbtdb->heaps[header->node->locknum],
+ header->heap_index);
+ else
+ isc_heap_decreased(rbtdb->heaps[header->node->locknum],
+ header->heap_index);
+ } else if (resign && header->heap_index == 0) {
+ header->attributes |= RDATASET_ATTR_RESIGN;
+ result = resign_insert(rbtdb, header->node->locknum, header);
+ }
+ NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock,
+ isc_rwlocktype_write);
+ return (result);
+}
+
+static isc_result_t
+getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
+ dns_name_t *foundname)
+{
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ rdatasetheader_t *header = NULL, *this;
+ unsigned int i;
+ isc_result_t result = ISC_R_NOTFOUND;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+
+ for (i = 0; i < rbtdb->node_lock_count; i++) {
+ this = isc_heap_element(rbtdb->heaps[i], 1);
+ if (this == NULL)
+ continue;
+ if (header == NULL)
+ header = this;
+ else if (isc_serial_lt(this->resign, header->resign))
+ header = this;
+ }
+
+ if (header == NULL)
+ goto unlock;
+
+ NODE_LOCK(&rbtdb->node_locks[header->node->locknum].lock,
+ isc_rwlocktype_read);
+
+ bind_rdataset(rbtdb, header->node, header, 0, rdataset);
+
+ if (foundname != NULL)
+ dns_rbt_fullnamefromnode(header->node, foundname);
+
+ NODE_UNLOCK(&rbtdb->node_locks[header->node->locknum].lock,
+ isc_rwlocktype_read);
+
+ result = ISC_R_SUCCESS;
+
+ unlock:
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
+
+ return (result);
+}
+
+static void
+resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version)
+{
+ rbtdb_version_t *rbtversion = (rbtdb_version_t *)version;
+ dns_rbtdb_t *rbtdb = (dns_rbtdb_t *)db;
+ dns_rbtnode_t *node;
+ rdatasetheader_t *header;
+
+ REQUIRE(VALID_RBTDB(rbtdb));
+ REQUIRE(rdataset != NULL);
+ REQUIRE(rbtdb->future_version == rbtversion);
+ REQUIRE(rbtversion->writer);
+
+ node = rdataset->private2;
+ header = rdataset->private3;
+ header--;
+
+ RBTDB_LOCK(&rbtdb->lock, isc_rwlocktype_read);
+ NODE_LOCK(&rbtdb->node_locks[node->locknum].lock,
+ isc_rwlocktype_write);
+ /*
+ * Delete from heap and save to re-signed list so that it can
+ * be restored if we backout of this change.
+ */
+ new_reference(rbtdb, node);
+ isc_heap_delete(rbtdb->heaps[node->locknum], header->heap_index);
+ header->heap_index = 0;
+ ISC_LIST_APPEND(rbtversion->resigned_list, header, lru_link);
+
+ NODE_UNLOCK(&rbtdb->node_locks[node->locknum].lock,
+ isc_rwlocktype_write);
+ RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_read);
+}
+
static dns_dbmethods_t zone_methods = {
attach,
detach,
settask,
getoriginnode,
NULL,
+ setsigningtime,
+ getsigningtime,
+ resigned,
+ isdnssec,
};
static dns_dbmethods_t cache_methods = {
overmem,
settask,
getoriginnode,
- NULL
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ isdnssec
};
isc_result_t
}
for (i = 0; i < (int)rbtdb->node_lock_count; i++)
ISC_LIST_INIT(rbtdb->rdatasets[i]);
-
- /*
- * Create the heaps.
- */
- rbtdb->heaps = isc_mem_get(mctx, rbtdb->node_lock_count *
- sizeof(isc_heap_t *));
- if (rbtdb->heaps == NULL) {
- result = ISC_R_NOMEMORY;
- goto cleanup_rdatasets;
- }
- for (i = 0; i < (int)rbtdb->node_lock_count; i++)
- rbtdb->heaps[i] = NULL;
- for (i = 0; i < (int)rbtdb->node_lock_count; i++) {
- result = isc_heap_create(mctx, ttl_sooner,
- ttl_set_index, 0,
- &rbtdb->heaps[i]);
- if (result != ISC_R_SUCCESS)
- goto cleanup_heaps;
- }
} else {
rbtdb->rdatasets = NULL;
- rbtdb->heaps = NULL;
+ }
+
+ /*
+ * Create the heaps.
+ */
+ rbtdb->heaps = isc_mem_get(mctx, rbtdb->node_lock_count *
+ sizeof(isc_heap_t *));
+ if (rbtdb->heaps == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup_rdatasets;
+ }
+ for (i = 0; i < (int)rbtdb->node_lock_count; i++)
+ rbtdb->heaps[i] = NULL;
+
+ for (i = 0; i < (int)rbtdb->node_lock_count; i++) {
+ if (IS_CACHE(rbtdb))
+ result = isc_heap_create(mctx, ttl_sooner, set_index,
+ 0, &rbtdb->heaps[i]);
+ else
+ result = isc_heap_create(mctx, resign_sooner,
+ set_index, 0,
+ &rbtdb->heaps[i]);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup_heaps;
}
rbtdb->deadnodes = isc_mem_get(mctx, rbtdb->node_lock_count *
return (result);
}
rbtdb->attributes = 0;
- rbtdb->secure = ISC_FALSE;
+ rbtdb->secure = dns_db_insecure;
rbtdb->overmem = ISC_FALSE;
rbtdb->task = NULL;
#if DNS_RDATASET_FIXED
unsigned int offset;
#endif
+ unsigned int length;
isc_region_t r;
+ unsigned int flags = 0;
REQUIRE(raw != NULL);
raw += offset;
}
#endif
- r.length = raw[0] * 256 + raw[1];
-
+ length = raw[0] * 256 + raw[1];
#if DNS_RDATASET_FIXED
raw += 4;
#else
raw += 2;
#endif
+ if (rdataset->type == dns_rdatatype_rrsig) {
+ flags = ((*raw & DNS_RDATASLAB_WARNMASK)
+ >> DNS_RDATASLAB_WARNSHIFT)
+ << DNS_RDATA_WARNSHIFT;
+ if (*raw & DNS_RDATASLAB_OFFLINE)
+ flags |= DNS_RDATA_OFFLINE;
+ length--;
+ raw++;
+ }
+ r.length = length;
r.base = raw;
dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+ rdata->flags |= flags;
}
static void
update_header(dns_rbtdb_t *rbtdb, rdatasetheader_t *header,
isc_stdtime_t now)
{
+ INSIST(IS_CACHE(rbtdb));
+
/* To be checked: can we really assume this? XXXMLG */
INSIST(ISC_LINK_LINKED(header, lru_link));
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdata.c,v 1.196 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: rdata.c,v 1.197 2008/04/01 01:37:25 marka Exp $ */
/*! \file */
/* ISC_LIST_INIT(rdata->list); */
}
-#if 0
+#if 1
#define DNS_RDATA_INITIALIZED(rdata) \
((rdata)->data == NULL && (rdata)->length == 0 && \
(rdata)->rdclass == 0 && (rdata)->type == 0 && (rdata)->flags == 0 && \
#define DNS_RDATA_INITIALIZED(rdata) ISC_TRUE
#endif
#endif
+
#define DNS_RDATA_VALIDFLAGS(rdata) \
- (((rdata)->flags & ~DNS_RDATA_UPDATE) == 0)
+ (((rdata)->flags & ~(DNS_RDATA_UPDATE|DNS_RDATA_OFFLINE)) == 0)
void
dns_rdata_reset(dns_rdata_t *rdata) {
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdataset.c,v 1.79 2007/06/19 23:47:16 tbox Exp $ */
+/* $Id: rdataset.c,v 1.80 2008/04/01 01:37:25 marka Exp $ */
/*! \file */
rdataset->privateuint4 = 0;
rdataset->private5 = NULL;
rdataset->private6 = NULL;
+ rdataset->resign = 0;
}
void
isc_result_t
dns_rdataset_getnoqname(dns_rdataset_t *rdataset, dns_name_t *name,
- dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
+ dns_rdataset_t *nsec, dns_rdataset_t *nsecsig)
{
REQUIRE(DNS_RDATASET_VALID(rdataset));
REQUIRE(rdataset->methods != NULL);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rdataslab.c,v 1.43 2007/06/18 23:47:41 tbox Exp $ */
+/* $Id: rdataslab.c,v 1.44 2008/04/01 01:37:25 marka Exp $ */
/*! \file */
* data records
* data length (2 bytes)
* order (2 bytes)
+ * meta data (1 byte for RRSIG's)
* data (data length bytes)
*
* If DNS_RDATASET_FIXED is defined to be zero (0) the format of a
#if DNS_RDATASET_FIXED
unsigned int *offsettable;
#endif
+ unsigned int length;
buflen = reservelen + 2;
#if DNS_RDATASET_FIXED
x[i].order = i;
#endif
+ if (x[i].rdata.flags & DNS_RDATA_OFFLINE)
+ fprintf(stderr, "OFFLINE\n");
result = dns_rdataset_next(rdataset);
}
if (result != ISC_R_NOMORE)
x[i].order = x[i-1].order;
#endif
nitems--;
- } else
+ } else {
#if DNS_RDATASET_FIXED
buflen += (8 + x[i-1].rdata.length);
#else
buflen += (2 + x[i-1].rdata.length);
#endif
+ /*
+ * Provide space to store the per RR meta data.
+ */
+ if (rdataset->type == dns_rdatatype_rrsig)
+ buflen++;
+ }
}
/*
* Don't forget the last item!
#else
buflen += (2 + x[i-1].rdata.length);
#endif
+ /*
+ * Provide space to store the per RR meta data.
+ */
+ if (rdataset->type == dns_rdatatype_rrsig)
+ buflen++;
/*
* Ensure that singleton types are actually singletons.
#if DNS_RDATASET_FIXED
offsettable[x[i].order] = rawbuf - offsetbase;
#endif
- *rawbuf++ = (x[i].rdata.length & 0xff00) >> 8;
- *rawbuf++ = (x[i].rdata.length & 0x00ff);
+ length = x[i].rdata.length;
+ if (rdataset->type == dns_rdatatype_rrsig)
+ length++;
+ *rawbuf++ = (length & 0xff00) >> 8;
+ *rawbuf++ = (length & 0x00ff);
#if DNS_RDATASET_FIXED
rawbuf += 2; /* filled in later */
#endif
+ /*
+ * Store the per RR meta data.
+ */
+ if (rdataset->type == dns_rdatatype_rrsig) {
+ *rawbuf = ((x[i].rdata.flags & DNS_RDATA_WARNMASK)
+ >> DNS_RDATA_WARNSHIFT)
+ << DNS_RDATASLAB_WARNSHIFT;
+ *rawbuf++ |= (x[i].rdata.flags & DNS_RDATA_OFFLINE) ?
+ DNS_RDATASLAB_OFFLINE : 0;
+ if (x[i].rdata.flags & DNS_RDATA_OFFLINE)
+ fprintf(stderr, "set DNS_RDATASLAB_OFFLINE\n");
+ }
memcpy(rawbuf, x[i].rdata.data, x[i].rdata.length);
rawbuf += x[i].rdata.length;
}
rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
unsigned char *raw = rdataset->private5;
isc_region_t r;
+ unsigned int length;
+ unsigned int flags = 0;
REQUIRE(raw != NULL);
- r.length = raw[0] * 256 + raw[1];
+ length = raw[0] * 256 + raw[1];
#if DNS_RDATASET_FIXED
raw += 4;
#else
raw += 2;
#endif
+ if (rdataset->type == dns_rdatatype_rrsig) {
+ flags = ((*raw & DNS_RDATASLAB_WARNMASK)
+ >> DNS_RDATASLAB_WARNSHIFT)
+ << DNS_RDATA_WARNSHIFT;
+ if (*raw & DNS_RDATASLAB_OFFLINE)
+ flags |= DNS_RDATA_OFFLINE;
+ length--;
+ raw++;
+ }
+ r.length = length;
r.base = raw;
dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
+ rdata->flags |= flags;
}
static void
{
unsigned char *tcurrent = *current;
isc_region_t region;
+ unsigned int length;
+ isc_boolean_t offline = ISC_FALSE;
- region.length = *tcurrent++ * 256;
- region.length += *tcurrent++;
+ length = *tcurrent++ * 256;
+ length += *tcurrent++;
+
+ if (type == dns_rdatatype_rrsig) {
+ if ((*tcurrent & DNS_RDATASLAB_OFFLINE) != 0)
+ offline = ISC_TRUE;
+ length--;
+ tcurrent++;
+ }
+ region.length = length;
#if DNS_RDATASET_FIXED
tcurrent += 2;
#endif
region.base = tcurrent;
tcurrent += region.length;
dns_rdata_fromregion(rdata, rdclass, type, ®ion);
+ if (offline) {
+ rdata->flags |= DNS_RDATA_OFFLINE;
+ fprintf(stderr, "rdata_from_slab: DNS_RDATA_OFFLINE\n");
+ }
*current = tcurrent;
}
dns_rdataclass_t rdclass, dns_rdatatype_t type,
unsigned int flags, unsigned char **tslabp)
{
- unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent;
+ unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent, *data;
unsigned int ocount, ncount, count, olength, tlength, tcount, length;
- isc_region_t nregion;
dns_rdata_t ordata = DNS_RDATA_INIT;
dns_rdata_t nrdata = DNS_RDATA_INIT;
isc_boolean_t added_something = ISC_FALSE;
* the old slab.
*/
do {
- nregion.length = *ncurrent++ * 256;
- nregion.length += *ncurrent++;
-#if DNS_RDATASET_FIXED
- ncurrent += 2; /* Skip order. */
-#endif
- nregion.base = ncurrent;
dns_rdata_init(&nrdata);
- dns_rdata_fromregion(&nrdata, rdclass, type, &nregion);
+ rdata_from_slab(&ncurrent, rdclass, type, &nrdata);
if (!rdata_in_slab(oslab, reservelen, rdclass, type, &nrdata))
{
/*
* This rdata isn't in the old slab.
*/
#if DNS_RDATASET_FIXED
- tlength += nregion.length + 8;
+ tlength += nrdata.length + 8;
#else
- tlength += nregion.length + 2;
+ tlength += nrdata.length + 2;
#endif
+ if (type == dns_rdatatype_rrsig)
+ tlength++;
tcount++;
nncount++;
added_something = ISC_TRUE;
}
- ncurrent += nregion.length;
ncount--;
} while (ncount > 0);
ncount = nncount;
offsettable[oorder] = tcurrent - offsetbase;
#endif
length = ordata.length;
+ data = ordata.data;
+ if (type == dns_rdatatype_rrsig) {
+ length++;
+ data--;
+ }
*tcurrent++ = (length & 0xff00) >> 8;
*tcurrent++ = (length & 0x00ff);
#if DNS_RDATASET_FIXED
tcurrent += 2; /* fill in later */
#endif
- memcpy(tcurrent, ordata.data, length);
+ memcpy(tcurrent, data, length);
tcurrent += length;
oadded++;
if (oadded < ocount) {
offsettable[ocount + norder] = tcurrent - offsetbase;
#endif
length = nrdata.length;
+ data = nrdata.data;
+ if (type == dns_rdatatype_rrsig) {
+ length++;
+ data--;
+ }
*tcurrent++ = (length & 0xff00) >> 8;
*tcurrent++ = (length & 0x00ff);
#if DNS_RDATASET_FIXED
tcurrent += 2; /* fill in later */
#endif
- memcpy(tcurrent, nrdata.data, length);
+ memcpy(tcurrent, data, length);
tcurrent += length;
nadded++;
if (nadded < ncount) {
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: rootns.c,v 1.34 2008/02/05 23:47:08 tbox Exp $ */
+/* $Id: rootns.c,v 1.35 2008/04/01 01:37:25 marka Exp $ */
/*! \file */
if (dns_name_compare(name, &ns.name) == 0)
return (ISC_R_SUCCESS);
result = dns_rdataset_next(rootns);
+ dns_rdata_reset(&rdata);
}
if (result == ISC_R_NOMORE)
result = ISC_R_NOTFOUND;
(rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
result = dns_rdataset_first(&rootrrset);
while (result == ISC_R_SUCCESS) {
+ dns_rdata_reset(&rdata);
dns_rdataset_current(&rootrrset, &rdata);
if (!inrrset(&hintrrset, &rdata))
report(view, name, ISC_TRUE, &rdata);
}
result = dns_rdataset_first(&hintrrset);
while (result == ISC_R_SUCCESS) {
+ dns_rdata_reset(&rdata);
dns_rdataset_current(&hintrrset, &rdata);
if (!inrrset(&rootrrset, &rdata))
report(view, name, ISC_FALSE, &rdata);
(rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
result = dns_rdataset_first(&rootrrset);
while (result == ISC_R_SUCCESS) {
+ dns_rdata_reset(&rdata);
dns_rdataset_current(&rootrrset, &rdata);
report(view, name, ISC_TRUE, &rdata);
result = dns_rdataset_next(&rootrrset);
(rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
result = dns_rdataset_first(&rootrrset);
while (result == ISC_R_SUCCESS) {
+ dns_rdata_reset(&rdata);
dns_rdataset_current(&rootrrset, &rdata);
if (!inrrset(&hintrrset, &rdata))
report(view, name, ISC_TRUE, &rdata);
}
result = dns_rdataset_first(&hintrrset);
while (result == ISC_R_SUCCESS) {
+ dns_rdata_reset(&rdata);
dns_rdataset_current(&hintrrset, &rdata);
if (!inrrset(&rootrrset, &rdata))
report(view, name, ISC_FALSE, &rdata);
(rresult == ISC_R_SUCCESS || rresult == DNS_R_GLUE)) {
result = dns_rdataset_first(&rootrrset);
while (result == ISC_R_SUCCESS) {
+ dns_rdata_reset(&rdata);
dns_rdataset_current(&rootrrset, &rdata);
report(view, name, ISC_TRUE, &rdata);
dns_rdata_reset(&rdata);
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: sdb.c,v 1.62 2008/01/18 23:46:58 tbox Exp $ */
+/* $Id: sdb.c,v 1.63 2008/04/01 01:37:25 marka Exp $ */
/*! \file */
overmem,
settask,
NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
NULL
};
* USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: sdlz.c,v 1.14 2007/08/27 03:32:27 marka Exp $ */
+/* $Id: sdlz.c,v 1.15 2008/04/01 01:37:25 marka Exp $ */
/*! \file */
overmem,
settask,
NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
NULL
};
*/
/*
- * $Id: tsig.c,v 1.133 2008/01/18 23:46:58 tbox Exp $
+ * $Id: tsig.c,v 1.134 2008/04/01 01:37:25 marka Exp $
*/
/*! \file */
#include <config.h>
dns_rbtnodechain_current(&chain, &foundname, origin, &node);
tkey = node->data;
if (tkey != NULL) {
- tsig_log(tkey, 2, "tsig expire: generated=%d, refs=%d, expire=%d)", tkey->generated, isc_refcount_current(&tkey->refs), now - tkey->expire);
+ tsig_log(tkey, 2, "tsig expire: generated=%d, refs=%d, expire=%d", tkey->generated, isc_refcount_current(&tkey->refs), now - tkey->expire);
if (tkey->generated
&& isc_refcount_current(&tkey->refs) == 1
&& tkey->inception != tkey->expire
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: zone.c,v 1.472 2008/01/24 23:47:00 tbox Exp $ */
+/* $Id: zone.c,v 1.473 2008/04/01 01:37:25 marka Exp $ */
/*! \file */
#include <isc/refcount.h>
#include <isc/rwlock.h>
#include <isc/serial.h>
+#include <isc/stdtime.h>
#include <isc/string.h>
#include <isc/taskpool.h>
#include <isc/timer.h>
#include <dns/callbacks.h>
#include <dns/db.h>
#include <dns/dbiterator.h>
+#include <dns/dnssec.h>
#include <dns/events.h>
#include <dns/journal.h>
+#include <dns/keyvalues.h>
#include <dns/log.h>
#include <dns/master.h>
#include <dns/masterdump.h>
#include <dns/message.h>
#include <dns/name.h>
+#include <dns/nsec.h>
#include <dns/peer.h>
#include <dns/rcode.h>
#include <dns/rdataclass.h>
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
+#include <dns/rdatasetiter.h>
#include <dns/rdatastruct.h>
#include <dns/rdatatype.h>
#include <dns/request.h>
#include <dns/resolver.h>
#include <dns/result.h>
-#include <dns/stats.h>
+#include <dns/soa.h>
#include <dns/ssu.h>
+#include <dns/stats.h>
#include <dns/tsig.h>
#include <dns/xfrin.h>
#include <dns/zone.h>
+#include <dst/dst.h>
+
#define ZONE_MAGIC ISC_MAGIC('Z', 'O', 'N', 'E')
#define DNS_ZONE_VALID(zone) ISC_MAGIC_VALID(zone, ZONE_MAGIC)
typedef struct dns_forward dns_forward_t;
typedef struct dns_io dns_io_t;
typedef ISC_LIST(dns_io_t) dns_iolist_t;
+typedef struct dns_signing dns_signing_t;
+typedef ISC_LIST(dns_signing_t) dns_signinglist_t;
#define DNS_ZONE_CHECKLOCK
#ifdef DNS_ZONE_CHECKLOCK
isc_time_t dumptime;
isc_time_t loadtime;
isc_time_t notifytime;
+ isc_time_t resigntime;
+ isc_time_t keywarntime;
+ isc_time_t signingtime;
isc_uint32_t serial;
isc_uint32_t refresh;
isc_uint32_t retry;
isc_uint32_t expire;
isc_uint32_t minimum;
+ isc_stdtime_t key_expiry;
char *keydirectory;
isc_uint32_t maxrefresh;
* Serial number for deferred journal compaction.
*/
isc_uint32_t compact_serial;
+ /*%
+ * Keys that are signing the zone for the first time.
+ */
+ ISC_LIST(dns_signing_t) signing;
};
#define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
#define UNREACH_CHACHE_SIZE 10U
#define UNREACH_HOLD_TIME 600 /* 10 minutes */
+#define CHECK(op) \
+ do { result = (op); \
+ if (result != ISC_R_SUCCESS) goto failure; \
+ } while (0)
+
struct dns_unreachable {
isc_sockaddr_t remote;
isc_sockaddr_t local;
isc_event_t *event;
};
+/*%
+ * Hold state for when we are signing a zone with a new
+ * DNSKEY as result of a update.
+ */
+struct dns_signing {
+ unsigned int magic;
+ dns_db_t *db;
+ dns_dbiterator_t *dbiterator;
+ dns_secalg_t algorithm;
+ isc_uint16_t keyid;
+ ISC_LINK(dns_signing_t) link;
+};
+
#define SEND_BUFFER_SIZE 2048
static void zone_settimer(dns_zone_t *, isc_time_t *);
isc_sockaddr_t *remote,
isc_sockaddr_t *local,
isc_time_t *now);
+static isc_result_t zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm,
+ uint16_t keyid);
#define ENTER zone_debuglog(zone, me, 1, "enter")
isc_time_settoepoch(&zone->dumptime);
isc_time_settoepoch(&zone->loadtime);
zone->notifytime = now;
+ isc_time_settoepoch(&zone->resigntime);
+ isc_time_settoepoch(&zone->keywarntime);
+ isc_time_settoepoch(&zone->signingtime);
zone->serial = 0;
zone->refresh = DNS_ZONE_DEFAULTREFRESH;
zone->retry = DNS_ZONE_DEFAULTRETRY;
zone->maxxfrout = MAX_XFER_TIME;
zone->ssutable = NULL;
zone->sigvalidityinterval = 30 * 24 * 3600;
+ zone->sigvalidityinterval = 3600; /* XXMPA */
zone->view = NULL;
zone->acache = NULL;
zone->checkmx = NULL;
zone->notifydelay = 5;
zone->isself = NULL;
zone->isselfarg = NULL;
+ ISC_LIST_INIT(zone->signing);
zone->magic = ZONE_MAGIC;
static void
zone_free(dns_zone_t *zone) {
isc_mem_t *mctx = NULL;
+ dns_signing_t *signing;
REQUIRE(DNS_ZONE_VALID(zone));
REQUIRE(isc_refcount_current(&zone->erefs) == 0);
dns_zonemgr_releasezone(zone->zmgr, zone);
/* Unmanaged objects */
+ for (signing = ISC_LIST_HEAD(zone->signing);
+ signing != NULL;
+ signing = ISC_LIST_HEAD(zone->signing)) {
+ ISC_LIST_UNLINK(zone->signing, signing, link);
+ dns_db_detach(&signing->db);
+ dns_dbiterator_destroy(&signing->dbiterator);
+ isc_mem_put(zone->mctx, signing, sizeof *signing);
+ }
if (zone->masterfile != NULL)
isc_mem_free(zone->mctx, zone->masterfile);
zone->masterfile = NULL;
return (zone_load(zone, DNS_ZONELOADFLAG_NOSTAT));
}
+static unsigned int
+get_master_options(dns_zone_t *zone) {
+ unsigned int options;
+
+ options = DNS_MASTER_ZONE;
+ if (zone->type == dns_zone_slave)
+ options |= DNS_MASTER_SLAVE;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS))
+ options |= DNS_MASTER_CHECKNS;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS))
+ options |= DNS_MASTER_FATALNS;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES))
+ options |= DNS_MASTER_CHECKNAMES;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL))
+ options |= DNS_MASTER_CHECKNAMESFAIL;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX))
+ options |= DNS_MASTER_CHECKMX;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL))
+ options |= DNS_MASTER_CHECKMXFAIL;
+ if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD))
+ options |= DNS_MASTER_CHECKWILDCARD;
+ if (zone->type == dns_zone_master &&
+ (zone->update_acl != NULL || zone->ssutable != NULL))
+ options |= DNS_MASTER_RESIGN;
+ return (options);
+}
+
static void
zone_gotreadhandle(isc_task_t *task, isc_event_t *event) {
dns_load_t *load = event->ev_arg;
if (result == ISC_R_CANCELED)
goto fail;
- options = DNS_MASTER_ZONE;
- if (load->zone->type == dns_zone_slave)
- options |= DNS_MASTER_SLAVE;
- if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNS))
- options |= DNS_MASTER_CHECKNS;
- if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_FATALNS))
- options |= DNS_MASTER_FATALNS;
- if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNAMES))
- options |= DNS_MASTER_CHECKNAMES;
- if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKNAMESFAIL))
- options |= DNS_MASTER_CHECKNAMESFAIL;
- if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMX))
- options |= DNS_MASTER_CHECKMX;
- if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKMXFAIL))
- options |= DNS_MASTER_CHECKMXFAIL;
- if (DNS_ZONE_OPTION(load->zone, DNS_ZONEOPT_CHECKWILDCARD))
- options |= DNS_MASTER_CHECKWILDCARD;
+ options = get_master_options(load->zone);
+
result = dns_master_loadfileinc2(load->zone->masterfile,
dns_db_origin(load->db),
dns_db_origin(load->db),
isc_result_t tresult;
unsigned int options;
- options = DNS_MASTER_ZONE;
+ options = get_master_options(zone);
+
if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_MANYERRORS))
options |= DNS_MASTER_MANYERRORS;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNS))
- options |= DNS_MASTER_CHECKNS;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_FATALNS))
- options |= DNS_MASTER_FATALNS;
- if (zone->type == dns_zone_slave)
- options |= DNS_MASTER_SLAVE;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMES))
- options |= DNS_MASTER_CHECKNAMES;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKNAMESFAIL))
- options |= DNS_MASTER_CHECKNAMESFAIL;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMX))
- options |= DNS_MASTER_CHECKMX;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKMXFAIL))
- options |= DNS_MASTER_CHECKMXFAIL;
- if (DNS_ZONE_OPTION(zone, DNS_ZONEOPT_CHECKWILDCARD))
- options |= DNS_MASTER_CHECKWILDCARD;
if (zone->zmgr != NULL && zone->db != NULL && zone->task != NULL) {
load = isc_mem_get(zone->mctx, sizeof(*load));
}
+static void
+set_signingtime(dns_zone_t *zone) {
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdataset_t rdataset;
+ isc_result_t result;
+
+ result = dns_db_findnode(zone->db, &zone->origin, ISC_FALSE, &node);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ dns_db_currentversion(zone->db, &version);
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(zone->db, node, version,
+ (dns_rdatatype_t)0xffff,
+ dns_rdatatype_none, 0,
+ &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ goto cleanup;
+
+ for (result = dns_rdataset_first(&rdataset);
+ result == ISC_R_SUCCESS;
+ result = dns_rdataset_next(&rdataset))
+ {
+ dns_rdataset_current(&rdataset, &rdata);
+ if (rdata.length != 4 || rdata.data[3] != 0) {
+ dns_rdata_reset(&rdata);
+ continue;
+ }
+
+ result = zone_signwithkey(zone, rdata.data[0],
+ (rdata.data[1] << 8) | rdata.data[2]);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "dns_zone_signwithkey failed: %s",
+ dns_result_totext(result));
+ }
+ dns_rdata_reset(&rdata);
+ }
+ dns_rdataset_disassociate(&rdataset);
+
+ cleanup:
+ if (node != NULL)
+ dns_db_detachnode(zone->db, &node);
+ if (version != NULL)
+ dns_db_closeversion(zone->db, &version, ISC_FALSE);
+
+}
+
+static void
+set_resigntime(dns_zone_t *zone) {
+ dns_rdataset_t rdataset;
+ dns_fixedname_t fixed;
+ char namebuf[DNS_NAME_FORMATSIZE];
+ unsigned int resign;
+ isc_result_t result;
+ isc_uint32_t nanosecs;
+
+ dns_rdataset_init(&rdataset);
+ dns_fixedname_init(&fixed);
+ result = dns_db_getsigningtime(zone->db, &rdataset,
+ dns_fixedname_name(&fixed));
+ if (result != ISC_R_SUCCESS) {
+ isc_time_settoepoch(&zone->resigntime);
+ return;
+ }
+ resign = rdataset.resign;
+fprintf(stderr, "set_resigntime %u\n", resign);
+ dns_name_format(dns_fixedname_name(&fixed), namebuf, sizeof(namebuf));
+ dns_rdataset_disassociate(&rdataset);
+ isc_random_get(&nanosecs);
+ nanosecs %= 1000000000;
+ isc_time_set(&zone->resigntime, resign, nanosecs);
+}
+
static isc_result_t
zone_postload(dns_zone_t *zone, dns_db_t *db, isc_time_t loadtime,
isc_result_t result)
isc_time_t now;
isc_boolean_t needdump = ISC_FALSE;
isc_boolean_t hasinclude = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_HASINCLUDE);
+ unsigned int options;
TIME_NOW(&now);
! DNS_ZONE_OPTION(zone, DNS_ZONEOPT_NOMERGE) &&
! DNS_ZONE_FLAG(zone, DNS_ZONEFLG_LOADED))
{
- result = dns_journal_rollforward(zone->mctx, db,
+ if (zone->type == dns_zone_master &&
+ (zone->update_acl != NULL || zone->ssutable != NULL))
+ options = DNS_JOURNALOPT_RESIGN;
+ else
+ options = 0;
+ result = dns_journal_rollforward(zone->mctx, db, options,
zone->journal);
if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND &&
result != DNS_R_UPTODATE && result != DNS_R_NOJOURNAL &&
zone->loadtime = loadtime;
dns_zone_log(zone, ISC_LOG_DEBUG(1), "loaded");
-
/*
* Obtain ns, soa and cname counts for top of zone.
*/
"zone may fail to transfer "
"to slaves.");
}
+
+ if (zone->type == dns_zone_master &&
+ (zone->update_acl != NULL || zone->ssutable != NULL) &&
+ (zone->sigvalidityinterval / 4) < (3 * refresh) &&
+ dns_db_issecure(db))
+ {
+ dns_zone_log(zone, ISC_LOG_WARNING,
+ "1/4 sig-validity-interval less than "
+ "3 * refresh.");
+ }
+
zone->serial = serial;
zone->refresh = RANGE(refresh,
zone->minrefresh, zone->maxrefresh);
result = ISC_R_SUCCESS;
if (needdump)
zone_needdump(zone, DNS_DUMP_DELAY);
- if (zone->task != NULL)
+ if (zone->task != NULL) {
+ if (zone->type == dns_zone_master) {
+ set_resigntime(zone);
+ set_signingtime(zone);
+ }
zone_settimer(zone, &now);
+ }
if (! dns_db_ispersistent(db))
dns_zone_log(zone, ISC_LOG_INFO, "loaded serial %u%s",
goto unlock;
/*
- * masters must countain count elements!
+ * masters must countain count elements!
+ */
+ new = isc_mem_get(zone->mctx, count * sizeof(*new));
+ if (new == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto unlock;
+ }
+ memcpy(new, masters, count * sizeof(*new));
+
+ /*
+ * Similarly for mastersok.
+ */
+ newok = isc_mem_get(zone->mctx, count * sizeof(*newok));
+ if (newok == NULL) {
+ result = ISC_R_NOMEMORY;
+ isc_mem_put(zone->mctx, new, count * sizeof(*new));
+ goto unlock;
+ };
+ for (i = 0; i < count; i++)
+ newok[i] = ISC_FALSE;
+
+ /*
+ * if keynames is non-NULL, it must contain count elements!
+ */
+ newname = NULL;
+ if (keynames != NULL) {
+ newname = isc_mem_get(zone->mctx, count * sizeof(*newname));
+ if (newname == NULL) {
+ result = ISC_R_NOMEMORY;
+ isc_mem_put(zone->mctx, new, count * sizeof(*new));
+ isc_mem_put(zone->mctx, newok, count * sizeof(*newok));
+ goto unlock;
+ }
+ for (i = 0; i < count; i++)
+ newname[i] = NULL;
+ for (i = 0; i < count; i++) {
+ if (keynames[i] != NULL) {
+ newname[i] = isc_mem_get(zone->mctx,
+ sizeof(dns_name_t));
+ if (newname[i] == NULL)
+ goto allocfail;
+ dns_name_init(newname[i], NULL);
+ result = dns_name_dup(keynames[i], zone->mctx,
+ newname[i]);
+ if (result != ISC_R_SUCCESS) {
+ allocfail:
+ for (i = 0; i < count; i++)
+ if (newname[i] != NULL)
+ dns_name_free(
+ newname[i],
+ zone->mctx);
+ isc_mem_put(zone->mctx, new,
+ count * sizeof(*new));
+ isc_mem_put(zone->mctx, newok,
+ count * sizeof(*newok));
+ isc_mem_put(zone->mctx, newname,
+ count * sizeof(*newname));
+ goto unlock;
+ }
+ }
+ }
+ }
+
+ /*
+ * Everything is ok so attach to the zone.
+ */
+ zone->masters = new;
+ zone->mastersok = newok;
+ zone->masterkeynames = newname;
+ zone->masterscnt = count;
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS);
+
+ unlock:
+ UNLOCK_ZONE(zone);
+ return (result);
+}
+
+isc_result_t
+dns_zone_getdb(dns_zone_t *zone, dns_db_t **dpb) {
+ isc_result_t result = ISC_R_SUCCESS;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (zone->db == NULL)
+ result = DNS_R_NOTLOADED;
+ else
+ dns_db_attach(zone->db, dpb);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+ return (result);
+}
+
+/*
+ * Co-ordinates the starting of routine jobs.
+ */
+
+void
+dns_zone_maintenance(dns_zone_t *zone) {
+ const char me[] = "dns_zone_maintenance";
+ isc_time_t now;
+
+ REQUIRE(DNS_ZONE_VALID(zone));
+ ENTER;
+
+ LOCK_ZONE(zone);
+ TIME_NOW(&now);
+ zone_settimer(zone, &now);
+ UNLOCK_ZONE(zone);
+}
+
+static inline isc_boolean_t
+was_dumping(dns_zone_t *zone) {
+ isc_boolean_t dumping;
+
+ REQUIRE(LOCKED_ZONE(zone));
+
+ dumping = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING);
+ if (!dumping) {
+ DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
+ isc_time_settoepoch(&zone->dumptime);
+ }
+ return (dumping);
+}
+
+#define MAXZONEKEYS 10
+
+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);
+ 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
+increment_soa_serial(dns_db_t *db, dns_dbversion_t *ver,
+ dns_diff_t *diff, isc_mem_t *mctx)
+{
+ dns_difftuple_t *deltuple = NULL;
+ dns_difftuple_t *addtuple = NULL;
+ isc_uint32_t serial;
+ isc_result_t result;
+
+ CHECK(dns_db_createsoatuple(db, ver, mctx, DNS_DIFFOP_DEL, &deltuple));
+ CHECK(dns_difftuple_copy(deltuple, &addtuple));
+ addtuple->op = DNS_DIFFOP_ADD;
+
+ serial = dns_soa_getserial(&addtuple->rdata);
+
+ /* RFC1982 */
+ serial = (serial + 1) & 0xFFFFFFFF;
+ if (serial == 0)
+ serial = 1;
+
+ dns_soa_setserial(serial, &addtuple->rdata);
+ CHECK(do_one_tuple(&deltuple, db, ver, diff));
+ CHECK(do_one_tuple(&addtuple, db, ver, diff));
+ result = ISC_R_SUCCESS;
+
+ failure:
+ if (addtuple != NULL)
+ dns_difftuple_free(&addtuple);
+ if (deltuple != NULL)
+ dns_difftuple_free(&deltuple);
+ return (result);
+}
+
+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));
+}
+
+static isc_boolean_t
+ksk_sanity(dns_db_t *db, dns_dbversion_t *ver) {
+ isc_boolean_t ret = ISC_FALSE;
+ isc_boolean_t have_ksk = ISC_FALSE, have_nonksk = ISC_FALSE;
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_dnskey_t dnskey;
+
+ dns_rdataset_init(&rdataset);
+ CHECK(dns_db_findnode(db, dns_db_origin(db), ISC_FALSE, &node));
+ CHECK(dns_db_findrdataset(db, node, ver, dns_rdatatype_dnskey, 0, 0,
+ &rdataset, NULL));
+ CHECK(dns_rdataset_first(&rdataset));
+ while (result == ISC_R_SUCCESS && (!have_ksk || !have_nonksk)) {
+ dns_rdataset_current(&rdataset, &rdata);
+ CHECK(dns_rdata_tostruct(&rdata, &dnskey, NULL));
+ if ((dnskey.flags & (DNS_KEYFLAG_OWNERMASK|DNS_KEYTYPE_NOAUTH))
+ == DNS_KEYOWNER_ZONE) {
+ if ((dnskey.flags & DNS_KEYFLAG_KSK) != 0)
+ have_ksk = ISC_TRUE;
+ else
+ have_nonksk = ISC_TRUE;
+ }
+ dns_rdata_reset(&rdata);
+ result = dns_rdataset_next(&rdataset);
+ }
+ if (have_ksk && have_nonksk)
+ ret = ISC_TRUE;
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (ret);
+}
+
+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));
+ result = dns_dnssec_findzonekeys2(db, ver, node, dns_db_origin(db),
+ directory, mctx, maxkeys, keys,
+ nkeys);
+ if (result == ISC_R_NOTFOUND)
+ result = ISC_R_SUCCESS;
+ failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+static isc_result_t
+offline(dns_db_t *db, dns_dbversion_t *ver, dns_diff_t *diff, dns_name_t *name,
+ dns_ttl_t ttl, dns_rdata_t *rdata)
+{
+ isc_result_t result;
+
+ if ((rdata->flags & DNS_RDATA_OFFLINE) != 0) {
+fprintf(stderr, "rdata is already marked as offline\n");
+ return (ISC_R_SUCCESS);
+ }
+fprintf(stderr, "mark as offline\n");
+ result = update_one_rr(db, ver, diff, DNS_DIFFOP_DELRESIGN,
+ name, ttl, rdata);
+ if (result != ISC_R_SUCCESS)
+ return (result);
+ rdata->flags |= DNS_RDATA_OFFLINE;
+ result = update_one_rr(db, ver, diff, DNS_DIFFOP_ADDRESIGN,
+ name, ttl, rdata);
+ return (result);
+}
+
+static void
+set_key_expiry_warning(dns_zone_t *zone, isc_stdtime_t when, isc_stdtime_t now)
+{
+ unsigned int delta;
+
+ zone->key_expiry = when;
+ if (when <= now) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "DNSKEY RRSIG(s) have expired");
+ isc_time_settoepoch(&zone->keywarntime);
+ } else if (when < now + 7 * 24 * 3600) {
+ dns_zone_log(zone, ISC_LOG_WARNING,
+ "DNSKEY RRSIG(s) will expire at %u",
+ when); /* XXXMPA convert to date. */
+ delta = when - now;
+ delta--; /* loop prevention */
+ delta /= 24 * 3600; /* to whole days */
+ delta *= 24 * 3600; /* to seconds */
+ isc_time_set(&zone->keywarntime, when - delta, 0);
+ } else {
+ dns_zone_log(zone, ISC_LOG_NOTICE, /* XXMPA ISC_LOG_DEBUG(1) */
+ "setting keywarntime to %u - 7 days",
+ when); /* XXXMPA convert to date. */
+ isc_time_set(&zone->keywarntime, when - 7 * 24 * 3600, 0);
+ }
+}
+
+/*
+ * Delete expired RRsigs and any RRsigs we are about to re-sign.
+ * See also update.c:del_keysigs().
+ */
+static isc_result_t
+del_sigs(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 now)
+{
+ 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;
+ isc_stdtime_t warn = 0, maybe = 0;
+
+ 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, type,
+ (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);
+
+ if (type != dns_rdatatype_dnskey) {
+ result = update_one_rr(db, ver, diff,
+ DNS_DIFFOP_DEL, name,
+ rdataset.ttl, &rdata);
+ dns_rdata_reset(&rdata);
+ if (result != ISC_R_SUCCESS)
+ break;
+ continue;
+ }
+
+ /*
+ * RRSIG(DNSKEY) requires special processing.
+ */
+ found = ISC_FALSE;
+ for (i = 0; i < nkeys; i++) {
+ if (rrsig.keyid == dst_key_id(keys[i])) {
+ found = ISC_TRUE;
+ /*
+ * Mark offline RRSIG(DNSKEY).
+ * We want the earliest offline expire time
+ * iff there is a new offline signature.
+ */
+ if (!dst_key_isprivate(keys[i])) {
+ if (warn != 0 &&
+ warn > rrsig.timeexpire)
+ warn = rrsig.timeexpire;
+ if (rdata.flags & DNS_RDATA_OFFLINE) {
+ if (maybe == 0 ||
+ maybe > rrsig.timeexpire)
+ maybe =
+ rrsig.timeexpire;
+ break;
+ }
+ if (warn == 0)
+ warn = maybe;
+ if (warn == 0 ||
+ warn > rrsig.timeexpire)
+ warn = rrsig.timeexpire;
+ result = offline(db, ver, diff, name,
+ rdataset.ttl, &rdata);
+ 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;
+ if (warn != 0)
+ set_key_expiry_warning(zone, warn, now);
+failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+static isc_result_t
+add_sigs(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_mem_t *mctx, isc_stdtime_t inception,
+ isc_stdtime_t expire, isc_boolean_t check_ksk)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t sig_rdata = DNS_RDATA_INIT;
+ unsigned char data[1024]; /* XXX */
+ isc_buffer_t buffer;
+ unsigned int i;
+
+ dns_rdataset_init(&rdataset);
+ isc_buffer_init(&buffer, data, sizeof(data));
+
+ 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, type, 0,
+ (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 (i = 0; i < nkeys; i++) {
+ if (check_ksk && type != dns_rdatatype_dnskey &&
+ (dst_key_flags(keys[i]) & DNS_KEYFLAG_KSK) != 0)
+ continue;
+ if (!dst_key_isprivate(keys[i]))
+ 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);
+ }
+
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ return (result);
+}
+
+static void
+zone_resigninc(dns_zone_t *zone) {
+ const char *journalfile;
+ dns_db_t *db = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_diff_t sig_diff;
+ dns_fixedname_t fixed;
+ dns_name_t *name;
+ dns_rdataset_t rdataset;
+ dns_rdatatype_t covers;
+ dst_key_t *zone_keys[MAXZONEKEYS];
+ isc_boolean_t check_ksk;
+ isc_result_t result;
+ isc_stdtime_t now, inception, soaexpire, expire, stop;
+ isc_uint32_t jitter;
+ unsigned int i;
+ unsigned int nkeys = 0;
+ unsigned int resign;
+
+ dns_rdataset_init(&rdataset);
+ dns_fixedname_init(&fixed);
+ dns_diff_init(zone->mctx, &sig_diff);
+
+ /*
+ * Updates are disabled. Pause for 5 minutes.
+ */
+ if (zone->update_disabled) {
+ result = ISC_R_FAILURE;
+ goto failure;
+ }
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ dns_db_attach(zone->db, &db);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+ result = dns_db_newversion(db, &version);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:dns_db_newversion -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ result = find_zone_keys(zone, db, version, zone->mctx, MAXZONEKEYS,
+ zone_keys, &nkeys);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:find_zone_keys -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ isc_stdtime_get(&now);
+ inception = now - 3600; /* Allow for clock skew. */
+ inception = now - 4; /* XXXMPA */
+ soaexpire = now + dns_zone_getsigvalidityinterval(zone);
+ /*
+ * Spread out signatures over time if they happen to be
+ * clumped. We don't do this for each add_sigs() call as
+ * we still want some clustering to occur.
+ */
+ isc_random_get(&jitter);
+ expire = soaexpire - jitter % 3600;
+ expire = soaexpire; /* XXXMPA */
+ stop = now + 5;
+
+ check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
+ if (check_ksk)
+ check_ksk = ksk_sanity(db, version);
+
+ name = dns_fixedname_name(&fixed);
+ result = dns_db_getsigningtime(db, &rdataset, name);
+ if (result != ISC_R_SUCCESS && result != ISC_R_NOTFOUND) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:dns_db_getsigningtime -> %s\n",
+ dns_result_totext(result));
+ }
+
+ i = 0;
+ while (result == ISC_R_SUCCESS) {
+ resign = rdataset.resign;
+ covers = rdataset.covers;
+ /*
+ * Stop if we hit the SOA as that means we have walked the
+ * entire zone. The SOA record should always be the most
+ * recent signature.
+ */
+ /* XXXMPA increase number of RRsets signed pre call */
+ if (covers == dns_rdatatype_soa || i++ > 3 || resign > stop) {
+ /*
+ * Ensure that we don't loop resigning the SOA.
+ */
+ if (covers == dns_rdatatype_soa)
+ dns_db_resigned(db, &rdataset, version);
+ dns_rdataset_disassociate(&rdataset);
+ break;
+ }
+
+ dns_db_resigned(db, &rdataset, version);
+ dns_rdataset_disassociate(&rdataset);
+
+ result = del_sigs(zone, db, version, name, covers, &sig_diff,
+ zone_keys, nkeys, now);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:del_sigs -> %s\n",
+ dns_result_totext(result));
+ break;
+ }
+ result = add_sigs(db, version, name, covers, &sig_diff,
+ zone_keys, nkeys, zone->mctx, inception,
+ expire, check_ksk);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:add_sigs -> %s\n",
+ dns_result_totext(result));
+ break;
+ }
+ result = dns_db_getsigningtime(db, &rdataset,
+ dns_fixedname_name(&fixed));
+ if (nkeys == 0 && result == ISC_R_NOTFOUND) {
+ result = ISC_R_SUCCESS;
+ break;
+ }
+ if (result != ISC_R_SUCCESS)
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:dns_db_getsigningtime -> %s\n",
+ dns_result_totext(result));
+ }
+
+ if (result != ISC_R_NOMORE && result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa,
+ &sig_diff, zone_keys, nkeys, now);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:del_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ result = increment_soa_serial(db, version, &sig_diff, zone->mctx);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:increment_soa_serial -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ /*
+ * Generate maximum life time signatures so that the above loop
+ * termination is sensible.
+ */
+ result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa,
+ &sig_diff, zone_keys, nkeys, zone->mctx, inception,
+ soaexpire, check_ksk);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:add_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ journalfile = dns_zone_getjournal(zone);
+ if (journalfile != NULL) {
+ dns_journal_t *journal = NULL;
+ result = dns_journal_open(zone->mctx, journalfile,
+ ISC_TRUE, &journal);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:dns_journal_open -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ result = dns_journal_write_transaction(journal, &sig_diff);
+ dns_journal_destroy(&journal);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_resigninc:dns_journal_write_transaction -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ }
+
+ /*
+ * Everything has succeeded. Commit the changes.
+ */
+ dns_db_closeversion(db, &version, ISC_TRUE);
+
+ failure:
+ dns_diff_clear(&sig_diff);
+ for (i = 0; i < nkeys; i++)
+ dst_key_free(&zone_keys[i]);
+ if (version != NULL) {
+ dns_db_closeversion(zone->db, &version, ISC_FALSE);
+ dns_db_detach(&db);
+ } else if (db != NULL)
+ dns_db_detach(&db);
+ if (result == ISC_R_SUCCESS) {
+ set_resigntime(zone);
+ LOCK_ZONE(zone);
+ zone_needdump(zone, DNS_DUMP_DELAY);
+ DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDNOTIFY);
+ UNLOCK_ZONE(zone);
+ } else {
+ /*
+ * Something failed. Retry in 5 minutes.
+ */
+ isc_interval_t ival;
+ isc_interval_set(&ival, 300, 0);
+ isc_time_nowplusinterval(&zone->resigntime, &ival);
+ }
+}
+
+static isc_result_t
+next_active(dns_db_t *db, dns_dbversion_t *version, dns_name_t *oldname,
+ dns_name_t *newname, isc_boolean_t bottom)
+{
+ isc_result_t result;
+ dns_dbiterator_t *dbit = NULL;
+ dns_rdatasetiter_t *rdsit = NULL;
+ dns_dbnode_t *node = NULL;
+
+ CHECK(dns_db_createiterator(db, ISC_FALSE, &dbit));
+ CHECK(dns_dbiterator_seek(dbit, oldname));
+ while (1) {
+ result = dns_dbiterator_next(dbit);
+ if (result == ISC_R_NOMORE)
+ CHECK(dns_dbiterator_first(dbit));
+ CHECK(dns_dbiterator_current(dbit, &node, newname));
+ if (bottom && dns_name_issubdomain(newname, oldname) &&
+ !dns_name_equal(newname, oldname)) {
+ dns_db_detachnode(db, &node);
+ continue;
+ }
+ /*
+ * Is this node empty?
+ */
+ CHECK(dns_db_allrdatasets(db, node, version, 0, &rdsit));
+ result = dns_rdatasetiter_first(rdsit);
+ dns_db_detachnode(db, &node);
+ dns_rdatasetiter_destroy(&rdsit);
+ if (result != ISC_R_NOMORE)
+ break;
+ }
+ failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (dbit != NULL)
+ dns_dbiterator_destroy(&dbit);
+ return (result);
+}
+
+static void
+set_bit(unsigned char *array, unsigned int index) {
+ unsigned int shift, mask;
+
+ shift = 7 - (index % 8);
+ mask = 1 << shift;
+
+ array[index / 8] |= mask;
+}
+
+static isc_boolean_t
+signed_with_key(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
+ dns_rdatatype_t type, dst_key_t *key)
+{
+ isc_result_t result;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ dns_rdata_rrsig_t rrsig;
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_findrdataset(db, node, version, dns_rdatatype_rrsig,
+ type, 0, &rdataset, NULL);
+ if (result != ISC_R_SUCCESS)
+ return (ISC_FALSE);
+ 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);
+ INSIST(result == ISC_R_SUCCESS);
+ if (rrsig.algorithm == dst_key_alg(key) &&
+ rrsig.keyid == dst_key_id(key)) {
+ dns_rdataset_disassociate(&rdataset);
+ return (ISC_TRUE);
+ }
+ dns_rdata_reset(&rdata);
+ }
+ dns_rdataset_disassociate(&rdataset);
+ return (ISC_FALSE);
+}
+
+static isc_result_t
+sign_a_node(dns_db_t *db, dns_name_t *name, dns_dbnode_t *node,
+ dns_dbversion_t *version, dst_key_t *key,
+ isc_stdtime_t inception, isc_stdtime_t expire,
+ unsigned int minimum,
+ isc_boolean_t is_ksk, isc_boolean_t *delegation,
+ dns_diff_t *diff, int *signatures, isc_mem_t *mctx)
+{
+ isc_result_t result;
+ dns_rdatasetiter_t *iterator = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ isc_buffer_t buffer;
+ unsigned char data[1024];
+ isc_boolean_t seen_soa, seen_ns, seen_rr, seen_dname, seen_nsec;
+ unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE];
+ isc_boolean_t bottom;
+ dns_name_t *next;
+ dns_fixedname_t fixed;
+
+ result = dns_db_allrdatasets(db, node, version, 0, &iterator);
+ if (result != ISC_R_SUCCESS) {
+ if (result == ISC_R_NOTFOUND)
+ result = ISC_R_SUCCESS;
+ return (result);
+ }
+ dns_rdataset_init(&rdataset);
+ isc_buffer_init(&buffer, data, sizeof(data));
+ seen_rr = seen_soa = seen_ns = seen_dname = seen_nsec = ISC_FALSE;
+ for (result = dns_rdatasetiter_first(iterator);
+ result == ISC_R_SUCCESS;
+ result = dns_rdatasetiter_next(iterator)) {
+ dns_rdatasetiter_current(iterator, &rdataset);
+ if (rdataset.type == dns_rdatatype_soa)
+ seen_soa = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_ns)
+ seen_ns = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_dname)
+ seen_dname = ISC_TRUE;
+ else if (rdataset.type == dns_rdatatype_nsec)
+ seen_nsec = ISC_TRUE;
+ seen_rr = ISC_TRUE;
+ dns_rdataset_disassociate(&rdataset);
+ }
+ if (result != ISC_R_NOMORE)
+ goto failure;
+ if (seen_ns && !seen_soa)
+ *delegation = ISC_TRUE;
+ if (!seen_nsec && seen_rr) {
+ /* Build and add NSEC. */
+ dns_fixedname_init(&fixed);
+ next = dns_fixedname_name(&fixed);
+ bottom = (seen_ns && !seen_soa) || seen_dname;
+ CHECK(next_active(db, version, name, next, bottom));
+ CHECK(dns_nsec_buildrdata(db, version, node, next, nsecbuffer,
+ &rdata));
+ if (dns_name_equal(dns_db_origin(db), name)) {
+ /*
+ * Set the OPT bit to indicate that this is a
+ * partially secure zone.
+ */
+ isc_region_t region;
+
+ dns_rdata_toregion(&rdata, ®ion);
+ dns_name_fromregion(next, ®ion);
+ isc_region_consume(®ion, next->length);
+ INSIST(region.length > (2 + dns_rdatatype_opt / 8) &&
+ region.base[0] == 0 &&
+ region.base[1] > dns_rdatatype_opt / 8);
+ set_bit(region.base + 2, dns_rdatatype_opt);
+ }
+ CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name,
+ minimum, &rdata));
+ dns_rdata_reset(&rdata);
+ /* Count a NSEC generation as a signature generation. */
+ (*signatures)--;
+ }
+ result = dns_rdatasetiter_first(iterator);
+ while (result == ISC_R_SUCCESS) {
+ dns_rdatasetiter_current(iterator, &rdataset);
+ if (rdataset.type == dns_rdatatype_soa ||
+ rdataset.type == dns_rdatatype_rrsig)
+ goto next_rdataset;
+ if (is_ksk && rdataset.type != dns_rdatatype_dnskey)
+ goto next_rdataset;
+ if (*delegation && !dns_rdatatype_atparent(rdataset.type))
+ goto next_rdataset;
+ if (signed_with_key(db, node, version, rdataset.type, key))
+ goto next_rdataset;
+ /* Calculate the signature, creating a RRSIG RDATA. */
+ CHECK(dns_dnssec_sign(name, &rdataset, key, &inception,
+ &expire, mctx, &buffer, &rdata));
+ /* Update the database and journal with the RRSIG. */
+ /* XXX inefficient - will cause dataset merging */
+ CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADDRESIGN,
+ name, rdataset.ttl, &rdata));
+ dns_rdata_reset(&rdata);
+ (*signatures)--;
+ next_rdataset:
+ dns_rdataset_disassociate(&rdataset);
+ result = dns_rdatasetiter_next(iterator);
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ if (seen_dname)
+ *delegation = ISC_TRUE;
+failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (iterator != NULL)
+ dns_rdatasetiter_destroy(&iterator);
+ return (result);
+}
+
+static isc_result_t
+updatesecure(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name,
+ dns_ttl_t minimum, isc_boolean_t *secureupdated, dns_diff_t *diff)
+{
+ isc_result_t result;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned char nsecbuffer[DNS_NSEC_BUFFERSIZE];
+ dns_rdataset_t rdataset;
+ dns_rdata_nsec_t nsec;
+ dns_dbnode_t *node = NULL;
+
+ /*
+ * Check to see if the OPT bit has already been cleared.
+ */
+ CHECK(dns_db_getoriginnode(db, &node));
+ dns_rdataset_init(&rdataset);
+ CHECK(dns_db_findrdataset(db, node, version, dns_rdatatype_nsec,
+ dns_rdatatype_none, 0, &rdataset, NULL));
+ CHECK(dns_rdataset_first(&rdataset));
+ dns_rdataset_current(&rdataset, &rdata);
+ if (!dns_nsec_typepresent(&rdata, dns_rdatatype_opt))
+ goto failure;
+
+ /*
+ * Find the NEXT name for building the new record.
+ */
+ CHECK(dns_rdata_tostruct(&rdata, &nsec, NULL));
+
+ /*
+ * Delete the old NSEC record.
+ */
+ CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_DEL, name, minimum,
+ &rdata));
+ dns_rdata_reset(&rdata);
+
+ /*
+ * Add the new NSEC record.
+ */
+ CHECK(dns_nsec_buildrdata(db, version, node, &nsec.next, nsecbuffer,
+ &rdata));
+ CHECK(update_one_rr(db, version, diff, DNS_DIFFOP_ADD, name, minimum,
+ &rdata));
+ dns_rdata_reset(&rdata);
+
+ *secureupdated = ISC_TRUE;
+
+ failure:
+ if (node != NULL)
+ dns_db_detachnode(db, &node);
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ return (result);
+}
+
+static isc_result_t
+updatesignwithkey(dns_signing_t *signing, dns_dbversion_t *version,
+ dns_name_t *name, dns_diff_t *diff)
+{
+ isc_result_t result;
+ dns_dbnode_t *node = NULL;
+ dns_rdataset_t rdataset;
+ dns_rdata_t rdata = DNS_RDATA_INIT;
+ unsigned char data[4];
+
+ dns_rdataset_init(&rdataset);
+ result = dns_db_getoriginnode(signing->db, &node);
+ if (result != ISC_R_SUCCESS)
+ goto failure;
+
+ result = dns_db_findrdataset(signing->db, node, version, 0xffff,
+ dns_rdatatype_none, 0, &rdataset, NULL);
+ if (result == ISC_R_NOTFOUND) {
+ result = ISC_R_SUCCESS;
+ goto failure;
+ }
+ 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);
+ if (rdata.length != 4 ||
+ rdata.data[0] != signing->algorithm ||
+ rdata.data[1] != ((signing->keyid >> 8) & 0xff) ||
+ rdata.data[2] != (signing->keyid & 0xff) ||
+ rdata.data[3] != 0) {
+ dns_rdata_reset(&rdata);
+ continue;
+ }
+ CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_DEL,
+ name, rdataset.ttl, &rdata));
+ memcpy(data, rdata.data, 4);
+ data[3] = 1; /* mark as done */
+ rdata.data = data;
+ CHECK(update_one_rr(signing->db, version, diff, DNS_DIFFOP_ADD,
+ name, rdataset.ttl, &rdata));
+ break;
+ }
+ if (result == ISC_R_NOMORE)
+ result = ISC_R_SUCCESS;
+ failure:
+ if (dns_rdataset_isassociated(&rdataset))
+ dns_rdataset_disassociate(&rdataset);
+ if (node != NULL)
+ dns_db_detachnode(signing->db, &node);
+ return (result);
+}
+
+/*
+ * Incrementally sign the zone using the keys requested.
+ * Builds the NSEC chain is required.
+ */
+static void
+zone_sign(dns_zone_t *zone) {
+ const char *journalfile;
+ dns_db_t *db = NULL;
+ dns_dbnode_t *node = NULL;
+ dns_dbversion_t *version = NULL;
+ dns_diff_t sig_diff;
+ dns_fixedname_t fixed;
+ dns_fixedname_t nextfixed;
+ dns_name_t *name, *nextname;
+ dns_rdataset_t rdataset;
+ dns_signing_t *signing, *nextsigning;
+ dns_signinglist_t cleanup;
+ dst_key_t *zone_keys[MAXZONEKEYS];
+ int signatures;
+ isc_boolean_t check_ksk, is_ksk;
+ isc_boolean_t delegation;
+ isc_boolean_t finishedakey = ISC_FALSE;
+ isc_boolean_t secureupdated = ISC_FALSE;
+ isc_boolean_t first;
+ isc_result_t result;
+ isc_stdtime_t now, inception, soaexpire, expire, stop;
+ isc_uint32_t jitter;
+ unsigned int i;
+ unsigned int nkeys = 0;
+ unsigned int nodes;
+
+ dns_rdataset_init(&rdataset);
+ dns_fixedname_init(&fixed);
+ name = dns_fixedname_name(&fixed);
+ dns_fixedname_init(&nextfixed);
+ nextname = dns_fixedname_name(&nextfixed);
+ dns_diff_init(zone->mctx, &sig_diff);
+ ISC_LIST_INIT(cleanup);
+
+fprintf(stderr, "zone_sign\n");
+
+ /*
+ * Updates are disabled. Pause for 5 minutes.
*/
- new = isc_mem_get(zone->mctx, count * sizeof(*new));
- if (new == NULL) {
- result = ISC_R_NOMEMORY;
- goto unlock;
+ if (zone->update_disabled) {
+ result = ISC_R_FAILURE;
+ goto failure;
+ }
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ dns_db_attach(zone->db, &db);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+ result = dns_db_newversion(db, &version);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:dns_db_newversion -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ result = find_zone_keys(zone, db, version, zone->mctx,
+ MAXZONEKEYS, zone_keys, &nkeys);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:find_zone_keys -> %s\n",
+ dns_result_totext(result));
+ goto failure;
}
- memcpy(new, masters, count * sizeof(*new));
+ isc_stdtime_get(&now);
+ inception = now - 3600; /* Allow for clock skew. */
+ inception = now - 4; /* XXXMPA */
+ soaexpire = now + dns_zone_getsigvalidityinterval(zone);
/*
- * Similarly for mastersok.
+ * Spread out signatures over time if they happen to be
+ * clumped. We don't do this for each add_sigs() call as
+ * we still want some clustering to occur.
*/
- newok = isc_mem_get(zone->mctx, count * sizeof(*newok));
- if (newok == NULL) {
- result = ISC_R_NOMEMORY;
- isc_mem_put(zone->mctx, new, count * sizeof(*new));
- goto unlock;
- };
- for (i = 0; i < count; i++)
- newok[i] = ISC_FALSE;
+ isc_random_get(&jitter);
+ expire = soaexpire - jitter % 3600;
+ expire = soaexpire; /* XXXMPA */
+ stop = now + 5;
+
+ check_ksk = DNS_ZONE_OPTION(zone, DNS_ZONEOPT_UPDATECHECKKSK);
+ if (check_ksk)
+ check_ksk = ksk_sanity(db, version);
/*
- * if keynames is non-NULL, it must contain count elements!
+ * We keep pulling nodes off each interator in turn until
+ * we have no more noded to pull off or we reach the limits
+ * for this quantum.
*/
- newname = NULL;
- if (keynames != NULL) {
- newname = isc_mem_get(zone->mctx, count * sizeof(*newname));
- if (newname == NULL) {
- result = ISC_R_NOMEMORY;
- isc_mem_put(zone->mctx, new, count * sizeof(*new));
- isc_mem_put(zone->mctx, newok, count * sizeof(*newok));
- goto unlock;
+ nodes = 10;
+ signatures = 3;
+ signing = ISC_LIST_HEAD(zone->signing);
+ first = ISC_TRUE;
+ while (signing != NULL && nodes-- > 0 && signatures > 0) {
+ nextsigning = ISC_LIST_NEXT(signing, link);
+
+ ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
+ if (signing->db != zone->db) {
+ /*
+ * The zone has been reloaded. We will have
+ * created new signings as part of the reload
+ * process so we can destroy this one.
+ */
+ ISC_LIST_UNLINK(zone->signing, signing, link);
+ dns_db_detach(&signing->db);
+ dns_dbiterator_destroy(&signing->dbiterator);
+ isc_mem_put(zone->mctx, signing, sizeof *signing);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+ goto next_signing;
}
- for (i = 0; i < count; i++)
- newname[i] = NULL;
- for (i = 0; i < count; i++) {
- if (keynames[i] != NULL) {
- newname[i] = isc_mem_get(zone->mctx,
- sizeof(dns_name_t));
- if (newname[i] == NULL)
- goto allocfail;
- dns_name_init(newname[i], NULL);
- result = dns_name_dup(keynames[i], zone->mctx,
- newname[i]);
+ ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
+
+ if (signing->db != db)
+ goto next_signing;
+
+ is_ksk = ISC_FALSE;
+ dns_dbiterator_current(signing->dbiterator, &node, name);
+ /*
+ * On the first pass we need to check if the current node
+ * has not been obscured.
+ */
+ delegation = ISC_FALSE;
+ if (first) {
+ dns_fixedname_t ffound;
+ dns_name_t *found;
+ dns_fixedname_init(&ffound);
+ found = dns_fixedname_name(&ffound);
+ result = dns_db_find(db, name, version,
+ dns_rdatatype_soa,
+ DNS_DBFIND_NOWILD, 0, NULL, found,
+ NULL, NULL);
+ if ((result == DNS_R_DELEGATION ||
+ result == DNS_R_DNAME) &&
+ !dns_name_equal(name, found)) {
+ /*
+ * Remember the obscuring name so that
+ * we skip all obscured names.
+ */
+ dns_name_copy(found, name, NULL);
+ delegation = ISC_TRUE;
+ goto next_node;
+ }
+ }
+
+ /*
+ * Process one node.
+ */
+ for (i = 0; i < nkeys; i++) {
+ /*
+ * Find the key we want to sign with.
+ */
+ if (dst_key_alg(zone_keys[i]) != signing->algorithm ||
+ dst_key_id(zone_keys[i]) != signing->keyid ||
+ !dst_key_isprivate(zone_keys[i]))
+ continue;
+ /*
+ * Do we do KSK processing?
+ */
+ if (check_ksk &&
+ (dst_key_flags(zone_keys[i]) & DNS_KEYFLAG_KSK) != 0)
+ is_ksk = ISC_TRUE;
+ CHECK(sign_a_node(db, name, node, version,
+ zone_keys[i], inception, expire,
+ zone->minimum, is_ksk, &delegation,
+ &sig_diff, &signatures, zone->mctx));
+ break;
+ }
+ /*
+ * Go onto next node.
+ */
+ next_node:
+ dns_db_detachnode(db, &node);
+ do {
+ result = dns_dbiterator_next(signing->dbiterator);
+ if (result == ISC_R_NOMORE) {
+ ISC_LIST_UNLINK(zone->signing, signing, link);
+ ISC_LIST_APPEND(cleanup, signing, link);
+ finishedakey = ISC_TRUE;
+ if (!is_ksk && !secureupdated) {
+ /*
+ * We have finished regenerating the
+ * zone with a zone signing key.
+ * The NSEC chain is now complete and
+ * there is a full set of signatures
+ * for the zone. We can now clear the
+ * OPT bit from the NSEC record.
+ */
+ result = updatesecure(db, version,
+ &zone->origin,
+ zone->minimum,
+ &secureupdated,
+ &sig_diff);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone,
+ ISC_LOG_ERROR,
+ "updatesecure -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ }
+ result = updatesignwithkey(signing, version,
+ &zone->origin,
+ &sig_diff);
if (result != ISC_R_SUCCESS) {
- allocfail:
- for (i = 0; i < count; i++)
- if (newname[i] != NULL)
- dns_name_free(
- newname[i],
- zone->mctx);
- isc_mem_put(zone->mctx, new,
- count * sizeof(*new));
- isc_mem_put(zone->mctx, newok,
- count * sizeof(*newok));
- isc_mem_put(zone->mctx, newname,
- count * sizeof(*newname));
- goto unlock;
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "updatesignwithkey -> %s\n",
+ dns_result_totext(result));
+ goto failure;
}
- }
+ break;
+ } else if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:dns_dbiterator_next -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ } else if (delegation) {
+ dns_dbiterator_current(signing->dbiterator,
+ &node, nextname);
+ dns_db_detachnode(db, &node);
+ if (!dns_name_issubdomain(nextname, name))
+ break;
+ } else
+ break;
+ } while (1);
+ next_signing:
+ signing = nextsigning;
+ if (signing == NULL) {
+ first = ISC_FALSE;
+ signing = ISC_LIST_HEAD(zone->signing);
+ }
+ }
+
+ if (secureupdated) {
+ /*
+ * We have changed the NSEC RRset above so we need to update
+ * the signatures.
+ */
+ result = del_sigs(zone, db, version, &zone->origin,
+ dns_rdatatype_nsec, &sig_diff, zone_keys,
+ nkeys, now);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:del_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
}
+ result = add_sigs(db, version, &zone->origin,
+ dns_rdatatype_nsec, &sig_diff, zone_keys,
+ nkeys, zone->mctx, inception, soaexpire,
+ check_ksk);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:add_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ }
+ if (finishedakey) {
+ /*
+ * We have changed the RRset above so we need to update
+ * the signatures.
+ */
+ result = del_sigs(zone, db, version, &zone->origin,
+ (dns_rdatatype_t)0xffff, &sig_diff,
+ zone_keys, nkeys, now);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:del_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ result = add_sigs(db, version, &zone->origin,
+ (dns_rdatatype_t)0xffff, &sig_diff,
+ zone_keys, nkeys, zone->mctx, inception,
+ soaexpire, check_ksk);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:add_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ }
+ result = del_sigs(zone, db, version, &zone->origin, dns_rdatatype_soa,
+ &sig_diff, zone_keys, nkeys, now);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:del_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+
+ result = increment_soa_serial(db, version, &sig_diff, zone->mctx);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:increment_soa_serial -> %s\n",
+ dns_result_totext(result));
+ goto failure;
}
/*
- * Everything is ok so attach to the zone.
+ * Generate maximum life time signatures so that the above loop
+ * termination is sensible.
*/
- zone->masters = new;
- zone->mastersok = newok;
- zone->masterkeynames = newname;
- zone->masterscnt = count;
- DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NOMASTERS);
-
- unlock:
- UNLOCK_ZONE(zone);
- return (result);
-}
-
-isc_result_t
-dns_zone_getdb(dns_zone_t *zone, dns_db_t **dpb) {
- isc_result_t result = ISC_R_SUCCESS;
-
- REQUIRE(DNS_ZONE_VALID(zone));
-
- ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
- if (zone->db == NULL)
- result = DNS_R_NOTLOADED;
- else
- dns_db_attach(zone->db, dpb);
- ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
-
- return (result);
-}
-
-/*
- * Co-ordinates the starting of routine jobs.
- */
+ result = add_sigs(db, version, &zone->origin, dns_rdatatype_soa,
+ &sig_diff, zone_keys, nkeys, zone->mctx, inception,
+ soaexpire, check_ksk);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:add_sigs -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
-void
-dns_zone_maintenance(dns_zone_t *zone) {
- const char me[] = "dns_zone_maintenance";
- isc_time_t now;
+ journalfile = dns_zone_getjournal(zone);
+ if (journalfile != NULL) {
+ dns_journal_t *journal = NULL;
+ result = dns_journal_open(zone->mctx, journalfile,
+ ISC_TRUE, &journal);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:dns_journal_open -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
- REQUIRE(DNS_ZONE_VALID(zone));
- ENTER;
+ result = dns_journal_write_transaction(journal, &sig_diff);
+ dns_journal_destroy(&journal);
+ if (result != ISC_R_SUCCESS) {
+ dns_zone_log(zone, ISC_LOG_ERROR,
+ "zone_sign:dns_journal_write_transaction -> %s\n",
+ dns_result_totext(result));
+ goto failure;
+ }
+ }
- LOCK_ZONE(zone);
- TIME_NOW(&now);
- zone_settimer(zone, &now);
- UNLOCK_ZONE(zone);
-}
+ /*
+ * Everything has succeeded. Commit the changes.
+ */
+ dns_db_closeversion(db, &version, ISC_TRUE);
-static inline isc_boolean_t
-was_dumping(dns_zone_t *zone) {
- isc_boolean_t dumping;
+ /*
+ * Everything succeeded so we can clean these up now.
+ */
+ signing = ISC_LIST_HEAD(cleanup);
+ while (signing != NULL) {
+ ISC_LIST_UNLINK(cleanup, signing, link);
+ dns_db_detach(&signing->db);
+ dns_dbiterator_destroy(&signing->dbiterator);
+ isc_mem_put(zone->mctx, signing, sizeof *signing);
+ signing = ISC_LIST_HEAD(cleanup);
+ }
- REQUIRE(LOCKED_ZONE(zone));
+ set_resigntime(zone);
- dumping = DNS_ZONE_FLAG(zone, DNS_ZONEFLG_DUMPING);
- DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_DUMPING);
- if (!dumping) {
- DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDDUMP);
- isc_time_settoepoch(&zone->dumptime);
+ failure:
+ /*
+ * Rollback the cleanup list.
+ */
+ signing = ISC_LIST_HEAD(cleanup);
+ while (signing != NULL) {
+ ISC_LIST_UNLINK(cleanup, signing, link);
+ ISC_LIST_APPEND(zone->signing, signing, link);
+ dns_dbiterator_first(signing->dbiterator);
+ signing = ISC_LIST_HEAD(cleanup);
+ }
+ for (signing = ISC_LIST_HEAD(zone->signing);
+ signing != NULL;
+ signing = ISC_LIST_NEXT(signing, link))
+ dns_dbiterator_pause(signing->dbiterator);
+ dns_diff_clear(&sig_diff);
+ for (i = 0; i < nkeys; i++)
+ dst_key_free(&zone_keys[i]);
+ if (version != NULL) {
+ dns_db_closeversion(db, &version, ISC_FALSE);
+ dns_db_detach(&db);
+ } else if (db != NULL)
+ dns_db_detach(&db);
+ if (ISC_LIST_HEAD(zone->signing) != NULL) {
+ isc_interval_t i;
+ if (zone->update_disabled)
+ isc_interval_set(&i, 60, 0); /* 1 minute */
+ else
+ isc_interval_set(&i, 0, 10000000); /* 10 ms */
+ isc_interval_set(&i, 120, 0); /* XXXMPA */
+ isc_time_nowplusinterval(&zone->signingtime, &i);
+ } else {
+ fprintf(stderr, "sign_zone done\n");
+ isc_time_settoepoch(&zone->signingtime);
}
- return (dumping);
}
static void
break;
}
- /*
- * Do we need to send out notify messages?
- */
switch (zone->type) {
case dns_zone_master:
case dns_zone_slave:
+ /*
+ * Do we need to send out notify messages?
+ */
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDNOTIFY) &&
isc_time_compare(&now, &zone->notifytime) >= 0)
zone_notify(zone, &now);
+ /*
+ * Do we need to sign/resign some RRsets?
+ */
+ if (!isc_time_isepoch(&zone->signingtime) &&
+ isc_time_compare(&now, &zone->signingtime) >= 0)
+ zone_sign(zone);
+ else if (!isc_time_isepoch(&zone->resigntime) &&
+ isc_time_compare(&now, &zone->resigntime) >= 0)
+ zone_resigninc(zone);
+ /*
+ * Do we need to issue a key expiry warning.
+ */
+ if (!isc_time_isepoch(&zone->keywarntime) &&
+ isc_time_compare(&now, &zone->keywarntime) >= 0)
+ set_key_expiry_warning(zone, zone->key_expiry,
+ isc_time_seconds(&now));
break;
default:
break;
dns_zone_markdirty(dns_zone_t *zone) {
LOCK_ZONE(zone);
+ set_resigntime(zone); /* XXXMPA make seperate call back */
zone_needdump(zone, DNS_DUMP_DELAY);
UNLOCK_ZONE(zone);
}
isc_time_compare(&zone->dumptime, &next) < 0)
next = zone->dumptime;
}
+ if (!isc_time_isepoch(&zone->resigntime)) {
+ if (isc_time_isepoch(&next) ||
+ isc_time_compare(&zone->resigntime, &next) < 0)
+ next = zone->resigntime;
+ }
+ if (!isc_time_isepoch(&zone->keywarntime)) {
+ if (isc_time_isepoch(&next) ||
+ isc_time_compare(&zone->keywarntime, &next) < 0)
+ next = zone->keywarntime;
+ }
+ if (!isc_time_isepoch(&zone->signingtime)) {
+ if (isc_time_isepoch(&next) ||
+ isc_time_compare(&zone->signingtime, &next) < 0)
+ next = zone->signingtime;
+ }
break;
case dns_zone_slave:
REQUIRE(DNS_ZONE_VALID(zone));
zone->sigvalidityinterval = interval;
+ zone->sigvalidityinterval = 3600; /* XXXMPA */
}
isc_uint32_t
return (zone->notifydelay);
}
+isc_result_t
+dns_zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid) {
+ isc_result_t result;
+ REQUIRE(DNS_ZONE_VALID(zone));
+
+ dns_zone_log(zone, ISC_LOG_NOTICE,
+ "dns_zone_signwithkey(algorithm=%u, keyid=%u)",
+ algorithm, keyid);
+ LOCK_ZONE(zone);
+ result = zone_signwithkey(zone, algorithm, keyid);
+ UNLOCK_ZONE(zone);
+
+ return (result);
+}
+
+static isc_result_t
+zone_signwithkey(dns_zone_t *zone, dns_secalg_t algorithm, uint16_t keyid) {
+ dns_signing_t *signing;
+ isc_result_t result;
+ isc_time_t now;
+
+ signing = isc_mem_get(zone->mctx, sizeof *signing);
+ if (signing == NULL)
+ return (ISC_R_NOMEMORY);
+
+ signing->magic = 0;
+ signing->db = NULL;
+ signing->dbiterator = NULL;
+ signing->algorithm = algorithm;
+ signing->keyid = keyid;
+
+ TIME_NOW(&now);
+
+ if (zone->db != NULL) {
+ dns_db_attach(zone->db, &signing->db);
+ result = dns_db_createiterator(signing->db, ISC_FALSE,
+ &signing->dbiterator);
+
+ if (result == ISC_R_SUCCESS)
+ result = dns_dbiterator_first(signing->dbiterator);
+ if (result == ISC_R_SUCCESS) {
+ dns_dbiterator_pause(signing->dbiterator);
+ ISC_LIST_INITANDAPPEND(zone->signing, signing, link);
+ signing = NULL;
+ if (isc_time_isepoch(&zone->signingtime)) {
+ zone->signingtime = now;
+ if (zone->task != NULL)
+ zone_settimer(zone, &now);
+ }
+ }
+ } else
+ result = ISC_R_NOTFOUND;
+
+ if (signing != NULL) {
+ dns_db_detach(&signing->db);
+ if (signing->dbiterator != NULL)
+ dns_dbiterator_destroy(&signing->dbiterator);
+ isc_mem_put(zone->mctx, signing, sizeof *signing);
+ }
+ return (result);
+}
+
#ifdef HAVE_LIBXML2
isc_result_t
* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: mem.c,v 1.143 2008/03/31 23:47:11 tbox Exp $ */
+/* $Id: mem.c,v 1.144 2008/04/01 01:37:25 marka Exp $ */
/*! \file */
static ISC_LIST(isc_mem_t) contexts;
static isc_once_t once = ISC_ONCE_INIT;
-static isc_mutex_t lock;
+static isc_mutex_t contextlock;
/*%
* Total size of lost memory due to a bug of external library.
unsigned int magic;
isc_ondestroy_t ondestroy;
unsigned int flags;
- isc_mutex_t lock;
+ isc_mutex_t memlock;
isc_memalloc_t memalloc;
isc_memfree_t memfree;
void * arg;
static void
initialize_action(void) {
- RUNTIME_CHECK(isc_mutex_init(&lock) == ISC_R_SUCCESS);
+ RUNTIME_CHECK(isc_mutex_init(&contextlock) == ISC_R_SUCCESS);
ISC_LIST_INIT(contexts);
totallost = 0;
}
return (ISC_R_NOMEMORY);
if ((flags & ISC_MEMFLAG_NOLOCK) == 0) {
- result = isc_mutex_init(&ctx->lock);
+ result = isc_mutex_init(&ctx->memlock);
if (result != ISC_R_SUCCESS) {
(memfree)(arg, ctx);
return (result);
ctx->memalloc_failures = 0;
- LOCK(&lock);
+ LOCK(&contextlock);
ISC_LIST_INITANDAPPEND(contexts, ctx, link);
- UNLOCK(&lock);
+ UNLOCK(&contextlock);
*ctxp = ctx;
return (ISC_R_SUCCESS);
(ctx->memfree)(ctx->arg, ctx->debuglist);
#endif /* ISC_MEM_TRACKLINES */
if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
- DESTROYLOCK(&ctx->lock);
+ DESTROYLOCK(&ctx->memlock);
(memfree)(arg, ctx);
}
ctx->magic = 0;
- LOCK(&lock);
+ LOCK(&contextlock);
ISC_LIST_UNLINK(contexts, ctx, link);
totallost += ctx->inuse;
- UNLOCK(&lock);
+ UNLOCK(&contextlock);
INSIST(ISC_LIST_EMPTY(ctx->pools));
ondest = ctx->ondestroy;
if ((ctx->flags & ISC_MEMFLAG_NOLOCK) == 0)
- DESTROYLOCK(&ctx->lock);
+ DESTROYLOCK(&ctx->memlock);
(ctx->memfree)(ctx->arg, ctx);
isc_ondestroy_notify(&ondest, ctx);
REQUIRE(VALID_CONTEXT(source));
REQUIRE(targetp != NULL && *targetp == NULL);
- MCTXLOCK(source, &source->lock);
+ MCTXLOCK(source, &source->memlock);
source->references++;
- MCTXUNLOCK(source, &source->lock);
+ MCTXUNLOCK(source, &source->memlock);
*targetp = source;
}
ctx = *ctxp;
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
INSIST(ctx->references > 0);
ctx->references--;
if (ctx->references == 0)
want_destroy = ISC_TRUE;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
if (want_destroy)
destroy(ctx);
}
isc__mem_free(ctx, ptr FLARG_PASS);
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
ctx->references--;
if (ctx->references == 0)
want_destroy = ISC_TRUE;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
if (want_destroy)
destroy(ctx);
}
if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
mem_putunlocked(ctx, ptr, size);
} else {
mem_put(ctx, ptr, size);
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
mem_putstats(ctx, ptr, size);
}
if (ctx->references == 0)
want_destroy = ISC_TRUE;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
if (want_destroy)
destroy(ctx);
ctx = *ctxp;
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
#if ISC_MEM_TRACKLINES
if (ctx->references != 1)
print_active(ctx, stderr);
#endif
REQUIRE(ctx->references == 1);
ctx->references--;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
destroy(ctx);
isc_mem_ondestroy(isc_mem_t *ctx, isc_task_t *task, isc_event_t **event) {
isc_result_t res;
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
res = isc_ondestroy_register(&ctx->ondestroy, task, event);
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
return (res);
}
return (isc__mem_allocate(ctx, size FLARG_PASS));
if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
ptr = mem_getunlocked(ctx, size);
} else {
ptr = mem_get(ctx, size);
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
if (ptr != NULL)
mem_getstats(ctx, size);
}
fprintf(stderr, "maxinuse = %lu\n",
(unsigned long)ctx->inuse);
}
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
if (call_water)
(ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
}
if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
mem_putunlocked(ctx, ptr, size);
} else {
mem_put(ctx, ptr, size);
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
mem_putstats(ctx, ptr, size);
}
if (ctx->water != NULL)
call_water = ISC_TRUE;
}
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
if (call_water)
(ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
isc_mem_waterack(isc_mem_t *ctx, int flag) {
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
if (flag == ISC_MEM_LOWATER)
ctx->hi_called = ISC_FALSE;
else if (flag == ISC_MEM_HIWATER)
ctx->hi_called = ISC_TRUE;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
}
#if ISC_MEM_TRACKLINES
const isc_mempool_t *pool;
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
for (i = 0; i <= ctx->max_size; i++) {
s = &ctx->stats[i];
* Note that since a pool can be locked now, these stats might be
* somewhat off if the pool is in active use at the time the stats
* are dumped. The link fields are protected by the isc_mem_t's
- * lock, however, so walking this list and extracting integers from
+ * contextlock, however, so walking this list and extracting integers from
* stats fields is always safe.
*/
pool = ISC_LIST_HEAD(ctx->pools);
print_active(ctx, out);
#endif
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
}
/*
REQUIRE(VALID_CONTEXT(ctx));
if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
si = isc__mem_allocateunlocked(ctx, size);
} else {
si = isc__mem_allocateunlocked(ctx, size);
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
if (si != NULL)
mem_getstats(ctx, si[-1].u.size);
}
fprintf(stderr, "maxinuse = %lu\n",
(unsigned long)ctx->inuse);
}
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
if (call_water)
(ctx->water)(ctx->water_arg, ISC_MEM_HIWATER);
}
if ((ctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
mem_putunlocked(ctx, si, size);
} else {
mem_put(ctx, si, size);
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
mem_putstats(ctx, si, size);
}
if (ctx->water != NULL)
call_water = ISC_TRUE;
}
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
if (call_water)
(ctx->water)(ctx->water_arg, ISC_MEM_LOWATER);
void
isc_mem_setdestroycheck(isc_mem_t *ctx, isc_boolean_t flag) {
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
ctx->checkfree = flag;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
}
/*
void
isc_mem_setquota(isc_mem_t *ctx, size_t quota) {
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
ctx->quota = quota;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
}
size_t
size_t quota;
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
quota = ctx->quota;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
return (quota);
}
size_t inuse;
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
inuse = ctx->inuse;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
return (inuse);
}
REQUIRE(VALID_CONTEXT(ctx));
REQUIRE(hiwater >= lowater);
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
oldwater = ctx->water;
oldwater_arg = ctx->water_arg;
if (water == NULL) {
ctx->lo_water = lowater;
ctx->hi_called = ISC_FALSE;
}
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
if (callwater && oldwater != NULL)
(oldwater)(oldwater_arg, ISC_MEM_LOWATER);
isc_mem_setname(isc_mem_t *ctx, const char *name, void *tag) {
REQUIRE(VALID_CONTEXT(ctx));
- LOCK(&ctx->lock);
+ LOCK(&ctx->memlock);
memset(ctx->name, 0, sizeof(ctx->name));
strncpy(ctx->name, name, sizeof(ctx->name) - 1);
ctx->tag = tag;
- UNLOCK(&ctx->lock);
+ UNLOCK(&ctx->memlock);
}
const char *
*mpctxp = mpctx;
- MCTXLOCK(mctx, &mctx->lock);
+ MCTXLOCK(mctx, &mctx->memlock);
ISC_LIST_INITANDAPPEND(mctx->pools, mpctx, link);
mctx->poolcnt++;
- MCTXUNLOCK(mctx, &mctx->lock);
+ MCTXUNLOCK(mctx, &mctx->memlock);
return (ISC_R_SUCCESS);
}
/*
* Return any items on the free list
*/
- MCTXLOCK(mctx, &mctx->lock);
+ MCTXLOCK(mctx, &mctx->memlock);
while (mpctx->items != NULL) {
INSIST(mpctx->freecount > 0);
mpctx->freecount--;
mem_putstats(mctx, item, mpctx->size);
}
}
- MCTXUNLOCK(mctx, &mctx->lock);
+ MCTXUNLOCK(mctx, &mctx->memlock);
/*
* Remove our linked list entry from the memory context.
*/
- MCTXLOCK(mctx, &mctx->lock);
+ MCTXLOCK(mctx, &mctx->memlock);
ISC_LIST_UNLINK(mctx->pools, mpctx, link);
mctx->poolcnt--;
- MCTXUNLOCK(mctx, &mctx->lock);
+ MCTXUNLOCK(mctx, &mctx->memlock);
mpctx->magic = 0;
* We need to dip into the well. Lock the memory context here and
* fill up our free list.
*/
- MCTXLOCK(mctx, &mctx->lock);
+ MCTXLOCK(mctx, &mctx->memlock);
for (i = 0; i < mpctx->fillcount; i++) {
if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
item = mem_getunlocked(mctx, mpctx->size);
mpctx->items = item;
mpctx->freecount++;
}
- MCTXUNLOCK(mctx, &mctx->lock);
+ MCTXUNLOCK(mctx, &mctx->memlock);
/*
* If we didn't get any items, return NULL.
#if ISC_MEM_TRACKLINES
if (item != NULL) {
- MCTXLOCK(mctx, &mctx->lock);
+ MCTXLOCK(mctx, &mctx->memlock);
ADD_TRACE(mctx, item, mpctx->size, file, line);
- MCTXUNLOCK(mctx, &mctx->lock);
+ MCTXUNLOCK(mctx, &mctx->memlock);
}
#endif /* ISC_MEM_TRACKLINES */
mpctx->allocated--;
#if ISC_MEM_TRACKLINES
- MCTXLOCK(mctx, &mctx->lock);
+ MCTXLOCK(mctx, &mctx->memlock);
DELETE_TRACE(mctx, mem, mpctx->size, file, line);
- MCTXUNLOCK(mctx, &mctx->lock);
+ MCTXUNLOCK(mctx, &mctx->memlock);
#endif /* ISC_MEM_TRACKLINES */
/*
*/
if (mpctx->freecount >= mpctx->freemax) {
if ((mctx->flags & ISC_MEMFLAG_INTERNAL) != 0) {
- MCTXLOCK(mctx, &mctx->lock);
+ MCTXLOCK(mctx, &mctx->memlock);
mem_putunlocked(mctx, mem, mpctx->size);
- MCTXUNLOCK(mctx, &mctx->lock);
+ MCTXUNLOCK(mctx, &mctx->memlock);
} else {
mem_put(mctx, mem, mpctx->size);
- MCTXLOCK(mctx, &mctx->lock);
+ MCTXLOCK(mctx, &mctx->memlock);
mem_putstats(mctx, mem, mpctx->size);
- MCTXUNLOCK(mctx, &mctx->lock);
+ MCTXUNLOCK(mctx, &mctx->memlock);
}
if (mpctx->lock != NULL)
UNLOCK(mpctx->lock);
RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
- LOCK(&lock);
+ LOCK(&contextlock);
for (ctx = ISC_LIST_HEAD(contexts);
ctx != NULL;
ctx = ISC_LIST_NEXT(ctx, link)) {
fprintf(file, "context: %p\n", ctx);
print_active(ctx, file);
}
- UNLOCK(&lock);
+ UNLOCK(&contextlock);
#endif
}
RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
- LOCK(&lock);
+ LOCK(&contextlock);
if (!ISC_LIST_EMPTY(contexts)) {
#if ISC_MEM_TRACKLINES
isc_mem_t *ctx;
#endif
INSIST(0);
}
- UNLOCK(&lock);
+ UNLOCK(&contextlock);
}
unsigned int
unsigned int references;
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
references = ctx->references;
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
return (references);
}
}
REQUIRE(VALID_CONTEXT(ctx));
- MCTXLOCK(ctx, &ctx->lock);
+ MCTXLOCK(ctx, &ctx->memlock);
summary->contextsize += sizeof(*ctx) +
(ctx->max_size + 1) * sizeof(struct stats) +
(isc_uint64_t)ctx->lo_water);
xmlTextWriterEndElement(writer); /* lowater */
- MCTXUNLOCK(ctx, &ctx->lock);
+ MCTXUNLOCK(ctx, &ctx->memlock);
xmlTextWriterEndElement(writer); /* context */
}
RUNTIME_CHECK(isc_once_do(&once, initialize_action) == ISC_R_SUCCESS);
- LOCK(&lock);
+ LOCK(&contextlock);
lost = totallost;
for (ctx = ISC_LIST_HEAD(contexts);
ctx != NULL;
ctx = ISC_LIST_NEXT(ctx, link)) {
renderctx(ctx, &summary, writer);
}
- UNLOCK(&lock);
+ UNLOCK(&contextlock);
xmlTextWriterEndElement(writer); /* contexts */