xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/dns/sdb.c (revision f8cf1a9151c7af1cb0bd8b09c13c66bca599c027)
1 /*	$NetBSD: sdb.c,v 1.1 2024/02/18 20:57:33 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 /*! \file */
17 
18 #include <inttypes.h>
19 #include <stdbool.h>
20 #include <string.h>
21 
22 #include <isc/buffer.h>
23 #include <isc/lex.h>
24 #include <isc/log.h>
25 #include <isc/magic.h>
26 #include <isc/mem.h>
27 #include <isc/once.h>
28 #include <isc/print.h>
29 #include <isc/refcount.h>
30 #include <isc/region.h>
31 #include <isc/util.h>
32 
33 #include <dns/callbacks.h>
34 #include <dns/db.h>
35 #include <dns/dbiterator.h>
36 #include <dns/fixedname.h>
37 #include <dns/log.h>
38 #include <dns/rdata.h>
39 #include <dns/rdatalist.h>
40 #include <dns/rdataset.h>
41 #include <dns/rdatasetiter.h>
42 #include <dns/rdatatype.h>
43 #include <dns/result.h>
44 #include <dns/sdb.h>
45 #include <dns/types.h>
46 
47 #include "rdatalist_p.h"
48 
49 struct dns_sdbimplementation {
50 	const dns_sdbmethods_t *methods;
51 	void *driverdata;
52 	unsigned int flags;
53 	isc_mem_t *mctx;
54 	isc_mutex_t driverlock;
55 	dns_dbimplementation_t *dbimp;
56 };
57 
58 struct dns_sdb {
59 	/* Unlocked */
60 	dns_db_t common;
61 	char *zone;
62 	dns_sdbimplementation_t *implementation;
63 	void *dbdata;
64 
65 	/* Atomic */
66 	isc_refcount_t references;
67 };
68 
69 struct dns_sdblookup {
70 	/* Unlocked */
71 	unsigned int magic;
72 	dns_sdb_t *sdb;
73 	ISC_LIST(dns_rdatalist_t) lists;
74 	ISC_LIST(isc_buffer_t) buffers;
75 	dns_name_t *name;
76 	ISC_LINK(dns_sdblookup_t) link;
77 	dns_rdatacallbacks_t callbacks;
78 
79 	/* Atomic */
80 	isc_refcount_t references;
81 };
82 
83 typedef struct dns_sdblookup dns_sdbnode_t;
84 
85 struct dns_sdballnodes {
86 	dns_dbiterator_t common;
87 	ISC_LIST(dns_sdbnode_t) nodelist;
88 	dns_sdbnode_t *current;
89 	dns_sdbnode_t *origin;
90 };
91 
92 typedef dns_sdballnodes_t sdb_dbiterator_t;
93 
94 typedef struct sdb_rdatasetiter {
95 	dns_rdatasetiter_t common;
96 	dns_rdatalist_t *current;
97 } sdb_rdatasetiter_t;
98 
99 #define SDB_MAGIC ISC_MAGIC('S', 'D', 'B', '-')
100 
101 /*%
102  * Note that "impmagic" is not the first four bytes of the struct, so
103  * ISC_MAGIC_VALID cannot be used.
104  */
105 #define VALID_SDB(sdb) ((sdb) != NULL && (sdb)->common.impmagic == SDB_MAGIC)
106 
107 #define SDBLOOKUP_MAGIC	      ISC_MAGIC('S', 'D', 'B', 'L')
108 #define VALID_SDBLOOKUP(sdbl) ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
109 #define VALID_SDBNODE(sdbn)   VALID_SDBLOOKUP(sdbn)
110 
111 /* These values are taken from RFC1537 */
112 #define SDB_DEFAULT_REFRESH 28800U  /* 8 hours */
113 #define SDB_DEFAULT_RETRY   7200U   /* 2 hours */
114 #define SDB_DEFAULT_EXPIRE  604800U /* 7 days */
115 #define SDB_DEFAULT_MINIMUM 86400U  /* 1 day */
116 
117 /* This is a reasonable value */
118 #define SDB_DEFAULT_TTL (60 * 60 * 24)
119 
120 #ifdef __COVERITY__
121 #define MAYBE_LOCK(sdb)	  LOCK(&sdb->implementation->driverlock)
122 #define MAYBE_UNLOCK(sdb) UNLOCK(&sdb->implementation->driverlock)
123 #else /* ifdef __COVERITY__ */
124 #define MAYBE_LOCK(sdb)                                          \
125 	do {                                                     \
126 		unsigned int flags = sdb->implementation->flags; \
127 		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)       \
128 			LOCK(&sdb->implementation->driverlock);  \
129 	} while (0)
130 
131 #define MAYBE_UNLOCK(sdb)                                         \
132 	do {                                                      \
133 		unsigned int flags = sdb->implementation->flags;  \
134 		if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)        \
135 			UNLOCK(&sdb->implementation->driverlock); \
136 	} while (0)
137 #endif /* ifdef __COVERITY__ */
138 
139 static int dummy;
140 
141 static isc_result_t
142 dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
143 	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
144 	       void *driverarg, dns_db_t **dbp);
145 
146 static isc_result_t
147 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
148 	     dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
149 	     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset);
150 
151 static isc_result_t
152 createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);
153 
154 static void
155 destroynode(dns_sdbnode_t *node);
156 
157 static void
158 detachnode(dns_db_t *db, dns_dbnode_t **targetp);
159 
160 static void
161 list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
162 		dns_rdataset_t *rdataset);
163 
164 static void
165 dbiterator_destroy(dns_dbiterator_t **iteratorp);
166 static isc_result_t
167 dbiterator_first(dns_dbiterator_t *iterator);
168 static isc_result_t
169 dbiterator_last(dns_dbiterator_t *iterator);
170 static isc_result_t
171 dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name);
172 static isc_result_t
173 dbiterator_prev(dns_dbiterator_t *iterator);
174 static isc_result_t
175 dbiterator_next(dns_dbiterator_t *iterator);
176 static isc_result_t
177 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
178 		   dns_name_t *name);
179 static isc_result_t
180 dbiterator_pause(dns_dbiterator_t *iterator);
181 static isc_result_t
182 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name);
183 
184 static dns_dbiteratormethods_t dbiterator_methods = {
185 	dbiterator_destroy, dbiterator_first, dbiterator_last,
186 	dbiterator_seek,    dbiterator_prev,  dbiterator_next,
187 	dbiterator_current, dbiterator_pause, dbiterator_origin
188 };
189 
190 static void
191 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
192 static isc_result_t
193 rdatasetiter_first(dns_rdatasetiter_t *iterator);
194 static isc_result_t
195 rdatasetiter_next(dns_rdatasetiter_t *iterator);
196 static void
197 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset);
198 
199 static dns_rdatasetitermethods_t rdatasetiter_methods = {
200 	rdatasetiter_destroy, rdatasetiter_first, rdatasetiter_next,
201 	rdatasetiter_current
202 };
203 
204 /*
205  * Functions used by implementors of simple databases
206  */
207 isc_result_t
208 dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
209 		 void *driverdata, unsigned int flags, isc_mem_t *mctx,
210 		 dns_sdbimplementation_t **sdbimp) {
211 	dns_sdbimplementation_t *imp;
212 	isc_result_t result;
213 
214 	REQUIRE(drivername != NULL);
215 	REQUIRE(methods != NULL);
216 	REQUIRE(methods->lookup != NULL || methods->lookup2 != NULL);
217 	REQUIRE(mctx != NULL);
218 	REQUIRE(sdbimp != NULL && *sdbimp == NULL);
219 	REQUIRE((flags &
220 		 ~(DNS_SDBFLAG_RELATIVEOWNER | DNS_SDBFLAG_RELATIVERDATA |
221 		   DNS_SDBFLAG_THREADSAFE | DNS_SDBFLAG_DNS64)) == 0);
222 
223 	imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
224 	imp->methods = methods;
225 	imp->driverdata = driverdata;
226 	imp->flags = flags;
227 	imp->mctx = NULL;
228 	isc_mem_attach(mctx, &imp->mctx);
229 	isc_mutex_init(&imp->driverlock);
230 
231 	imp->dbimp = NULL;
232 	result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
233 				 &imp->dbimp);
234 	if (result != ISC_R_SUCCESS) {
235 		goto cleanup_mutex;
236 	}
237 	*sdbimp = imp;
238 
239 	return (ISC_R_SUCCESS);
240 
241 cleanup_mutex:
242 	isc_mutex_destroy(&imp->driverlock);
243 	isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
244 	return (result);
245 }
246 
247 void
248 dns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
249 	dns_sdbimplementation_t *imp;
250 
251 	REQUIRE(sdbimp != NULL && *sdbimp != NULL);
252 
253 	imp = *sdbimp;
254 	*sdbimp = NULL;
255 	dns_db_unregister(&imp->dbimp);
256 	isc_mutex_destroy(&imp->driverlock);
257 
258 	isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_sdbimplementation_t));
259 }
260 
261 static unsigned int
262 initial_size(unsigned int len) {
263 	unsigned int size;
264 
265 	for (size = 1024; size < (64 * 1024); size *= 2) {
266 		if (len < size) {
267 			return (size);
268 		}
269 	}
270 	return (65535);
271 }
272 
273 isc_result_t
274 dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval,
275 		 dns_ttl_t ttl, const unsigned char *rdatap,
276 		 unsigned int rdlen) {
277 	dns_rdatalist_t *rdatalist;
278 	dns_rdata_t *rdata;
279 	isc_buffer_t *rdatabuf = NULL;
280 	isc_mem_t *mctx;
281 	isc_region_t region;
282 
283 	mctx = lookup->sdb->common.mctx;
284 
285 	rdatalist = ISC_LIST_HEAD(lookup->lists);
286 	while (rdatalist != NULL) {
287 		if (rdatalist->type == typeval) {
288 			break;
289 		}
290 		rdatalist = ISC_LIST_NEXT(rdatalist, link);
291 	}
292 
293 	if (rdatalist == NULL) {
294 		rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
295 		dns_rdatalist_init(rdatalist);
296 		rdatalist->rdclass = lookup->sdb->common.rdclass;
297 		rdatalist->type = typeval;
298 		rdatalist->ttl = ttl;
299 		ISC_LIST_APPEND(lookup->lists, rdatalist, link);
300 	} else if (rdatalist->ttl != ttl) {
301 		return (DNS_R_BADTTL);
302 	}
303 
304 	rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
305 
306 	isc_buffer_allocate(mctx, &rdatabuf, rdlen);
307 	DE_CONST(rdatap, region.base);
308 	region.length = rdlen;
309 	isc_buffer_copyregion(rdatabuf, &region);
310 	isc_buffer_usedregion(rdatabuf, &region);
311 	dns_rdata_init(rdata);
312 	dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
313 			     &region);
314 	ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
315 	ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
316 
317 	return (ISC_R_SUCCESS);
318 }
319 
320 isc_result_t
321 dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
322 	      const char *data) {
323 	unsigned int datalen;
324 	dns_rdatatype_t typeval;
325 	isc_textregion_t r;
326 	isc_lex_t *lex = NULL;
327 	isc_result_t result;
328 	unsigned char *p = NULL;
329 	unsigned int size = 0; /* Init to suppress compiler warning */
330 	isc_mem_t *mctx;
331 	dns_sdbimplementation_t *imp;
332 	const dns_name_t *origin;
333 	isc_buffer_t b;
334 	isc_buffer_t rb;
335 
336 	REQUIRE(VALID_SDBLOOKUP(lookup));
337 	REQUIRE(type != NULL);
338 	REQUIRE(data != NULL);
339 
340 	mctx = lookup->sdb->common.mctx;
341 
342 	DE_CONST(type, r.base);
343 	r.length = strlen(type);
344 	result = dns_rdatatype_fromtext(&typeval, &r);
345 	if (result != ISC_R_SUCCESS) {
346 		return (result);
347 	}
348 
349 	imp = lookup->sdb->implementation;
350 	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0) {
351 		origin = &lookup->sdb->common.origin;
352 	} else {
353 		origin = dns_rootname;
354 	}
355 
356 	result = isc_lex_create(mctx, 64, &lex);
357 	if (result != ISC_R_SUCCESS) {
358 		goto failure;
359 	}
360 
361 	datalen = strlen(data);
362 	size = initial_size(datalen);
363 	do {
364 		isc_buffer_constinit(&b, data, datalen);
365 		isc_buffer_add(&b, datalen);
366 		result = isc_lex_openbuffer(lex, &b);
367 		if (result != ISC_R_SUCCESS) {
368 			goto failure;
369 		}
370 
371 		if (size >= 65535) {
372 			size = 65535;
373 		}
374 		p = isc_mem_get(mctx, size);
375 		isc_buffer_init(&rb, p, size);
376 		result = dns_rdata_fromtext(NULL, lookup->sdb->common.rdclass,
377 					    typeval, lex, origin, 0, mctx, &rb,
378 					    &lookup->callbacks);
379 		if (result != ISC_R_NOSPACE) {
380 			break;
381 		}
382 
383 		/*
384 		 * Is the RR too big?
385 		 */
386 		if (size >= 65535) {
387 			break;
388 		}
389 		isc_mem_put(mctx, p, size);
390 		p = NULL;
391 		size *= 2;
392 	} while (result == ISC_R_NOSPACE);
393 
394 	if (result != ISC_R_SUCCESS) {
395 		goto failure;
396 	}
397 
398 	result = dns_sdb_putrdata(lookup, typeval, ttl, isc_buffer_base(&rb),
399 				  isc_buffer_usedlength(&rb));
400 failure:
401 	if (p != NULL) {
402 		isc_mem_put(mctx, p, size);
403 	}
404 	if (lex != NULL) {
405 		isc_lex_destroy(&lex);
406 	}
407 
408 	return (result);
409 }
410 
411 static isc_result_t
412 getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
413 	dns_name_t *newname;
414 	const dns_name_t *origin;
415 	dns_fixedname_t fnewname;
416 	dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
417 	dns_sdbimplementation_t *imp = sdb->implementation;
418 	dns_sdbnode_t *sdbnode;
419 	isc_mem_t *mctx = sdb->common.mctx;
420 	isc_buffer_t b;
421 	isc_result_t result;
422 
423 	newname = dns_fixedname_initname(&fnewname);
424 
425 	if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0) {
426 		origin = &sdb->common.origin;
427 	} else {
428 		origin = dns_rootname;
429 	}
430 	isc_buffer_constinit(&b, name, strlen(name));
431 	isc_buffer_add(&b, strlen(name));
432 
433 	result = dns_name_fromtext(newname, &b, origin, 0, NULL);
434 	if (result != ISC_R_SUCCESS) {
435 		return (result);
436 	}
437 
438 	if (allnodes->common.relative_names) {
439 		/* All names are relative to the root */
440 		unsigned int nlabels = dns_name_countlabels(newname);
441 		dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
442 	}
443 
444 	sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
445 	if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
446 		sdbnode = NULL;
447 		result = createnode(sdb, &sdbnode);
448 		if (result != ISC_R_SUCCESS) {
449 			return (result);
450 		}
451 		sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
452 		dns_name_init(sdbnode->name, NULL);
453 		dns_name_dup(newname, mctx, sdbnode->name);
454 		ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
455 		if (allnodes->origin == NULL &&
456 		    dns_name_equal(newname, &sdb->common.origin))
457 		{
458 			allnodes->origin = sdbnode;
459 		}
460 	}
461 	*nodep = sdbnode;
462 	return (ISC_R_SUCCESS);
463 }
464 
465 isc_result_t
466 dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
467 		   const char *type, dns_ttl_t ttl, const char *data) {
468 	isc_result_t result;
469 	dns_sdbnode_t *sdbnode = NULL;
470 	result = getnode(allnodes, name, &sdbnode);
471 	if (result != ISC_R_SUCCESS) {
472 		return (result);
473 	}
474 	return (dns_sdb_putrr(sdbnode, type, ttl, data));
475 }
476 
477 isc_result_t
478 dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
479 		      dns_rdatatype_t type, dns_ttl_t ttl, const void *rdata,
480 		      unsigned int rdlen) {
481 	isc_result_t result;
482 	dns_sdbnode_t *sdbnode = NULL;
483 	result = getnode(allnodes, name, &sdbnode);
484 	if (result != ISC_R_SUCCESS) {
485 		return (result);
486 	}
487 	return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
488 }
489 
490 isc_result_t
491 dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
492 	       uint32_t serial) {
493 	char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
494 	int n;
495 
496 	REQUIRE(mname != NULL);
497 	REQUIRE(rname != NULL);
498 
499 	n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u", mname, rname,
500 		     serial, SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
501 		     SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
502 	if (n >= (int)sizeof(str) || n < 0) {
503 		return (ISC_R_NOSPACE);
504 	}
505 	return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
506 }
507 
508 /*
509  * DB routines
510  */
511 
512 static void
513 attach(dns_db_t *source, dns_db_t **targetp) {
514 	dns_sdb_t *sdb = (dns_sdb_t *)source;
515 
516 	REQUIRE(VALID_SDB(sdb));
517 
518 	isc_refcount_increment(&sdb->references);
519 
520 	*targetp = source;
521 }
522 
523 static void
524 destroy(dns_sdb_t *sdb) {
525 	dns_sdbimplementation_t *imp = sdb->implementation;
526 
527 	isc_refcount_destroy(&sdb->references);
528 
529 	if (imp->methods->destroy != NULL) {
530 		MAYBE_LOCK(sdb);
531 		imp->methods->destroy(sdb->zone, imp->driverdata, &sdb->dbdata);
532 		MAYBE_UNLOCK(sdb);
533 	}
534 
535 	isc_mem_free(sdb->common.mctx, sdb->zone);
536 
537 	sdb->common.magic = 0;
538 	sdb->common.impmagic = 0;
539 
540 	dns_name_free(&sdb->common.origin, sdb->common.mctx);
541 
542 	isc_mem_putanddetach(&sdb->common.mctx, sdb, sizeof(dns_sdb_t));
543 }
544 
545 static void
546 detach(dns_db_t **dbp) {
547 	dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
548 
549 	REQUIRE(VALID_SDB(sdb));
550 
551 	*dbp = NULL;
552 
553 	if (isc_refcount_decrement(&sdb->references) == 1) {
554 		destroy(sdb);
555 	}
556 }
557 
558 static isc_result_t
559 beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
560 	UNUSED(db);
561 	UNUSED(callbacks);
562 	return (ISC_R_NOTIMPLEMENTED);
563 }
564 
565 static isc_result_t
566 endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
567 	UNUSED(db);
568 	UNUSED(callbacks);
569 	return (ISC_R_NOTIMPLEMENTED);
570 }
571 
572 static isc_result_t
573 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
574      dns_masterformat_t masterformat) {
575 	UNUSED(db);
576 	UNUSED(version);
577 	UNUSED(filename);
578 	UNUSED(masterformat);
579 	return (ISC_R_NOTIMPLEMENTED);
580 }
581 
582 static void
583 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
584 	REQUIRE(versionp != NULL && *versionp == NULL);
585 
586 	UNUSED(db);
587 
588 	*versionp = (void *)&dummy;
589 	return;
590 }
591 
592 static isc_result_t
593 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
594 	UNUSED(db);
595 	UNUSED(versionp);
596 
597 	return (ISC_R_NOTIMPLEMENTED);
598 }
599 
600 static void
601 attachversion(dns_db_t *db, dns_dbversion_t *source,
602 	      dns_dbversion_t **targetp) {
603 	REQUIRE(source != NULL && source == (void *)&dummy);
604 	REQUIRE(targetp != NULL && *targetp == NULL);
605 
606 	UNUSED(db);
607 	*targetp = source;
608 	return;
609 }
610 
611 static void
612 closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
613 	REQUIRE(versionp != NULL && *versionp == (void *)&dummy);
614 	REQUIRE(!commit);
615 
616 	UNUSED(db);
617 	UNUSED(commit);
618 
619 	*versionp = NULL;
620 }
621 
622 static isc_result_t
623 createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
624 	dns_sdbnode_t *node;
625 
626 	node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
627 
628 	node->sdb = NULL;
629 	attach((dns_db_t *)sdb, (dns_db_t **)(void *)&node->sdb);
630 	ISC_LIST_INIT(node->lists);
631 	ISC_LIST_INIT(node->buffers);
632 	ISC_LINK_INIT(node, link);
633 	node->name = NULL;
634 	dns_rdatacallbacks_init(&node->callbacks);
635 
636 	isc_refcount_init(&node->references, 1);
637 
638 	node->magic = SDBLOOKUP_MAGIC;
639 
640 	*nodep = node;
641 	return (ISC_R_SUCCESS);
642 }
643 
644 static void
645 destroynode(dns_sdbnode_t *node) {
646 	dns_rdatalist_t *list;
647 	dns_rdata_t *rdata;
648 	isc_buffer_t *b;
649 	dns_sdb_t *sdb;
650 	isc_mem_t *mctx;
651 
652 	sdb = node->sdb;
653 	mctx = sdb->common.mctx;
654 
655 	while (!ISC_LIST_EMPTY(node->lists)) {
656 		list = ISC_LIST_HEAD(node->lists);
657 		while (!ISC_LIST_EMPTY(list->rdata)) {
658 			rdata = ISC_LIST_HEAD(list->rdata);
659 			ISC_LIST_UNLINK(list->rdata, rdata, link);
660 			isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
661 		}
662 		ISC_LIST_UNLINK(node->lists, list, link);
663 		isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
664 	}
665 
666 	while (!ISC_LIST_EMPTY(node->buffers)) {
667 		b = ISC_LIST_HEAD(node->buffers);
668 		ISC_LIST_UNLINK(node->buffers, b, link);
669 		isc_buffer_free(&b);
670 	}
671 
672 	if (node->name != NULL) {
673 		dns_name_free(node->name, mctx);
674 		isc_mem_put(mctx, node->name, sizeof(dns_name_t));
675 	}
676 
677 	node->magic = 0;
678 	isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
679 	detach((dns_db_t **)(void *)&sdb);
680 }
681 
682 static isc_result_t
683 getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
684 	dns_sdb_t *sdb = (dns_sdb_t *)db;
685 	dns_sdbnode_t *node = NULL;
686 	isc_result_t result;
687 	isc_buffer_t b;
688 	char namestr[DNS_NAME_MAXTEXT + 1];
689 	dns_sdbimplementation_t *imp;
690 	dns_name_t relname;
691 	dns_name_t *name;
692 
693 	REQUIRE(VALID_SDB(sdb));
694 	REQUIRE(nodep != NULL && *nodep == NULL);
695 
696 	imp = sdb->implementation;
697 	name = &sdb->common.origin;
698 
699 	if (imp->methods->lookup2 != NULL) {
700 		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
701 			dns_name_init(&relname, NULL);
702 			name = &relname;
703 		}
704 	} else {
705 		isc_buffer_init(&b, namestr, sizeof(namestr));
706 		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
707 			dns_name_init(&relname, NULL);
708 			result = dns_name_totext(&relname, true, &b);
709 			if (result != ISC_R_SUCCESS) {
710 				return (result);
711 			}
712 		} else {
713 			result = dns_name_totext(name, true, &b);
714 			if (result != ISC_R_SUCCESS) {
715 				return (result);
716 			}
717 		}
718 		isc_buffer_putuint8(&b, 0);
719 	}
720 
721 	result = createnode(sdb, &node);
722 	if (result != ISC_R_SUCCESS) {
723 		return (result);
724 	}
725 
726 	MAYBE_LOCK(sdb);
727 	if (imp->methods->lookup2 != NULL) {
728 		result = imp->methods->lookup2(&sdb->common.origin, name,
729 					       sdb->dbdata, node, NULL, NULL);
730 	} else {
731 		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
732 					      node, NULL, NULL);
733 	}
734 	MAYBE_UNLOCK(sdb);
735 	if (result != ISC_R_SUCCESS &&
736 	    !(result == ISC_R_NOTFOUND && imp->methods->authority != NULL))
737 	{
738 		destroynode(node);
739 		return (result);
740 	}
741 
742 	if (imp->methods->authority != NULL) {
743 		MAYBE_LOCK(sdb);
744 		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
745 		MAYBE_UNLOCK(sdb);
746 		if (result != ISC_R_SUCCESS) {
747 			destroynode(node);
748 			return (result);
749 		}
750 	}
751 
752 	*nodep = node;
753 	return (ISC_R_SUCCESS);
754 }
755 
756 static isc_result_t
757 findnodeext(dns_db_t *db, const dns_name_t *name, bool create,
758 	    dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
759 	    dns_dbnode_t **nodep) {
760 	dns_sdb_t *sdb = (dns_sdb_t *)db;
761 	dns_sdbnode_t *node = NULL;
762 	isc_result_t result;
763 	isc_buffer_t b;
764 	char namestr[DNS_NAME_MAXTEXT + 1];
765 	bool isorigin;
766 	dns_sdbimplementation_t *imp;
767 	dns_name_t relname;
768 	unsigned int labels;
769 
770 	REQUIRE(VALID_SDB(sdb));
771 	REQUIRE(nodep != NULL && *nodep == NULL);
772 
773 	UNUSED(name);
774 	UNUSED(create);
775 
776 	imp = sdb->implementation;
777 
778 	isorigin = dns_name_equal(name, &sdb->common.origin);
779 
780 	if (imp->methods->lookup2 != NULL) {
781 		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
782 			labels = dns_name_countlabels(name) -
783 				 dns_name_countlabels(&db->origin);
784 			dns_name_init(&relname, NULL);
785 			dns_name_getlabelsequence(name, 0, labels, &relname);
786 			name = &relname;
787 		}
788 	} else {
789 		isc_buffer_init(&b, namestr, sizeof(namestr));
790 		if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
791 			labels = dns_name_countlabels(name) -
792 				 dns_name_countlabels(&db->origin);
793 			dns_name_init(&relname, NULL);
794 			dns_name_getlabelsequence(name, 0, labels, &relname);
795 			result = dns_name_totext(&relname, true, &b);
796 			if (result != ISC_R_SUCCESS) {
797 				return (result);
798 			}
799 		} else {
800 			result = dns_name_totext(name, true, &b);
801 			if (result != ISC_R_SUCCESS) {
802 				return (result);
803 			}
804 		}
805 		isc_buffer_putuint8(&b, 0);
806 	}
807 
808 	result = createnode(sdb, &node);
809 	if (result != ISC_R_SUCCESS) {
810 		return (result);
811 	}
812 
813 	MAYBE_LOCK(sdb);
814 	if (imp->methods->lookup2 != NULL) {
815 		result = imp->methods->lookup2(&sdb->common.origin, name,
816 					       sdb->dbdata, node, methods,
817 					       clientinfo);
818 	} else {
819 		result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata,
820 					      node, methods, clientinfo);
821 	}
822 	MAYBE_UNLOCK(sdb);
823 	if (result != ISC_R_SUCCESS && !(result == ISC_R_NOTFOUND && isorigin &&
824 					 imp->methods->authority != NULL))
825 	{
826 		destroynode(node);
827 		return (result);
828 	}
829 
830 	if (isorigin && imp->methods->authority != NULL) {
831 		MAYBE_LOCK(sdb);
832 		result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
833 		MAYBE_UNLOCK(sdb);
834 		if (result != ISC_R_SUCCESS) {
835 			destroynode(node);
836 			return (result);
837 		}
838 	}
839 
840 	*nodep = node;
841 	return (ISC_R_SUCCESS);
842 }
843 
844 static isc_result_t
845 findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
846 	dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
847 	dns_dbnode_t **nodep, dns_name_t *foundname,
848 	dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
849 	dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
850 	dns_sdb_t *sdb = (dns_sdb_t *)db;
851 	dns_dbnode_t *node = NULL;
852 	dns_fixedname_t fname;
853 	dns_rdataset_t xrdataset;
854 	dns_name_t *xname;
855 	unsigned int nlabels, olabels;
856 	isc_result_t result;
857 	unsigned int i;
858 	unsigned int flags;
859 
860 	REQUIRE(VALID_SDB(sdb));
861 	REQUIRE(nodep == NULL || *nodep == NULL);
862 	REQUIRE(version == NULL || version == (void *)&dummy);
863 
864 	UNUSED(options);
865 
866 	if (!dns_name_issubdomain(name, &db->origin)) {
867 		return (DNS_R_NXDOMAIN);
868 	}
869 
870 	olabels = dns_name_countlabels(&db->origin);
871 	nlabels = dns_name_countlabels(name);
872 
873 	xname = dns_fixedname_initname(&fname);
874 
875 	if (rdataset == NULL) {
876 		dns_rdataset_init(&xrdataset);
877 		rdataset = &xrdataset;
878 	}
879 
880 	result = DNS_R_NXDOMAIN;
881 	flags = sdb->implementation->flags;
882 	i = (flags & DNS_SDBFLAG_DNS64) != 0 ? nlabels : olabels;
883 	for (; i <= nlabels; i++) {
884 		/*
885 		 * Look up the next label.
886 		 */
887 		dns_name_getlabelsequence(name, nlabels - i, i, xname);
888 		result = findnodeext(db, xname, false, methods, clientinfo,
889 				     &node);
890 		if (result == ISC_R_NOTFOUND) {
891 			/*
892 			 * No data at zone apex?
893 			 */
894 			if (i == olabels) {
895 				return (DNS_R_BADDB);
896 			}
897 			result = DNS_R_NXDOMAIN;
898 			continue;
899 		}
900 		if (result != ISC_R_SUCCESS) {
901 			return (result);
902 		}
903 
904 		/*
905 		 * DNS64 zone's don't have DNAME or NS records.
906 		 */
907 		if ((flags & DNS_SDBFLAG_DNS64) != 0) {
908 			goto skip;
909 		}
910 
911 		/*
912 		 * DNS64 zone's don't have DNAME or NS records.
913 		 */
914 		if ((flags & DNS_SDBFLAG_DNS64) != 0) {
915 			goto skip;
916 		}
917 
918 		/*
919 		 * Look for a DNAME at the current label, unless this is
920 		 * the qname.
921 		 */
922 		if (i < nlabels) {
923 			result = findrdataset(db, node, version,
924 					      dns_rdatatype_dname, 0, now,
925 					      rdataset, sigrdataset);
926 			if (result == ISC_R_SUCCESS) {
927 				result = DNS_R_DNAME;
928 				break;
929 			}
930 		}
931 
932 		/*
933 		 * Look for an NS at the current label, unless this is the
934 		 * origin or glue is ok.
935 		 */
936 		if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
937 			result = findrdataset(db, node, version,
938 					      dns_rdatatype_ns, 0, now,
939 					      rdataset, sigrdataset);
940 			if (result == ISC_R_SUCCESS) {
941 				if (i == nlabels && type == dns_rdatatype_any) {
942 					result = DNS_R_ZONECUT;
943 					dns_rdataset_disassociate(rdataset);
944 					if (sigrdataset != NULL &&
945 					    dns_rdataset_isassociated(
946 						    sigrdataset))
947 					{
948 						dns_rdataset_disassociate(
949 							sigrdataset);
950 					}
951 				} else {
952 					result = DNS_R_DELEGATION;
953 				}
954 				break;
955 			}
956 		}
957 
958 		/*
959 		 * If the current name is not the qname, add another label
960 		 * and try again.
961 		 */
962 		if (i < nlabels) {
963 			destroynode(node);
964 			node = NULL;
965 			continue;
966 		}
967 
968 	skip:
969 		/*
970 		 * If we're looking for ANY, we're done.
971 		 */
972 		if (type == dns_rdatatype_any) {
973 			result = ISC_R_SUCCESS;
974 			break;
975 		}
976 
977 		/*
978 		 * Look for the qtype.
979 		 */
980 		result = findrdataset(db, node, version, type, 0, now, rdataset,
981 				      sigrdataset);
982 		if (result == ISC_R_SUCCESS) {
983 			break;
984 		}
985 
986 		/*
987 		 * Look for a CNAME
988 		 */
989 		if (type != dns_rdatatype_cname) {
990 			result = findrdataset(db, node, version,
991 					      dns_rdatatype_cname, 0, now,
992 					      rdataset, sigrdataset);
993 			if (result == ISC_R_SUCCESS) {
994 				result = DNS_R_CNAME;
995 				break;
996 			}
997 		}
998 
999 		result = DNS_R_NXRRSET;
1000 		break;
1001 	}
1002 
1003 	if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset)) {
1004 		dns_rdataset_disassociate(rdataset);
1005 	}
1006 
1007 	if (foundname != NULL) {
1008 		dns_name_copynf(xname, foundname);
1009 	}
1010 
1011 	if (nodep != NULL) {
1012 		*nodep = node;
1013 	} else if (node != NULL) {
1014 		detachnode(db, &node);
1015 	}
1016 
1017 	return (result);
1018 }
1019 
1020 static isc_result_t
1021 findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
1022 	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
1023 	    dns_name_t *dcname, dns_rdataset_t *rdataset,
1024 	    dns_rdataset_t *sigrdataset) {
1025 	UNUSED(db);
1026 	UNUSED(name);
1027 	UNUSED(options);
1028 	UNUSED(now);
1029 	UNUSED(nodep);
1030 	UNUSED(foundname);
1031 	UNUSED(dcname);
1032 	UNUSED(rdataset);
1033 	UNUSED(sigrdataset);
1034 
1035 	return (ISC_R_NOTIMPLEMENTED);
1036 }
1037 
1038 static void
1039 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
1040 	dns_sdb_t *sdb = (dns_sdb_t *)db;
1041 	dns_sdbnode_t *node = (dns_sdbnode_t *)source;
1042 
1043 	REQUIRE(VALID_SDB(sdb));
1044 
1045 	UNUSED(sdb);
1046 
1047 	isc_refcount_increment(&node->references);
1048 
1049 	*targetp = source;
1050 }
1051 
1052 static void
1053 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
1054 	dns_sdb_t *sdb = (dns_sdb_t *)db;
1055 	dns_sdbnode_t *node;
1056 
1057 	REQUIRE(VALID_SDB(sdb));
1058 	REQUIRE(targetp != NULL && *targetp != NULL);
1059 
1060 	UNUSED(sdb);
1061 
1062 	node = (dns_sdbnode_t *)(*targetp);
1063 
1064 	*targetp = NULL;
1065 
1066 	if (isc_refcount_decrement(&node->references) == 1) {
1067 		destroynode(node);
1068 	}
1069 }
1070 
1071 static isc_result_t
1072 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1073 	UNUSED(db);
1074 	UNUSED(node);
1075 	UNUSED(now);
1076 	UNREACHABLE();
1077 }
1078 
1079 static void
1080 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1081 	UNUSED(db);
1082 	UNUSED(node);
1083 	UNUSED(out);
1084 	return;
1085 }
1086 
1087 static isc_result_t
1088 createiterator(dns_db_t *db, unsigned int options,
1089 	       dns_dbiterator_t **iteratorp) {
1090 	dns_sdb_t *sdb = (dns_sdb_t *)db;
1091 	REQUIRE(VALID_SDB(sdb));
1092 
1093 	sdb_dbiterator_t *sdbiter;
1094 	isc_result_t result;
1095 	dns_sdbimplementation_t *imp = sdb->implementation;
1096 
1097 	if (imp->methods->allnodes == NULL) {
1098 		return (ISC_R_NOTIMPLEMENTED);
1099 	}
1100 
1101 	if ((options & DNS_DB_NSEC3ONLY) != 0 ||
1102 	    (options & DNS_DB_NONSEC3) != 0)
1103 	{
1104 		return (ISC_R_NOTIMPLEMENTED);
1105 	}
1106 
1107 	sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1108 
1109 	sdbiter->common.methods = &dbiterator_methods;
1110 	sdbiter->common.db = NULL;
1111 	dns_db_attach(db, &sdbiter->common.db);
1112 	sdbiter->common.relative_names = ((options & DNS_DB_RELATIVENAMES) !=
1113 					  0);
1114 	sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1115 	ISC_LIST_INIT(sdbiter->nodelist);
1116 	sdbiter->current = NULL;
1117 	sdbiter->origin = NULL;
1118 
1119 	MAYBE_LOCK(sdb);
1120 	result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1121 	MAYBE_UNLOCK(sdb);
1122 	if (result != ISC_R_SUCCESS) {
1123 		dbiterator_destroy((dns_dbiterator_t **)(void *)&sdbiter);
1124 		return (result);
1125 	}
1126 
1127 	if (sdbiter->origin != NULL) {
1128 		ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1129 		ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1130 	}
1131 
1132 	*iteratorp = (dns_dbiterator_t *)sdbiter;
1133 
1134 	return (ISC_R_SUCCESS);
1135 }
1136 
1137 static isc_result_t
1138 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1139 	     dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
1140 	     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
1141 	REQUIRE(VALID_SDBNODE(node));
1142 
1143 	dns_rdatalist_t *list;
1144 	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1145 
1146 	UNUSED(db);
1147 	UNUSED(version);
1148 	UNUSED(covers);
1149 	UNUSED(now);
1150 	UNUSED(sigrdataset);
1151 
1152 	if (type == dns_rdatatype_rrsig) {
1153 		return (ISC_R_NOTIMPLEMENTED);
1154 	}
1155 
1156 	list = ISC_LIST_HEAD(sdbnode->lists);
1157 	while (list != NULL) {
1158 		if (list->type == type) {
1159 			break;
1160 		}
1161 		list = ISC_LIST_NEXT(list, link);
1162 	}
1163 	if (list == NULL) {
1164 		return (ISC_R_NOTFOUND);
1165 	}
1166 
1167 	list_tordataset(list, db, node, rdataset);
1168 
1169 	return (ISC_R_SUCCESS);
1170 }
1171 
1172 static isc_result_t
1173 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1174 	     unsigned int options, isc_stdtime_t now,
1175 	     dns_rdatasetiter_t **iteratorp) {
1176 	sdb_rdatasetiter_t *iterator;
1177 
1178 	REQUIRE(version == NULL || version == &dummy);
1179 
1180 	UNUSED(version);
1181 	UNUSED(now);
1182 
1183 	iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1184 
1185 	iterator->common.magic = DNS_RDATASETITER_MAGIC;
1186 	iterator->common.methods = &rdatasetiter_methods;
1187 	iterator->common.db = db;
1188 	iterator->common.node = NULL;
1189 	attachnode(db, node, &iterator->common.node);
1190 	iterator->common.version = version;
1191 	iterator->common.options = options;
1192 	iterator->common.now = now;
1193 
1194 	*iteratorp = (dns_rdatasetiter_t *)iterator;
1195 
1196 	return (ISC_R_SUCCESS);
1197 }
1198 
1199 static isc_result_t
1200 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1201 	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1202 	    dns_rdataset_t *addedrdataset) {
1203 	UNUSED(db);
1204 	UNUSED(node);
1205 	UNUSED(version);
1206 	UNUSED(now);
1207 	UNUSED(rdataset);
1208 	UNUSED(options);
1209 	UNUSED(addedrdataset);
1210 
1211 	return (ISC_R_NOTIMPLEMENTED);
1212 }
1213 
1214 static isc_result_t
1215 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1216 		 dns_rdataset_t *rdataset, unsigned int options,
1217 		 dns_rdataset_t *newrdataset) {
1218 	UNUSED(db);
1219 	UNUSED(node);
1220 	UNUSED(version);
1221 	UNUSED(rdataset);
1222 	UNUSED(options);
1223 	UNUSED(newrdataset);
1224 
1225 	return (ISC_R_NOTIMPLEMENTED);
1226 }
1227 
1228 static isc_result_t
1229 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1230 	       dns_rdatatype_t type, dns_rdatatype_t covers) {
1231 	UNUSED(db);
1232 	UNUSED(node);
1233 	UNUSED(version);
1234 	UNUSED(type);
1235 	UNUSED(covers);
1236 
1237 	return (ISC_R_NOTIMPLEMENTED);
1238 }
1239 
1240 static bool
1241 issecure(dns_db_t *db) {
1242 	UNUSED(db);
1243 
1244 	return (false);
1245 }
1246 
1247 static unsigned int
1248 nodecount(dns_db_t *db) {
1249 	UNUSED(db);
1250 
1251 	return (0);
1252 }
1253 
1254 static bool
1255 ispersistent(dns_db_t *db) {
1256 	UNUSED(db);
1257 	return (true);
1258 }
1259 
1260 static void
1261 overmem(dns_db_t *db, bool over) {
1262 	UNUSED(db);
1263 	UNUSED(over);
1264 }
1265 
1266 static void
1267 settask(dns_db_t *db, isc_task_t *task) {
1268 	UNUSED(db);
1269 	UNUSED(task);
1270 }
1271 
1272 static dns_dbmethods_t sdb_methods = {
1273 	attach,
1274 	detach,
1275 	beginload,
1276 	endload,
1277 	NULL, /* serialize */
1278 	dump,
1279 	currentversion,
1280 	newversion,
1281 	attachversion,
1282 	closeversion,
1283 	NULL, /* findnode */
1284 	NULL, /* find */
1285 	findzonecut,
1286 	attachnode,
1287 	detachnode,
1288 	expirenode,
1289 	printnode,
1290 	createiterator,
1291 	findrdataset,
1292 	allrdatasets,
1293 	addrdataset,
1294 	subtractrdataset,
1295 	deleterdataset,
1296 	issecure,
1297 	nodecount,
1298 	ispersistent,
1299 	overmem,
1300 	settask,
1301 	getoriginnode, /* getoriginnode */
1302 	NULL,	       /* transfernode */
1303 	NULL,	       /* getnsec3parameters */
1304 	NULL,	       /* findnsec3node */
1305 	NULL,	       /* setsigningtime */
1306 	NULL,	       /* getsigningtime */
1307 	NULL,	       /* resigned */
1308 	NULL,	       /* isdnssec */
1309 	NULL,	       /* getrrsetstats */
1310 	NULL,	       /* rpz_attach */
1311 	NULL,	       /* rpz_ready */
1312 	findnodeext,
1313 	findext,
1314 	NULL, /* setcachestats */
1315 	NULL, /* hashsize */
1316 	NULL, /* nodefullname */
1317 	NULL, /* getsize */
1318 	NULL, /* setservestalettl */
1319 	NULL, /* getservestalettl */
1320 	NULL, /* setservestalerefresh */
1321 	NULL, /* getservestalerefresh */
1322 	NULL, /* setgluecachestats */
1323 	NULL  /* adjusthashsize */
1324 };
1325 
1326 static isc_result_t
1327 dns_sdb_create(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
1328 	       dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1329 	       void *driverarg, dns_db_t **dbp) {
1330 	dns_sdb_t *sdb;
1331 	isc_result_t result;
1332 	char zonestr[DNS_NAME_MAXTEXT + 1];
1333 	isc_buffer_t b;
1334 	dns_sdbimplementation_t *imp;
1335 
1336 	REQUIRE(driverarg != NULL);
1337 
1338 	imp = driverarg;
1339 
1340 	if (type != dns_dbtype_zone) {
1341 		return (ISC_R_NOTIMPLEMENTED);
1342 	}
1343 
1344 	sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1345 	memset(sdb, 0, sizeof(dns_sdb_t));
1346 
1347 	dns_name_init(&sdb->common.origin, NULL);
1348 	sdb->common.attributes = 0;
1349 	sdb->common.methods = &sdb_methods;
1350 	sdb->common.rdclass = rdclass;
1351 	sdb->common.mctx = NULL;
1352 	sdb->implementation = imp;
1353 
1354 	isc_mem_attach(mctx, &sdb->common.mctx);
1355 
1356 	result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1357 	if (result != ISC_R_SUCCESS) {
1358 		goto cleanup_lock;
1359 	}
1360 
1361 	isc_buffer_init(&b, zonestr, sizeof(zonestr));
1362 	result = dns_name_totext(origin, true, &b);
1363 	if (result != ISC_R_SUCCESS) {
1364 		goto cleanup_origin;
1365 	}
1366 	isc_buffer_putuint8(&b, 0);
1367 
1368 	sdb->zone = isc_mem_strdup(mctx, zonestr);
1369 
1370 	sdb->dbdata = NULL;
1371 	if (imp->methods->create != NULL) {
1372 		MAYBE_LOCK(sdb);
1373 		result = imp->methods->create(sdb->zone, argc, argv,
1374 					      imp->driverdata, &sdb->dbdata);
1375 		MAYBE_UNLOCK(sdb);
1376 		if (result != ISC_R_SUCCESS) {
1377 			goto cleanup_zonestr;
1378 		}
1379 	}
1380 
1381 	isc_refcount_init(&sdb->references, 1);
1382 
1383 	sdb->common.magic = DNS_DB_MAGIC;
1384 	sdb->common.impmagic = SDB_MAGIC;
1385 
1386 	*dbp = (dns_db_t *)sdb;
1387 
1388 	return (ISC_R_SUCCESS);
1389 
1390 cleanup_zonestr:
1391 	isc_mem_free(mctx, sdb->zone);
1392 cleanup_origin:
1393 	dns_name_free(&sdb->common.origin, mctx);
1394 cleanup_lock:
1395 	isc_mem_putanddetach(&mctx, sdb, sizeof(dns_sdb_t));
1396 
1397 	return (result);
1398 }
1399 
1400 /*
1401  * Rdataset Methods
1402  */
1403 
1404 static void
1405 disassociate(dns_rdataset_t *rdataset) {
1406 	dns_dbnode_t *node = rdataset->private5;
1407 	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1408 	dns_db_t *db = (dns_db_t *)sdbnode->sdb;
1409 
1410 	detachnode(db, &node);
1411 	isc__rdatalist_disassociate(rdataset);
1412 }
1413 
1414 static void
1415 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1416 	dns_dbnode_t *node = source->private5;
1417 	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1418 	dns_db_t *db = (dns_db_t *)sdbnode->sdb;
1419 	dns_dbnode_t *tempdb = NULL;
1420 
1421 	isc__rdatalist_clone(source, target);
1422 	attachnode(db, node, &tempdb);
1423 	source->private5 = tempdb;
1424 }
1425 
1426 static dns_rdatasetmethods_t sdb_rdataset_methods = {
1427 	disassociate,
1428 	isc__rdatalist_first,
1429 	isc__rdatalist_next,
1430 	isc__rdatalist_current,
1431 	rdataset_clone,
1432 	isc__rdatalist_count,
1433 	isc__rdatalist_addnoqname,
1434 	isc__rdatalist_getnoqname,
1435 	NULL, /* addclosest */
1436 	NULL, /* getclosest */
1437 	NULL, /* settrust */
1438 	NULL, /* expire */
1439 	NULL, /* clearprefetch */
1440 	NULL, /* setownercase */
1441 	NULL, /* getownercase */
1442 	NULL  /* addglue */
1443 };
1444 
1445 static void
1446 list_tordataset(dns_rdatalist_t *rdatalist, dns_db_t *db, dns_dbnode_t *node,
1447 		dns_rdataset_t *rdataset) {
1448 	/*
1449 	 * The sdb rdataset is an rdatalist with some additions.
1450 	 *	- private1 & private2 are used by the rdatalist.
1451 	 *	- private3 & private 4 are unused.
1452 	 *	- private5 is the node.
1453 	 */
1454 
1455 	/* This should never fail. */
1456 	RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1457 		      ISC_R_SUCCESS);
1458 
1459 	rdataset->methods = &sdb_rdataset_methods;
1460 	dns_db_attachnode(db, node, &rdataset->private5);
1461 }
1462 
1463 /*
1464  * Database Iterator Methods
1465  */
1466 static void
1467 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1468 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1469 	dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1470 
1471 	while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1472 		dns_sdbnode_t *node;
1473 		node = ISC_LIST_HEAD(sdbiter->nodelist);
1474 		ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1475 		destroynode(node);
1476 	}
1477 
1478 	dns_db_detach(&sdbiter->common.db);
1479 	isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1480 
1481 	*iteratorp = NULL;
1482 }
1483 
1484 static isc_result_t
1485 dbiterator_first(dns_dbiterator_t *iterator) {
1486 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1487 
1488 	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1489 	if (sdbiter->current == NULL) {
1490 		return (ISC_R_NOMORE);
1491 	} else {
1492 		return (ISC_R_SUCCESS);
1493 	}
1494 }
1495 
1496 static isc_result_t
1497 dbiterator_last(dns_dbiterator_t *iterator) {
1498 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1499 
1500 	sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1501 	if (sdbiter->current == NULL) {
1502 		return (ISC_R_NOMORE);
1503 	} else {
1504 		return (ISC_R_SUCCESS);
1505 	}
1506 }
1507 
1508 static isc_result_t
1509 dbiterator_seek(dns_dbiterator_t *iterator, const dns_name_t *name) {
1510 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1511 
1512 	sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1513 	while (sdbiter->current != NULL) {
1514 		if (dns_name_equal(sdbiter->current->name, name)) {
1515 			return (ISC_R_SUCCESS);
1516 		}
1517 		sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1518 	}
1519 	return (ISC_R_NOTFOUND);
1520 }
1521 
1522 static isc_result_t
1523 dbiterator_prev(dns_dbiterator_t *iterator) {
1524 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1525 
1526 	sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1527 	if (sdbiter->current == NULL) {
1528 		return (ISC_R_NOMORE);
1529 	} else {
1530 		return (ISC_R_SUCCESS);
1531 	}
1532 }
1533 
1534 static isc_result_t
1535 dbiterator_next(dns_dbiterator_t *iterator) {
1536 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1537 
1538 	sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1539 	if (sdbiter->current == NULL) {
1540 		return (ISC_R_NOMORE);
1541 	} else {
1542 		return (ISC_R_SUCCESS);
1543 	}
1544 }
1545 
1546 static isc_result_t
1547 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1548 		   dns_name_t *name) {
1549 	sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1550 
1551 	attachnode(iterator->db, sdbiter->current, nodep);
1552 	if (name != NULL) {
1553 		dns_name_copynf(sdbiter->current->name, name);
1554 		return (ISC_R_SUCCESS);
1555 	}
1556 	return (ISC_R_SUCCESS);
1557 }
1558 
1559 static isc_result_t
1560 dbiterator_pause(dns_dbiterator_t *iterator) {
1561 	UNUSED(iterator);
1562 	return (ISC_R_SUCCESS);
1563 }
1564 
1565 static isc_result_t
1566 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1567 	UNUSED(iterator);
1568 	dns_name_copynf(dns_rootname, name);
1569 	return (ISC_R_SUCCESS);
1570 }
1571 
1572 /*
1573  * Rdataset Iterator Methods
1574  */
1575 
1576 static void
1577 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1578 	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1579 	detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1580 	isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1581 		    sizeof(sdb_rdatasetiter_t));
1582 	*iteratorp = NULL;
1583 }
1584 
1585 static isc_result_t
1586 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1587 	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1588 	dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1589 
1590 	if (ISC_LIST_EMPTY(sdbnode->lists)) {
1591 		return (ISC_R_NOMORE);
1592 	}
1593 	sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1594 	return (ISC_R_SUCCESS);
1595 }
1596 
1597 static isc_result_t
1598 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1599 	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1600 
1601 	sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1602 	if (sdbiterator->current == NULL) {
1603 		return (ISC_R_NOMORE);
1604 	} else {
1605 		return (ISC_R_SUCCESS);
1606 	}
1607 }
1608 
1609 static void
1610 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1611 	sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1612 
1613 	list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1614 			rdataset);
1615 }
1616