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