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