Commit c9d7e543 authored by Brian Wellington's avatar Brian Wellington
Browse files

597. [func] dnssec-signzone is now multithreaded.

parent 04bdb234
597. [func] dnssec-signzone is now multithreaded.
596. [bug] DNS_RDATASLAB_FORCE and DNS_RDATASLAB_EXACT are
not mutually exclusive.
......
......@@ -17,17 +17,22 @@
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: dnssec-signzone.c,v 1.114 2000/12/06 00:38:12 bwelling Exp $ */
/* $Id: dnssec-signzone.c,v 1.115 2000/12/07 01:41:14 bwelling Exp $ */
#include <config.h>
#include <stdlib.h>
#include <isc/app.h>
#include <isc/commandline.h>
#include <isc/entropy.h>
#include <isc/event.h>
#include <isc/mem.h>
#include <isc/mutex.h>
#include <isc/os.h>
#include <isc/stdio.h>
#include <isc/string.h>
#include <isc/task.h>
#include <isc/util.h>
#include <dns/db.h>
......@@ -69,11 +74,24 @@ struct signer_key_struct {
ISC_LINK(signer_key_t) link;
};
#define SIGNER_EVENTCLASS ISC_EVENTCLASS(0x4453)
#define SIGNER_EVENT_WRITE (SIGNER_EVENTCLASS + 0)
#define SIGNER_EVENT_WORK (SIGNER_EVENTCLASS + 1)
typedef struct signer_event sevent_t;
struct signer_event {
ISC_EVENT_COMMON(sevent_t);
dns_fixedname_t *fname;
dns_fixedname_t *fnextname;
dns_dbnode_t *node;
};
static ISC_LIST(signer_key_t) keylist;
static unsigned int keycount = 0;
static isc_stdtime_t starttime = 0, endtime = 0, now;
static int cycle = -1;
static isc_boolean_t tryverify = ISC_FALSE;
static isc_boolean_t printstats = ISC_FALSE;
static isc_mem_t *mctx = NULL;
static isc_entropy_t *ectx = NULL;
static dns_ttl_t zonettl;
......@@ -82,6 +100,29 @@ static const dns_master_style_t *masterstyle = &dns_master_style_explicitttl;
static unsigned int nsigned = 0, nretained = 0, ndropped = 0;
static unsigned int nverified = 0, nverifyfailed = 0;
static const char *directory;
static isc_mutex_t namelock, statslock;
static isc_taskmgr_t *taskmgr = NULL;
static dns_db_t *gdb; /* The database */
static dns_dbversion_t *gversion; /* The database version */
static dns_dbiterator_t *gdbiter; /* The database iterator */
static dns_name_t *gorigin; /* The database origin */
static dns_dbnode_t *gnode = NULL; /* The "current" database node */
static dns_name_t *lastzonecut;
static isc_task_t *master = NULL;
static unsigned int ntasks = 0;
static isc_boolean_t shuttingdown = ISC_FALSE, finished = ISC_FALSE;
static unsigned int assigned = 0, completed = 0;
#define INCSTAT(counter) \
if (printstats) { \
LOCK(&statslock); \
counter++; \
UNLOCK(&statslock); \
}
static void
sign(isc_task_t *task, isc_event_t *event);
static inline void
set_bit(unsigned char *array, unsigned int index, unsigned int bit) {
......@@ -125,17 +166,17 @@ signwithkey(dns_name_t *name, dns_rdataset_t *rdataset, dns_rdata_t *rdata,
fatal("key '%s' failed to sign data: %s",
keystr, isc_result_totext(result));
}
nsigned++;
INCSTAT(nsigned);
if (tryverify) {
result = dns_dnssec_verify(name, rdataset, key,
ISC_TRUE, mctx, rdata);
if (result == ISC_R_SUCCESS) {
vbprintf(3, "\tsignature verified\n");
nverified++;
INCSTAT(nverified);
} else {
vbprintf(3, "\tsignature failed to verify\n");
nverifyfailed++;
INCSTAT(nverifyfailed);
}
}
}
......@@ -146,9 +187,8 @@ issigningkey(signer_key_t *key) {
}
static inline isc_boolean_t
iszonekey(signer_key_t *key, dns_db_t *db) {
return (ISC_TF(dns_name_equal(dst_key_name(key->key),
dns_db_origin(db)) &&
iszonekey(signer_key_t *key) {
return (ISC_TF(dns_name_equal(dst_key_name(key->key), gorigin) &&
dst_key_iszonekey(key->key)));
}
......@@ -193,14 +233,14 @@ keythatsigned(dns_rdata_sig_t *sig) {
* I'm not sure if this is completely correct, but it seems to work.
*/
static isc_boolean_t
expecttofindkey(dns_name_t *name, dns_db_t *db, dns_dbversion_t *version) {
expecttofindkey(dns_name_t *name) {
unsigned int options = DNS_DBFIND_NOWILD;
dns_fixedname_t fname;
isc_result_t result;
char namestr[DNS_NAME_FORMATSIZE];
dns_fixedname_init(&fname);
result = dns_db_find(db, name, version, dns_rdatatype_key, options,
result = dns_db_find(gdb, name, gversion, dns_rdatatype_key, options,
0, NULL, dns_fixedname_name(&fname), NULL, NULL);
switch (result) {
case ISC_R_SUCCESS:
......@@ -225,10 +265,10 @@ setverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key,
isc_result_t result;
result = dns_dnssec_verify(name, set, key->key, ISC_FALSE, mctx, sig);
if (result == ISC_R_SUCCESS) {
nverified++;
INCSTAT(nverified);
return (ISC_TRUE);
} else {
nverifyfailed++;
INCSTAT(nverifyfailed);
return (ISC_FALSE);
}
}
......@@ -239,8 +279,8 @@ setverifies(dns_name_t *name, dns_rdataset_t *set, signer_key_t *key,
* be generated.
*/
static void
signset(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
dns_dbnode_t *node, dns_name_t *name, dns_rdataset_t *set)
signset(dns_diff_t *diff, dns_dbnode_t *node, dns_name_t *name,
dns_rdataset_t *set)
{
dns_rdataset_t sigset;
dns_rdata_t sigrdata = DNS_RDATA_INIT;
......@@ -263,7 +303,7 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
ttl = ISC_MIN(set->ttl, endtime - starttime);
dns_rdataset_init(&sigset);
result = dns_db_findrdataset(db, node, version, dns_rdatatype_sig,
result = dns_db_findrdataset(gdb, node, gversion, dns_rdatatype_sig,
set->type, 0, &sigset, NULL);
if (result == ISC_R_NOTFOUND) {
result = ISC_R_SUCCESS;
......@@ -278,10 +318,8 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
arraysize = keycount;
if (!nosigs)
arraysize += dns_rdataset_count(&sigset);
wassignedby = isc_mem_get(mctx,
arraysize * sizeof(isc_boolean_t));
nowsignedby = isc_mem_get(mctx,
arraysize * sizeof(isc_boolean_t));
wassignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
nowsignedby = isc_mem_get(mctx, arraysize * sizeof(isc_boolean_t));
if (wassignedby == NULL || nowsignedby == NULL)
fatal("out of memory");
......@@ -314,7 +352,7 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
"invalid validity period\n",
sigstr);
} else if (key == NULL && !future &&
expecttofindkey(&sig.signer, db, version))
expecttofindkey(&sig.signer))
{
/* sig is dropped and not replaced */
vbprintf(2, "\tsig by %s dropped - "
......@@ -340,7 +378,7 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
wassignedby[key->position] = ISC_TRUE;
resign = ISC_TRUE;
}
} else if (iszonekey(key, db)) {
} else if (iszonekey(key)) {
if (!expired && setverifies(name, set, key, &sigrdata))
{
vbprintf(2, "\tsig by %s retained\n", sigstr);
......@@ -363,7 +401,7 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
if (keep) {
nowsignedby[key->position] = ISC_TRUE;
nretained++;
INCSTAT(nretained);
} else {
tuple = NULL;
result = dns_difftuple_create(mctx, DNS_DIFFOP_DEL,
......@@ -371,7 +409,7 @@ signset(dns_db_t *db, dns_dbversion_t *version, dns_diff_t *diff,
&tuple);
check_result(result, "dns_difftuple_create");
dns_diff_append(diff, &tuple);
ndropped++;
INCSTAT(ndropped);
}
if (resign) {
......@@ -461,7 +499,7 @@ hasnullkey(dns_rdataset_t *rdataset) {
static void
opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
dns_db_t **db)
dns_db_t **dbp)
{
char filename[256];
isc_buffer_t b;
......@@ -484,12 +522,12 @@ opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
isc_buffer_putuint8(&b, 0);
result = dns_db_create(mctx, "rbt", name, dns_dbtype_zone,
rdclass, 0, NULL, db);
rdclass, 0, NULL, dbp);
check_result(result, "dns_db_create()");
result = dns_db_load(*db, filename);
result = dns_db_load(*dbp, filename);
if (result != ISC_R_SUCCESS && result != DNS_R_SEENINCLUDE)
dns_db_detach(db);
dns_db_detach(dbp);
}
/*
......@@ -497,9 +535,7 @@ opendb(const char *prefix, dns_name_t *name, dns_rdataclass_t rdclass,
* if found.
*/
static void
importparentsig(dns_db_t *db, dns_diff_t *diff, dns_name_t *name,
dns_rdataset_t *set)
{
importparentsig(dns_diff_t *diff, dns_name_t *name, dns_rdataset_t *set) {
dns_db_t *newdb = NULL;
dns_dbnode_t *newnode = NULL;
dns_rdataset_t newset, sigset;
......@@ -511,7 +547,7 @@ importparentsig(dns_db_t *db, dns_diff_t *diff, dns_name_t *name,
dns_rdata_init(&rdata);
dns_rdata_init(&newrdata);
opendb("signedkey-", name, dns_db_class(db), &newdb);
opendb("signedkey-", name, dns_db_class(gdb), &newdb);
if (newdb == NULL)
return;
......@@ -588,7 +624,7 @@ importparentsig(dns_db_t *db, dns_diff_t *diff, dns_name_t *name,
* Looks for our signatures of child keys. If present, inform the caller.
*/
static isc_boolean_t
haschildkey(dns_db_t *db, dns_name_t *name) {
haschildkey(dns_name_t *name) {
dns_db_t *newdb = NULL;
dns_dbnode_t *newnode = NULL;
dns_rdataset_t set, sigset;
......@@ -601,7 +637,7 @@ haschildkey(dns_db_t *db, dns_name_t *name) {
dns_rdataset_init(&set);
dns_rdataset_init(&sigset);
opendb("signedkey-", name, dns_db_class(db), &newdb);
opendb("signedkey-", name, dns_db_class(gdb), &newdb);
if (newdb == NULL)
return (ISC_FALSE);
......@@ -733,9 +769,7 @@ createnullkey(dns_db_t *db, dns_dbversion_t *version, dns_name_t *name) {
* parent/child KEY signatures, and handles other exceptional cases.
*/
static void
signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
dns_name_t *name)
{
signname(dns_dbnode_t *node, dns_name_t *name) {
isc_result_t result;
dns_rdataset_t rdataset;
dns_rdatasetiter_t *rdsiter;
......@@ -762,7 +796,7 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
program, namestr);
}
atorigin = dns_name_equal(name, dns_db_origin(db));
atorigin = dns_name_equal(name, gorigin);
/*
* If this is not the origin, determine if it's a delegation point.
......@@ -771,7 +805,7 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
dns_rdataset_t nsset;
dns_rdataset_init(&nsset);
result = dns_db_findrdataset(db, node, version,
result = dns_db_findrdataset(gdb, node, gversion,
dns_rdatatype_ns, 0, 0, &nsset,
NULL);
/* Is this a delegation point? */
......@@ -788,11 +822,11 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
if (isdelegation) {
dns_rdataset_t keyset;
childkey = haschildkey(db, name);
childkey = haschildkey(name);
neednullkey = ISC_TRUE;
dns_rdataset_init(&keyset);
result = dns_db_findrdataset(db, node, version,
result = dns_db_findrdataset(gdb, node, gversion,
dns_rdatatype_key, 0, 0, &keyset,
NULL);
if (result == ISC_R_SUCCESS && childkey) {
......@@ -813,7 +847,7 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
}
if (neednullkey)
createnullkey(db, version, name);
createnullkey(gdb, gversion, name);
}
/*
......@@ -822,7 +856,7 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
dns_diff_init(mctx, &diff);
dns_rdataset_init(&rdataset);
rdsiter = NULL;
result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
check_result(result, "dns_db_allrdatasets()");
result = dns_rdatasetiter_first(rdsiter);
while (result == ISC_R_SUCCESS) {
......@@ -836,7 +870,7 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
* If this is a KEY set at the apex, look for a signedkey file.
*/
if (atorigin && rdataset.type == dns_rdatatype_key) {
importparentsig(db, &diff, name, &rdataset);
importparentsig(&diff, name, &rdataset);
goto skip;
}
......@@ -857,7 +891,7 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
nxt_setbit(&rdataset, dns_rdatatype_key);
}
signset(db, version, &diff, node, name, &rdataset);
signset(&diff, node, name, &rdataset);
skip:
dns_rdataset_disassociate(&rdataset);
......@@ -871,7 +905,7 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
}
dns_rdatasetiter_destroy(&rdsiter);
result = dns_diff_apply(&diff, db, version);
result = dns_diff_apply(&diff, gdb, gversion);
if (result != ISC_R_SUCCESS) {
char namestr[DNS_NAME_FORMATSIZE];
dns_name_format(name, namestr, sizeof namestr);
......@@ -881,7 +915,7 @@ signname(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node,
}
static inline isc_boolean_t
active_node(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
active_node(dns_dbnode_t *node) {
dns_rdatasetiter_t *rdsiter;
isc_boolean_t active = ISC_FALSE;
isc_result_t result;
......@@ -889,7 +923,7 @@ active_node(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
dns_rdataset_init(&rdataset);
rdsiter = NULL;
result = dns_db_allrdatasets(db, node, version, 0, &rdsiter);
result = dns_db_allrdatasets(gdb, node, gversion, 0, &rdsiter);
check_result(result, "dns_db_allrdatasets()");
result = dns_rdatasetiter_first(rdsiter);
while (result == ISC_R_SUCCESS) {
......@@ -911,7 +945,7 @@ active_node(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
/*
* Make sure there is no NXT record for this node.
*/
result = dns_db_deleterdataset(db, node, version,
result = dns_db_deleterdataset(gdb, node, gversion,
dns_rdatatype_nxt, 0);
if (result == DNS_R_UNCHANGED)
result = ISC_R_SUCCESS;
......@@ -922,20 +956,18 @@ active_node(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
}
static inline isc_result_t
next_active(dns_db_t *db, dns_dbversion_t *version, dns_dbiterator_t *dbiter,
dns_name_t *name, dns_dbnode_t **nodep)
{
next_active(dns_name_t *name, dns_dbnode_t **nodep) {
isc_result_t result;
isc_boolean_t active;
do {
active = ISC_FALSE;
result = dns_dbiterator_current(dbiter, nodep, name);
result = dns_dbiterator_current(gdbiter, nodep, name);
if (result == ISC_R_SUCCESS) {
active = active_node(db, version, *nodep);
active = active_node(*nodep);
if (!active) {
dns_db_detachnode(db, nodep);
result = dns_dbiterator_next(dbiter);
dns_db_detachnode(gdb, nodep);
result = dns_dbiterator_next(gdbiter);
}
}
} while (result == ISC_R_SUCCESS && !active);
......@@ -944,26 +976,25 @@ next_active(dns_db_t *db, dns_dbversion_t *version, dns_dbiterator_t *dbiter,
}
static inline isc_result_t
next_nonglue(dns_db_t *db, dns_dbversion_t *version, dns_dbiterator_t *dbiter,
dns_name_t *name, dns_dbnode_t **nodep, dns_name_t *origin,
dns_name_t *lastcut)
next_nonglue(dns_name_t *name, dns_dbnode_t **nodep, dns_name_t *origin,
dns_name_t *lastcut)
{
isc_result_t result, dresult;
isc_result_t result;
do {
result = next_active(db, version, dbiter, name, nodep);
result = next_active(name, nodep);
if (result == ISC_R_SUCCESS) {
if (dns_name_issubdomain(name, origin) &&
(lastcut == NULL ||
!dns_name_issubdomain(name, lastcut)))
return (ISC_R_SUCCESS);
dresult = dns_master_dumpnodetostream(mctx, db,
version,
*nodep, name,
masterstyle, fp);
check_result(dresult, "dns_master_dumpnodetostream");
dns_db_detachnode(db, nodep);
result = dns_dbiterator_next(dbiter);
result = dns_master_dumpnodetostream(mctx, gdb,
gversion,
*nodep, name,
masterstyle, fp);
check_result(result, "dns_master_dumpnodetostream");
dns_db_detachnode(gdb, nodep);
result = dns_dbiterator_next(gdbiter);
}
} while (result == ISC_R_SUCCESS);
return (result);
......@@ -973,20 +1004,17 @@ next_nonglue(dns_db_t *db, dns_dbversion_t *version, dns_dbiterator_t *dbiter,
* Extracts the TTL from the SOA.
*/
static dns_ttl_t
soattl(dns_db_t *db, dns_dbversion_t *version) {
soattl(void) {
dns_rdataset_t soaset;
dns_name_t *origin;
dns_fixedname_t fname;
dns_name_t *name;
isc_result_t result;
dns_ttl_t ttl;
origin = dns_db_origin(db);
dns_fixedname_init(&fname);
name = dns_fixedname_name(&fname);
dns_rdataset_init(&soaset);
result = dns_db_find(db, origin, version, dns_rdatatype_soa,
result = dns_db_find(gdb, gorigin, gversion, dns_rdatatype_soa,
0, 0, NULL, name, &soaset, NULL);
if (result != ISC_R_SUCCESS) {
char namestr[DNS_NAME_FORMATSIZE];
......@@ -999,6 +1027,9 @@ soattl(dns_db_t *db, dns_dbversion_t *version) {
return (ttl);
}
/*
* Delete any SIG records at a node.
*/
static void
cleannode(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
dns_rdatasetiter_t *rdsiter = NULL;
......@@ -1023,7 +1054,7 @@ cleannode(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
dresult = dns_db_deleterdataset(db, node, version,
dns_rdatatype_sig,
covers);
check_result(dresult, "dns_db_allrdatasets");
check_result(dresult, "dns_db_deleterdataset");
}
}
if (result != ISC_R_NOMORE)
......@@ -1033,106 +1064,232 @@ cleannode(dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node) {
}
/*
* Generates NXTs and SIGs for each non-glue name in the zone.
* Set up the iterator and global state before starting the tasks.
*/
static void
signzone(dns_db_t *db, dns_dbversion_t *version) {
isc_result_t result, nxtresult, dresult;
dns_dbnode_t *node, *nextnode;
dns_fixedname_t fname, fnextname;
dns_name_t *name, *nextname, *target, *lastcut;
dns_dbiterator_t *dbiter;
dns_name_t *origin;
presign() {
isc_result_t result;
zonettl = soattl(db, version);
gdbiter = NULL;
result = dns_db_createiterator(gdb, ISC_FALSE, &gdbiter);
check_result(result, "dns_db_createiterator()");
dns_fixedname_init(&fname);
name = dns_fixedname_name(&fname);
dns_fixedname_init(&fnextname);
nextname = dns_fixedname_name(&fnextname);
result = dns_dbiterator_first(gdbiter);
check_result(result, "dns_dbiterator_first()");
origin = dns_db_origin(db);
lastzonecut = NULL;
lastcut = NULL;
dbiter = NULL;
result = dns_db_createiterator(db, ISC_FALSE, &dbiter);
check_result(result, "dns_db_createiterator()");
result = dns_dbiterator_first(dbiter);
node = NULL;
dns_name_concatenate(origin, NULL, name, NULL);
result = next_nonglue(db, version, dbiter, name, &node, origin,
lastcut);
while (result == ISC_R_SUCCESS) {
nextnode = NULL;
if (!dns_name_equal(name, dns_db_origin(db))) {
dns_rdatasetiter_t *rdsiter = NULL;
dns_rdataset_t set;
dns_rdataset_init(&set);
result = dns_db_allrdatasets(db, node, version,
0, &rdsiter);
check_result(result, "dns_db_allrdatasets");
result = dns_rdatasetiter_first(rdsiter);
while (result == ISC_R_SUCCESS) {
dns_rdatasetiter_current(rdsiter, &set);
if (set.type == dns_rdatatype_ns) {
dns_rdataset_disassociate(&set);
break;
}
zonettl = soattl();
}
/*
* Clean up the iterator and global state after the tasks complete.
*/
static void
postsign(void) {
if (lastzonecut != NULL) {
dns_name_free(lastzonecut, mctx);
isc_mem_put(mctx, lastzonecut, sizeof(dns_name_t));
}
dns_dbiterator_destroy(&gdbiter);
}
/*
* Find the next name to nxtify & sign
*/
static isc_result_t
getnextname(dns_name_t *name, dns_name_t *nextname, dns_dbnode_t **nodep) {
isc_result_t result;
dns_dbnode_t *nextnode, *curnode;
LOCK(&namelock);
if (shuttingdown || finished) {
result = ISC_R_NOMORE;
if (gnode != NULL)
dns_db_detachnode(gdb, &gnode);
goto out;
}
if (gnode == NULL) {
dns_fixedname_t ftname;
dns_name_t *tname;
dns_fixedname_init(&ftname);
tname = dns_fixedname_name(&ftname);
result = next_nonglue(tname, &gnode, gorigin, lastzonecut);
if (result != ISC_R_SUCCESS)
fatal("failed to iterate through the zone");
}
nextnode = NULL;
curnode = NULL;
dns_dbiterator_current(gdbiter, &curnode, name);
if (!dns_name_equal(name, gorigin)) {
dns_rdatasetiter_t *rdsiter = NULL;
dns_rdataset_t set;
dns_rdataset_init(&set);
result = dns_db_allrdatasets(gdb, curnode, gversion, 0,
&rdsiter);
check_result(result, "dns_db_allrdatasets");
result = dns_rdatasetiter_first(rdsiter);
while (result == ISC_R_SUCCESS) {
dns_rdatasetiter_current(rdsiter, &set);
if (set.type == dns_rdatatype_ns) {
dns_rdataset_disassociate(&set);
result = dns_rdatasetiter_next(rdsiter);
}
if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
fatal("rdataset iteration failed: %s",
isc_result_totext(result));
if (result == ISC_R_SUCCESS) {
if (lastcut != NULL)
dns_name_free(lastcut, mctx);
else {
lastcut = isc_mem_get(mctx,
sizeof(dns_name_t));
if (lastcut == NULL)
fatal("out of memory");
}
dns_name_init(lastcut, NULL);
result = dns_name_dup(name, mctx, lastcut);
check_result(result, "dns_name_dup()");