xref: /minix/external/bsd/bind/dist/lib/dns/ecdb.c (revision fb9c64b2)
1 /*	$NetBSD: ecdb.c,v 1.9 2015/07/08 17:28:58 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2009-2014  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include "config.h"
20 
21 #include <isc/result.h>
22 #include <isc/util.h>
23 #include <isc/mutex.h>
24 #include <isc/mem.h>
25 
26 #include <dns/db.h>
27 #include <dns/ecdb.h>
28 #include <dns/rdata.h>
29 #include <dns/rdataset.h>
30 #include <dns/rdatasetiter.h>
31 #include <dns/rdataslab.h>
32 
33 #define ECDB_MAGIC		ISC_MAGIC('E', 'C', 'D', 'B')
34 #define VALID_ECDB(db)		((db) != NULL && \
35 				 (db)->common.impmagic == ECDB_MAGIC)
36 
37 #define ECDBNODE_MAGIC		ISC_MAGIC('E', 'C', 'D', 'N')
38 #define VALID_ECDBNODE(ecdbn)	ISC_MAGIC_VALID(ecdbn, ECDBNODE_MAGIC)
39 
40 /*%
41  * The 'ephemeral' cache DB (ecdb) implementation.  An ecdb just provides
42  * temporary storage for ongoing name resolution with the common DB interfaces.
43  * It actually doesn't cache anything.  The implementation expects any stored
44  * data is released within a short period, and does not care about the
45  * scalability in terms of the number of nodes.
46  */
47 
48 typedef struct dns_ecdb {
49 	/* Unlocked */
50 	dns_db_t			common;
51 	isc_mutex_t			lock;
52 
53 	/* Locked */
54 	unsigned int			references;
55 	ISC_LIST(struct dns_ecdbnode)	nodes;
56 } dns_ecdb_t;
57 
58 typedef struct dns_ecdbnode {
59 	/* Unlocked */
60 	unsigned int			magic;
61 	isc_mutex_t			lock;
62 	dns_ecdb_t			*ecdb;
63 	dns_name_t			name;
64 	ISC_LINK(struct dns_ecdbnode)	link;
65 
66 	/* Locked */
67 	ISC_LIST(struct rdatasetheader)	rdatasets;
68 	unsigned int			references;
69 } dns_ecdbnode_t;
70 
71 typedef struct rdatasetheader {
72 	dns_rdatatype_t			type;
73 	dns_ttl_t			ttl;
74 	dns_trust_t			trust;
75 	dns_rdatatype_t			covers;
76 	unsigned int			attributes;
77 
78 	ISC_LINK(struct rdatasetheader)	link;
79 } rdatasetheader_t;
80 
81 /* Copied from rbtdb.c */
82 #define RDATASET_ATTR_NXDOMAIN		0x0010
83 #define RDATASET_ATTR_NEGATIVE		0x0100
84 #define NXDOMAIN(header) \
85 	(((header)->attributes & RDATASET_ATTR_NXDOMAIN) != 0)
86 #define NEGATIVE(header) \
87 	(((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0)
88 
89 static isc_result_t dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin,
90 				    dns_dbtype_t type,
91 				    dns_rdataclass_t rdclass,
92 				    unsigned int argc, char *argv[],
93 				    void *driverarg, dns_db_t **dbp);
94 
95 static void rdataset_disassociate(dns_rdataset_t *rdataset);
96 static isc_result_t rdataset_first(dns_rdataset_t *rdataset);
97 static isc_result_t rdataset_next(dns_rdataset_t *rdataset);
98 static void rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata);
99 static void rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target);
100 static unsigned int rdataset_count(dns_rdataset_t *rdataset);
101 static void rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust);
102 
103 static dns_rdatasetmethods_t rdataset_methods = {
104 	rdataset_disassociate,
105 	rdataset_first,
106 	rdataset_next,
107 	rdataset_current,
108 	rdataset_clone,
109 	rdataset_count,
110 	NULL,			/* addnoqname */
111 	NULL,			/* getnoqname */
112 	NULL,			/* addclosest */
113 	NULL,			/* getclosest */
114 	NULL,			/* getadditional */
115 	NULL,			/* setadditional */
116 	NULL,			/* putadditional */
117 	rdataset_settrust,	/* settrust */
118 	NULL,			/* expire */
119 	NULL			/* clearprefetch */
120 };
121 
122 typedef struct ecdb_rdatasetiter {
123 	dns_rdatasetiter_t		common;
124 	rdatasetheader_t	       *current;
125 } ecdb_rdatasetiter_t;
126 
127 static void		rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
128 static isc_result_t	rdatasetiter_first(dns_rdatasetiter_t *iterator);
129 static isc_result_t	rdatasetiter_next(dns_rdatasetiter_t *iterator);
130 static void		rdatasetiter_current(dns_rdatasetiter_t *iterator,
131 					     dns_rdataset_t *rdataset);
132 
133 static dns_rdatasetitermethods_t rdatasetiter_methods = {
134 	rdatasetiter_destroy,
135 	rdatasetiter_first,
136 	rdatasetiter_next,
137 	rdatasetiter_current
138 };
139 
140 isc_result_t
141 dns_ecdb_register(isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
142 	REQUIRE(mctx != NULL);
143 	REQUIRE(dbimp != NULL && *dbimp == NULL);
144 
145 	return (dns_db_register("ecdb", dns_ecdb_create, NULL, mctx, dbimp));
146 }
147 
148 void
149 dns_ecdb_unregister(dns_dbimplementation_t **dbimp) {
150 	REQUIRE(dbimp != NULL && *dbimp != NULL);
151 
152 	dns_db_unregister(dbimp);
153 }
154 
155 /*%
156  * DB routines
157  */
158 
159 static void
160 attach(dns_db_t *source, dns_db_t **targetp) {
161 	dns_ecdb_t *ecdb = (dns_ecdb_t *)source;
162 
163 	REQUIRE(VALID_ECDB(ecdb));
164 	REQUIRE(targetp != NULL && *targetp == NULL);
165 
166 	LOCK(&ecdb->lock);
167 	ecdb->references++;
168 	UNLOCK(&ecdb->lock);
169 
170 	*targetp = source;
171 }
172 
173 static void
174 destroy_ecdb(dns_ecdb_t **ecdbp) {
175 	dns_ecdb_t *ecdb = *ecdbp;
176 	isc_mem_t *mctx = ecdb->common.mctx;
177 
178 	if (dns_name_dynamic(&ecdb->common.origin))
179 		dns_name_free(&ecdb->common.origin, mctx);
180 
181 	DESTROYLOCK(&ecdb->lock);
182 
183 	ecdb->common.impmagic = 0;
184 	ecdb->common.magic = 0;
185 
186 	isc_mem_putanddetach(&mctx, ecdb, sizeof(*ecdb));
187 
188 	*ecdbp = NULL;
189 }
190 
191 static void
192 detach(dns_db_t **dbp) {
193 	dns_ecdb_t *ecdb;
194 	isc_boolean_t need_destroy = ISC_FALSE;
195 
196 	REQUIRE(dbp != NULL);
197 	ecdb = (dns_ecdb_t *)*dbp;
198 	REQUIRE(VALID_ECDB(ecdb));
199 
200 	LOCK(&ecdb->lock);
201 	ecdb->references--;
202 	if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
203 		need_destroy = ISC_TRUE;
204 	UNLOCK(&ecdb->lock);
205 
206 	if (need_destroy)
207 		destroy_ecdb(&ecdb);
208 
209 	*dbp = NULL;
210 }
211 
212 static void
213 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
214 	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
215 	dns_ecdbnode_t *node = (dns_ecdbnode_t *)source;
216 
217 	REQUIRE(VALID_ECDB(ecdb));
218 	REQUIRE(VALID_ECDBNODE(node));
219 	REQUIRE(targetp != NULL && *targetp == NULL);
220 
221 	LOCK(&node->lock);
222 	INSIST(node->references > 0);
223 	node->references++;
224 	INSIST(node->references != 0);		/* Catch overflow. */
225 	UNLOCK(&node->lock);
226 
227 	*targetp = node;
228 }
229 
230 static void
231 destroynode(dns_ecdbnode_t *node) {
232 	isc_mem_t *mctx;
233 	dns_ecdb_t *ecdb = node->ecdb;
234 	isc_boolean_t need_destroydb = ISC_FALSE;
235 	rdatasetheader_t *header;
236 
237 	mctx = ecdb->common.mctx;
238 
239 	LOCK(&ecdb->lock);
240 	ISC_LIST_UNLINK(ecdb->nodes, node, link);
241 	if (ecdb->references == 0 && ISC_LIST_EMPTY(ecdb->nodes))
242 		need_destroydb = ISC_TRUE;
243 	UNLOCK(&ecdb->lock);
244 
245 	dns_name_free(&node->name, mctx);
246 
247 	while ((header = ISC_LIST_HEAD(node->rdatasets)) != NULL) {
248 		unsigned int headersize;
249 
250 		ISC_LIST_UNLINK(node->rdatasets, header, link);
251 		headersize =
252 			dns_rdataslab_size((unsigned char *)header,
253 					   sizeof(*header));
254 		isc_mem_put(mctx, header, headersize);
255 	}
256 
257 	DESTROYLOCK(&node->lock);
258 
259 	node->magic = 0;
260 	isc_mem_put(mctx, node, sizeof(*node));
261 
262 	if (need_destroydb)
263 		destroy_ecdb(&ecdb);
264 }
265 
266 static void
267 detachnode(dns_db_t *db, dns_dbnode_t **nodep) {
268 	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
269 	dns_ecdbnode_t *node;
270 	isc_boolean_t need_destroy = ISC_FALSE;
271 
272 	REQUIRE(VALID_ECDB(ecdb));
273 	REQUIRE(nodep != NULL);
274 	node = (dns_ecdbnode_t *)*nodep;
275 	REQUIRE(VALID_ECDBNODE(node));
276 
277 	UNUSED(ecdb);		/* in case REQUIRE() is empty */
278 
279 	LOCK(&node->lock);
280 	INSIST(node->references > 0);
281 	node->references--;
282 	if (node->references == 0)
283 		need_destroy = ISC_TRUE;
284 	UNLOCK(&node->lock);
285 
286 	if (need_destroy)
287 		destroynode(node);
288 
289 	*nodep = NULL;
290 }
291 
292 static isc_result_t
293 find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
294     dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
295     dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
296     dns_rdataset_t *sigrdataset)
297 {
298 	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
299 
300 	REQUIRE(VALID_ECDB(ecdb));
301 
302 	UNUSED(name);
303 	UNUSED(version);
304 	UNUSED(type);
305 	UNUSED(options);
306 	UNUSED(now);
307 	UNUSED(nodep);
308 	UNUSED(foundname);
309 	UNUSED(rdataset);
310 	UNUSED(sigrdataset);
311 
312 	return (ISC_R_NOTFOUND);
313 }
314 
315 static isc_result_t
316 findzonecut(dns_db_t *db, dns_name_t *name,
317 	    unsigned int options, isc_stdtime_t now,
318 	    dns_dbnode_t **nodep, dns_name_t *foundname,
319 	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
320 {
321 	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
322 
323 	REQUIRE(VALID_ECDB(ecdb));
324 
325 	UNUSED(name);
326 	UNUSED(options);
327 	UNUSED(now);
328 	UNUSED(nodep);
329 	UNUSED(foundname);
330 	UNUSED(rdataset);
331 	UNUSED(sigrdataset);
332 
333 	return (ISC_R_NOTFOUND);
334 }
335 
336 static isc_result_t
337 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
338 	 dns_dbnode_t **nodep)
339 {
340 	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
341 	isc_mem_t *mctx;
342 	dns_ecdbnode_t *node;
343 	isc_result_t result;
344 
345 	REQUIRE(VALID_ECDB(ecdb));
346 	REQUIRE(nodep != NULL && *nodep == NULL);
347 
348 	UNUSED(name);
349 
350 	if (create != ISC_TRUE)	{
351 		/* an 'ephemeral' node is never reused. */
352 		return (ISC_R_NOTFOUND);
353 	}
354 
355 	mctx = ecdb->common.mctx;
356 	node = isc_mem_get(mctx, sizeof(*node));
357 	if (node == NULL)
358 		return (ISC_R_NOMEMORY);
359 
360 	result = isc_mutex_init(&node->lock);
361 	if (result != ISC_R_SUCCESS) {
362 		UNEXPECTED_ERROR(__FILE__, __LINE__,
363 				 "isc_mutex_init() failed: %s",
364 				 isc_result_totext(result));
365 		isc_mem_put(mctx, node, sizeof(*node));
366 		return (ISC_R_UNEXPECTED);
367 	}
368 
369 	dns_name_init(&node->name, NULL);
370 	result = dns_name_dup(name, mctx, &node->name);
371 	if (result != ISC_R_SUCCESS) {
372 		DESTROYLOCK(&node->lock);
373 		isc_mem_put(mctx, node, sizeof(*node));
374 		return (result);
375 	}
376 	node->ecdb= ecdb;
377 	node->references = 1;
378 	ISC_LIST_INIT(node->rdatasets);
379 
380 	ISC_LINK_INIT(node, link);
381 
382 	LOCK(&ecdb->lock);
383 	ISC_LIST_APPEND(ecdb->nodes, node, link);
384 	UNLOCK(&ecdb->lock);
385 
386 	node->magic = ECDBNODE_MAGIC;
387 
388 	*nodep = node;
389 
390 	return (ISC_R_SUCCESS);
391 }
392 
393 static void
394 bind_rdataset(dns_ecdb_t *ecdb, dns_ecdbnode_t *node,
395 	      rdatasetheader_t *header, dns_rdataset_t *rdataset)
396 {
397 	unsigned char *raw;
398 
399 	/*
400 	 * Caller must be holding the node lock.
401 	 */
402 
403 	REQUIRE(!dns_rdataset_isassociated(rdataset));
404 
405 	rdataset->methods = &rdataset_methods;
406 	rdataset->rdclass = ecdb->common.rdclass;
407 	rdataset->type = header->type;
408 	rdataset->covers = header->covers;
409 	rdataset->ttl = header->ttl;
410 	rdataset->trust = header->trust;
411 	if (NXDOMAIN(header))
412 		rdataset->attributes |= DNS_RDATASETATTR_NXDOMAIN;
413 	if (NEGATIVE(header))
414 		rdataset->attributes |= DNS_RDATASETATTR_NEGATIVE;
415 
416 	rdataset->private1 = ecdb;
417 	rdataset->private2 = node;
418 	raw = (unsigned char *)header + sizeof(*header);
419 	rdataset->private3 = raw;
420 	rdataset->count = 0;
421 
422 	/*
423 	 * Reset iterator state.
424 	 */
425 	rdataset->privateuint4 = 0;
426 	rdataset->private5 = NULL;
427 
428 	INSIST(node->references > 0);
429 	node->references++;
430 }
431 
432 static isc_result_t
433 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
434 	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
435 	    dns_rdataset_t *addedrdataset)
436 {
437 	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
438 	isc_region_t r;
439 	isc_result_t result = ISC_R_SUCCESS;
440 	isc_mem_t *mctx;
441 	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
442 	rdatasetheader_t *header;
443 
444 	REQUIRE(VALID_ECDB(ecdb));
445 	REQUIRE(VALID_ECDBNODE(ecdbnode));
446 
447 	UNUSED(version);
448 	UNUSED(now);
449 	UNUSED(options);
450 
451 	mctx = ecdb->common.mctx;
452 
453 	LOCK(&ecdbnode->lock);
454 
455 	/*
456 	 * Sanity check: this implementation does not allow overriding an
457 	 * existing rdataset of the same type.
458 	 */
459 	for (header = ISC_LIST_HEAD(ecdbnode->rdatasets); header != NULL;
460 	     header = ISC_LIST_NEXT(header, link)) {
461 		INSIST(header->type != rdataset->type ||
462 		       header->covers != rdataset->covers);
463 	}
464 
465 	result = dns_rdataslab_fromrdataset(rdataset, mctx,
466 					    &r, sizeof(rdatasetheader_t));
467 	if (result != ISC_R_SUCCESS)
468 		goto unlock;
469 
470 	header = (rdatasetheader_t *)r.base;
471 	header->type = rdataset->type;
472 	header->ttl = rdataset->ttl;
473 	header->trust = rdataset->trust;
474 	header->covers = rdataset->covers;
475 	header->attributes = 0;
476 	if ((rdataset->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
477 		header->attributes |= RDATASET_ATTR_NXDOMAIN;
478 	if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
479 		header->attributes |= RDATASET_ATTR_NEGATIVE;
480 	ISC_LINK_INIT(header, link);
481 	ISC_LIST_APPEND(ecdbnode->rdatasets, header, link);
482 
483 	if (addedrdataset == NULL)
484 		goto unlock;
485 
486 	bind_rdataset(ecdb, ecdbnode, header, addedrdataset);
487 
488  unlock:
489 	UNLOCK(&ecdbnode->lock);
490 
491 	return (result);
492 }
493 
494 static isc_result_t
495 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
496 	       dns_rdatatype_t type, dns_rdatatype_t covers)
497 {
498 	UNUSED(db);
499 	UNUSED(node);
500 	UNUSED(version);
501 	UNUSED(type);
502 	UNUSED(covers);
503 
504 	return (ISC_R_NOTIMPLEMENTED);
505 }
506 
507 static isc_result_t
508 createiterator(dns_db_t *db, unsigned int options,
509 	       dns_dbiterator_t **iteratorp)
510 {
511 	UNUSED(db);
512 	UNUSED(options);
513 	UNUSED(iteratorp);
514 
515 	return (ISC_R_NOTIMPLEMENTED);
516 }
517 
518 static isc_result_t
519 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
520 	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
521 {
522 	dns_ecdb_t *ecdb = (dns_ecdb_t *)db;
523 	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)node;
524 	isc_mem_t *mctx;
525 	ecdb_rdatasetiter_t *iterator;
526 
527 	REQUIRE(VALID_ECDB(ecdb));
528 	REQUIRE(VALID_ECDBNODE(ecdbnode));
529 
530 	mctx = ecdb->common.mctx;
531 
532 	iterator = isc_mem_get(mctx, sizeof(ecdb_rdatasetiter_t));
533 	if (iterator == NULL)
534 		return (ISC_R_NOMEMORY);
535 
536 	iterator->common.magic = DNS_RDATASETITER_MAGIC;
537 	iterator->common.methods = &rdatasetiter_methods;
538 	iterator->common.db = db;
539 	iterator->common.node = NULL;
540 	attachnode(db, node, &iterator->common.node);
541 	iterator->common.version = version;
542 	iterator->common.now = now;
543 
544 	*iteratorp = (dns_rdatasetiter_t *)iterator;
545 
546 	return (ISC_R_SUCCESS);
547 }
548 
549 static dns_dbmethods_t ecdb_methods = {
550 	attach,
551 	detach,
552 	NULL,			/* beginload */
553 	NULL,			/* endload */
554 	NULL,			/* serialize */
555 	NULL,			/* dump */
556 	NULL,			/* currentversion */
557 	NULL,			/* newversion */
558 	NULL,			/* attachversion */
559 	NULL,			/* closeversion */
560 	findnode,
561 	find,
562 	findzonecut,
563 	attachnode,
564 	detachnode,
565 	NULL,			/* expirenode */
566 	NULL,			/* printnode */
567 	createiterator,		/* createiterator */
568 	NULL,			/* findrdataset */
569 	allrdatasets,
570 	addrdataset,
571 	NULL,			/* subtractrdataset */
572 	deleterdataset,
573 	NULL,			/* issecure */
574 	NULL,			/* nodecount */
575 	NULL,			/* ispersistent */
576 	NULL,			/* overmem */
577 	NULL,			/* settask */
578 	NULL,			/* getoriginnode */
579 	NULL,			/* transfernode */
580 	NULL,			/* getnsec3parameters */
581 	NULL,			/* findnsec3node */
582 	NULL,			/* setsigningtime */
583 	NULL,			/* getsigningtime */
584 	NULL,			/* resigned */
585 	NULL,			/* isdnssec */
586 	NULL,			/* getrrsetstats */
587 	NULL,			/* rpz_attach */
588 	NULL,			/* rpz_ready */
589 	NULL,			/* findnodeext */
590 	NULL,			/* findext */
591 	NULL,			/* setcachestats */
592 	NULL			/* hashsize */
593 };
594 
595 static isc_result_t
596 dns_ecdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
597 		dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
598 		void *driverarg, dns_db_t **dbp)
599 {
600 	dns_ecdb_t *ecdb;
601 	isc_result_t result;
602 
603 	REQUIRE(mctx != NULL);
604 	REQUIRE(origin == dns_rootname);
605 	REQUIRE(type == dns_dbtype_cache);
606 	REQUIRE(dbp != NULL && *dbp == NULL);
607 
608 	UNUSED(argc);
609 	UNUSED(argv);
610 	UNUSED(driverarg);
611 
612 	ecdb = isc_mem_get(mctx, sizeof(*ecdb));
613 	if (ecdb == NULL)
614 		return (ISC_R_NOMEMORY);
615 
616 	ecdb->common.attributes = DNS_DBATTR_CACHE;
617 	ecdb->common.rdclass = rdclass;
618 	ecdb->common.methods = &ecdb_methods;
619 	dns_name_init(&ecdb->common.origin, NULL);
620 	result = dns_name_dupwithoffsets(origin, mctx, &ecdb->common.origin);
621 	if (result != ISC_R_SUCCESS) {
622 		isc_mem_put(mctx, ecdb, sizeof(*ecdb));
623 		return (result);
624 	}
625 
626 	result = isc_mutex_init(&ecdb->lock);
627 	if (result != ISC_R_SUCCESS) {
628 		UNEXPECTED_ERROR(__FILE__, __LINE__,
629 				 "isc_mutex_init() failed: %s",
630 				 isc_result_totext(result));
631 		if (dns_name_dynamic(&ecdb->common.origin))
632 			dns_name_free(&ecdb->common.origin, mctx);
633 		isc_mem_put(mctx, ecdb, sizeof(*ecdb));
634 		return (ISC_R_UNEXPECTED);
635 	}
636 
637 	ecdb->references = 1;
638 	ISC_LIST_INIT(ecdb->nodes);
639 
640 	ecdb->common.mctx = NULL;
641 	isc_mem_attach(mctx, &ecdb->common.mctx);
642 	ecdb->common.impmagic = ECDB_MAGIC;
643 	ecdb->common.magic = DNS_DB_MAGIC;
644 
645 	*dbp = (dns_db_t *)ecdb;
646 
647 	return (ISC_R_SUCCESS);
648 }
649 
650 /*%
651  * Rdataset Methods
652  */
653 
654 static void
655 rdataset_disassociate(dns_rdataset_t *rdataset) {
656 	dns_db_t *db = rdataset->private1;
657 	dns_dbnode_t *node = rdataset->private2;
658 
659 	dns_db_detachnode(db, &node);
660 }
661 
662 static isc_result_t
663 rdataset_first(dns_rdataset_t *rdataset) {
664 	unsigned char *raw = rdataset->private3;
665 	unsigned int count;
666 
667 	count = raw[0] * 256 + raw[1];
668 	if (count == 0) {
669 		rdataset->private5 = NULL;
670 		return (ISC_R_NOMORE);
671 	}
672 #if DNS_RDATASET_FIXED
673 	raw += 2 + (4 * count);
674 #else
675 	raw += 2;
676 #endif
677 	/*
678 	 * The privateuint4 field is the number of rdata beyond the cursor
679 	 * position, so we decrement the total count by one before storing
680 	 * it.
681 	 */
682 	count--;
683 	rdataset->privateuint4 = count;
684 	rdataset->private5 = raw;
685 
686 	return (ISC_R_SUCCESS);
687 }
688 
689 static isc_result_t
690 rdataset_next(dns_rdataset_t *rdataset) {
691 	unsigned int count;
692 	unsigned int length;
693 	unsigned char *raw;
694 
695 	count = rdataset->privateuint4;
696 	if (count == 0)
697 		return (ISC_R_NOMORE);
698 	count--;
699 	rdataset->privateuint4 = count;
700 	raw = rdataset->private5;
701 	length = raw[0] * 256 + raw[1];
702 #if DNS_RDATASET_FIXED
703 	raw += length + 4;
704 #else
705 	raw += length + 2;
706 #endif
707 	rdataset->private5 = raw;
708 
709 	return (ISC_R_SUCCESS);
710 }
711 
712 static void
713 rdataset_current(dns_rdataset_t *rdataset, dns_rdata_t *rdata) {
714 	unsigned char *raw = rdataset->private5;
715 	isc_region_t r;
716 	unsigned int length;
717 	unsigned int flags = 0;
718 
719 	REQUIRE(raw != NULL);
720 
721 	length = raw[0] * 256 + raw[1];
722 #if DNS_RDATASET_FIXED
723 	raw += 4;
724 #else
725 	raw += 2;
726 #endif
727 	if (rdataset->type == dns_rdatatype_rrsig) {
728 		if (*raw & DNS_RDATASLAB_OFFLINE)
729 			flags |= DNS_RDATA_OFFLINE;
730 		length--;
731 		raw++;
732 	}
733 	r.length = length;
734 	r.base = raw;
735 	dns_rdata_fromregion(rdata, rdataset->rdclass, rdataset->type, &r);
736 	rdata->flags |= flags;
737 }
738 
739 static void
740 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
741 	dns_db_t *db = source->private1;
742 	dns_dbnode_t *node = source->private2;
743 	dns_dbnode_t *cloned_node = NULL;
744 
745 	attachnode(db, node, &cloned_node);
746 	*target = *source;
747 
748 	/*
749 	 * Reset iterator state.
750 	 */
751 	target->privateuint4 = 0;
752 	target->private5 = NULL;
753 }
754 
755 static unsigned int
756 rdataset_count(dns_rdataset_t *rdataset) {
757 	unsigned char *raw = rdataset->private3;
758 	unsigned int count;
759 
760 	count = raw[0] * 256 + raw[1];
761 
762 	return (count);
763 }
764 
765 static void
766 rdataset_settrust(dns_rdataset_t *rdataset, dns_trust_t trust) {
767 	rdatasetheader_t *header = rdataset->private3;
768 
769 	header--;
770 	header->trust = rdataset->trust = trust;
771 }
772 
773 /*
774  * Rdataset Iterator Methods
775  */
776 
777 static void
778 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
779 	isc_mem_t *mctx;
780 	union {
781 		dns_rdatasetiter_t *rdatasetiterator;
782 		ecdb_rdatasetiter_t *ecdbiterator;
783 	} u;
784 
785 	REQUIRE(iteratorp != NULL);
786 	REQUIRE(DNS_RDATASETITER_VALID(*iteratorp));
787 
788 	u.rdatasetiterator = *iteratorp;
789 
790 	mctx = u.ecdbiterator->common.db->mctx;
791 	u.ecdbiterator->common.magic = 0;
792 
793 	dns_db_detachnode(u.ecdbiterator->common.db,
794 			  &u.ecdbiterator->common.node);
795 	isc_mem_put(mctx, u.ecdbiterator,
796 		    sizeof(ecdb_rdatasetiter_t));
797 
798 	*iteratorp = NULL;
799 }
800 
801 static isc_result_t
802 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
803 	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
804 	dns_ecdbnode_t *ecdbnode = (dns_ecdbnode_t *)iterator->node;
805 
806 	REQUIRE(DNS_RDATASETITER_VALID(iterator));
807 
808 	if (ISC_LIST_EMPTY(ecdbnode->rdatasets))
809 		return (ISC_R_NOMORE);
810 	ecdbiterator->current = ISC_LIST_HEAD(ecdbnode->rdatasets);
811 	return (ISC_R_SUCCESS);
812 }
813 
814 static isc_result_t
815 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
816 	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
817 
818 	REQUIRE(DNS_RDATASETITER_VALID(iterator));
819 
820 	ecdbiterator->current = ISC_LIST_NEXT(ecdbiterator->current, link);
821 	if (ecdbiterator->current == NULL)
822 		return (ISC_R_NOMORE);
823 	else
824 		return (ISC_R_SUCCESS);
825 }
826 
827 static void
828 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
829 	ecdb_rdatasetiter_t *ecdbiterator = (ecdb_rdatasetiter_t *)iterator;
830 	dns_ecdb_t *ecdb;
831 
832 	ecdb = (dns_ecdb_t *)iterator->db;
833 	REQUIRE(VALID_ECDB(ecdb));
834 
835 	bind_rdataset(ecdb, iterator->node, ecdbiterator->current, rdataset);
836 }
837