xref: /netbsd-src/external/mpl/bind/dist/bin/tests/system/dyndb/driver/db.c (revision 5dd36a3bc8bf2a9dec29ceb6349550414570c447)
1 /*	$NetBSD: db.c,v 1.3 2019/01/09 16:55:02 christos Exp $	*/
2 
3 /*
4  * Database API implementation. The interface is defined in lib/dns/db.h.
5  *
6  * dns_db_*() calls on database instances backed by this driver use
7  * struct sampledb_methods to find appropriate function implementation.
8  *
9  * This example re-uses RBT DB implementation from original BIND and blindly
10  * proxies most of dns_db_*() calls to this underlying RBT DB.
11  * See struct sampledb below.
12  *
13  * Copyright (C) 2009-2015  Red Hat ; see COPYRIGHT for license
14  */
15 #include <config.h>
16 
17 #include <inttypes.h>
18 #include <stdbool.h>
19 
20 #include <isc/string.h>
21 #include <isc/util.h>
22 
23 #include <dns/db.h>
24 #include <dns/diff.h>
25 #include <dns/enumclass.h>
26 #include <dns/rbt.h>
27 #include <dns/rdatalist.h>
28 #include <dns/rdatastruct.h>
29 #include <dns/soa.h>
30 #include <dns/types.h>
31 
32 #include "db.h"
33 #include "instance.h"
34 #include "syncptr.h"
35 #include "util.h"
36 
37 #define SAMPLEDB_MAGIC			ISC_MAGIC('S', 'M', 'D', 'B')
38 #define VALID_SAMPLEDB(sampledb) \
39 	((sampledb) != NULL && (sampledb)->common.impmagic == SAMPLEDB_MAGIC)
40 
41 struct sampledb {
42 	dns_db_t			common;
43 	isc_refcount_t			refs;
44 	sample_instance_t		*inst;
45 
46 	/*
47 	 * Internal RBT database implementation provided by BIND.
48 	 * Most dns_db_* calls (find(), createiterator(), etc.)
49 	 * are blindly forwarded to this RBT DB.
50 	 */
51 	dns_db_t			*rbtdb;
52 };
53 
54 typedef struct sampledb sampledb_t;
55 
56 /*
57  * Get full DNS name from the node.
58  *
59  * @warning
60  * The code silently expects that "node" came from RBTDB and thus
61  * assumption dns_dbnode_t (from RBTDB) == dns_rbtnode_t is correct.
62  *
63  * This should work as long as we use only RBTDB and nothing else.
64  */
65 static isc_result_t
66 sample_name_fromnode(dns_dbnode_t *node, dns_name_t *name) {
67 	dns_rbtnode_t *rbtnode = (dns_rbtnode_t *) node;
68 	return (dns_rbt_fullnamefromnode(rbtnode, name));
69 }
70 
71 static void
72 attach(dns_db_t *source, dns_db_t **targetp) {
73 	sampledb_t *sampledb = (sampledb_t *)source;
74 
75 	REQUIRE(VALID_SAMPLEDB(sampledb));
76 
77 	isc_refcount_increment(&sampledb->refs);
78 	*targetp = source;
79 }
80 
81 static void
82 free_sampledb(sampledb_t *sampledb) {
83 	REQUIRE(VALID_SAMPLEDB(sampledb));
84 
85 	dns_db_detach(&sampledb->rbtdb);
86 	dns_name_free(&sampledb->common.origin, sampledb->common.mctx);
87 	isc_mem_putanddetach(&sampledb->common.mctx, sampledb, sizeof(*sampledb));
88 }
89 
90 static void
91 detach(dns_db_t **dbp) {
92 	REQUIRE(dbp != NULL && VALID_SAMPLEDB((sampledb_t *)(*dbp)));
93 	sampledb_t *sampledb = (sampledb_t *)(*dbp);
94 	*dbp = NULL;
95 
96 	if (isc_refcount_decrement(&sampledb->refs) == 1) {
97 		free_sampledb(sampledb);
98 	}
99 }
100 
101 /*
102  * This method should never be called, because DB is "persistent".
103  * See ispersistent() function. It means that database do not need to be
104  * loaded in the usual sense.
105  */
106 static isc_result_t
107 beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
108 	UNUSED(db);
109 	UNUSED(callbacks);
110 
111 	fatal_error("current implementation should never call beginload()");
112 
113 	/* Not reached */
114 	return (ISC_R_SUCCESS);
115 }
116 
117 /*
118  * This method should never be called, because DB is "persistent".
119  * See ispersistent() function. It means that database do not need to be
120  * loaded in the usual sense.
121  */
122 static isc_result_t
123 endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
124 	UNUSED(db);
125 	UNUSED(callbacks);
126 
127 	fatal_error("current implementation should never call endload()");
128 
129 	/* Not reached */
130 	return (ISC_R_SUCCESS);
131 }
132 
133 static isc_result_t
134 serialize(dns_db_t *db, dns_dbversion_t *version, FILE *file) {
135 	sampledb_t *sampledb = (sampledb_t *) db;
136 
137 	REQUIRE(VALID_SAMPLEDB(sampledb));
138 
139 	return (dns_db_serialize(sampledb->rbtdb, version, file));
140 }
141 
142 static isc_result_t
143 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
144      dns_masterformat_t masterformat)
145 {
146 
147 	UNUSED(db);
148 	UNUSED(version);
149 	UNUSED(filename);
150 	UNUSED(masterformat);
151 
152 	fatal_error("current implementation should never call dump()");
153 
154 	/* Not reached */
155 	return (ISC_R_SUCCESS);
156 }
157 
158 static void
159 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
160 	sampledb_t *sampledb = (sampledb_t *)db;
161 
162 	REQUIRE(VALID_SAMPLEDB(sampledb));
163 
164 	dns_db_currentversion(sampledb->rbtdb, versionp);
165 }
166 
167 static isc_result_t
168 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
169 	sampledb_t *sampledb = (sampledb_t *)db;
170 
171 	REQUIRE(VALID_SAMPLEDB(sampledb));
172 
173 	return (dns_db_newversion(sampledb->rbtdb, versionp));
174 }
175 
176 static void
177 attachversion(dns_db_t *db, dns_dbversion_t *source,
178 	      dns_dbversion_t **targetp)
179 {
180 	sampledb_t *sampledb = (sampledb_t *)db;
181 
182 	REQUIRE(VALID_SAMPLEDB(sampledb));
183 
184 	dns_db_attachversion(sampledb->rbtdb, source, targetp);
185 }
186 
187 static void
188 closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
189 	sampledb_t *sampledb = (sampledb_t *)db;
190 
191 	REQUIRE(VALID_SAMPLEDB(sampledb));
192 
193 	dns_db_closeversion(sampledb->rbtdb, versionp, commit);
194 }
195 
196 static isc_result_t
197 findnode(dns_db_t *db, const dns_name_t *name, bool create,
198 	 dns_dbnode_t **nodep)
199 {
200 	sampledb_t *sampledb = (sampledb_t *) db;
201 
202 	REQUIRE(VALID_SAMPLEDB(sampledb));
203 
204 	return (dns_db_findnode(sampledb->rbtdb, name, create, nodep));
205 }
206 
207 static isc_result_t
208 find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
209      dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
210      dns_dbnode_t **nodep, dns_name_t *foundname, dns_rdataset_t *rdataset,
211      dns_rdataset_t *sigrdataset)
212 {
213 	sampledb_t *sampledb = (sampledb_t *) db;
214 
215 	REQUIRE(VALID_SAMPLEDB(sampledb));
216 
217 	return (dns_db_find(sampledb->rbtdb, name, version, type,
218 			    options, now, nodep, foundname,
219 			    rdataset, sigrdataset));
220 }
221 
222 static isc_result_t
223 findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
224 	    isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
225 	    dns_name_t *dcname, dns_rdataset_t *rdataset,
226 	    dns_rdataset_t *sigrdataset)
227 {
228 	sampledb_t *sampledb = (sampledb_t *) db;
229 
230 	REQUIRE(VALID_SAMPLEDB(sampledb));
231 
232 	return (dns_db_findzonecut(sampledb->rbtdb, name, options,
233 				   now, nodep, foundname, dcname, rdataset,
234 				   sigrdataset));
235 }
236 
237 static void
238 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
239 	sampledb_t *sampledb = (sampledb_t *) db;
240 
241 	REQUIRE(VALID_SAMPLEDB(sampledb));
242 
243 	dns_db_attachnode(sampledb->rbtdb, source, targetp);
244 
245 }
246 
247 static void
248 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
249 	sampledb_t *sampledb = (sampledb_t *) db;
250 
251 	REQUIRE(VALID_SAMPLEDB(sampledb));
252 
253 	dns_db_detachnode(sampledb->rbtdb, targetp);
254 }
255 
256 static isc_result_t
257 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
258 	sampledb_t *sampledb = (sampledb_t *) db;
259 
260 	REQUIRE(VALID_SAMPLEDB(sampledb));
261 
262 	return (dns_db_expirenode(sampledb->rbtdb, node, now));
263 }
264 
265 static void
266 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
267 	sampledb_t *sampledb = (sampledb_t *) db;
268 
269 	REQUIRE(VALID_SAMPLEDB(sampledb));
270 
271 	dns_db_printnode(sampledb->rbtdb, node, out);
272 }
273 
274 static isc_result_t
275 createiterator(dns_db_t *db, unsigned int options,
276 	       dns_dbiterator_t **iteratorp)
277 {
278 	sampledb_t *sampledb = (sampledb_t *) db;
279 
280 	REQUIRE(VALID_SAMPLEDB(sampledb));
281 
282 	return (dns_db_createiterator(sampledb->rbtdb, options, iteratorp));
283 }
284 
285 static isc_result_t
286 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
287 	     dns_rdatatype_t type, dns_rdatatype_t covers, isc_stdtime_t now,
288 	     dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
289 {
290 	sampledb_t *sampledb = (sampledb_t *) db;
291 
292 	REQUIRE(VALID_SAMPLEDB(sampledb));
293 
294 	return (dns_db_findrdataset(sampledb->rbtdb, node, version, type,
295 				    covers, now, rdataset, sigrdataset));
296 }
297 
298 static isc_result_t
299 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
300 	     isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
301 {
302 	sampledb_t *sampledb = (sampledb_t *) db;
303 
304 	REQUIRE(VALID_SAMPLEDB(sampledb));
305 
306 	return (dns_db_allrdatasets(sampledb->rbtdb, node, version,
307 				    now, iteratorp));
308 }
309 
310 static isc_result_t
311 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
312 	    isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
313 	    dns_rdataset_t *addedrdataset)
314 {
315 	sampledb_t *sampledb = (sampledb_t *) db;
316 	isc_result_t result;
317 	dns_fixedname_t name;
318 
319 	REQUIRE(VALID_SAMPLEDB(sampledb));
320 
321 	dns_fixedname_init(&name);
322 	CHECK(dns_db_addrdataset(sampledb->rbtdb, node, version, now,
323 				 rdataset, options, addedrdataset));
324 	if (rdataset->type == dns_rdatatype_a ||
325 	    rdataset->type == dns_rdatatype_aaaa) {
326 		CHECK(sample_name_fromnode(node, dns_fixedname_name(&name)));
327 		CHECK(syncptrs(sampledb->inst, dns_fixedname_name(&name),
328 			       rdataset, DNS_DIFFOP_ADD));
329 	}
330 
331 cleanup:
332 	return (result);
333 }
334 
335 static isc_result_t
336 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
337 		 dns_rdataset_t *rdataset, unsigned int options,
338 		 dns_rdataset_t *newrdataset)
339 {
340 	sampledb_t *sampledb = (sampledb_t *) db;
341 	isc_result_t result;
342 	dns_fixedname_t name;
343 
344 	REQUIRE(VALID_SAMPLEDB(sampledb));
345 
346 	dns_fixedname_init(&name);
347 	result = dns_db_subtractrdataset(sampledb->rbtdb, node, version,
348 					 rdataset, options, newrdataset);
349 	if (result != ISC_R_SUCCESS && result != DNS_R_NXRRSET)
350 		goto cleanup;
351 
352 	if (rdataset->type == dns_rdatatype_a ||
353 	    rdataset->type == dns_rdatatype_aaaa) {
354 		CHECK(sample_name_fromnode(node, dns_fixedname_name(&name)));
355 		CHECK(syncptrs(sampledb->inst, dns_fixedname_name(&name),
356 			       rdataset, DNS_DIFFOP_DEL));
357 	}
358 
359 cleanup:
360 	return (result);
361 }
362 
363 /*
364  * deleterdataset() function is not used during DNS update processing so syncptr
365  * implementation is left as an exercise to the reader.
366  */
367 static isc_result_t
368 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
369 	       dns_rdatatype_t type, dns_rdatatype_t covers)
370 {
371 	sampledb_t *sampledb = (sampledb_t *) db;
372 
373 	REQUIRE(VALID_SAMPLEDB(sampledb));
374 
375 	return (dns_db_deleterdataset(sampledb->rbtdb, node, version,
376 				      type, covers));
377 }
378 
379 static bool
380 issecure(dns_db_t *db) {
381 	sampledb_t *sampledb = (sampledb_t *) db;
382 
383 	REQUIRE(VALID_SAMPLEDB(sampledb));
384 
385 	return (dns_db_issecure(sampledb->rbtdb));
386 }
387 
388 static unsigned int
389 nodecount(dns_db_t *db) {
390 	sampledb_t *sampledb = (sampledb_t *) db;
391 
392 	REQUIRE(VALID_SAMPLEDB(sampledb));
393 
394 	return (dns_db_nodecount(sampledb->rbtdb));
395 }
396 
397 /*
398  * The database does not need to be loaded from disk or written to disk.
399  * Always return true.
400  */
401 static bool
402 ispersistent(dns_db_t *db) {
403 	UNUSED(db);
404 
405 	return (true);
406 }
407 
408 static void
409 overmem(dns_db_t *db, bool over) {
410 	sampledb_t *sampledb = (sampledb_t *) db;
411 
412 	REQUIRE(VALID_SAMPLEDB(sampledb));
413 
414 	dns_db_overmem(sampledb->rbtdb, over);
415 }
416 
417 static void
418 settask(dns_db_t *db, isc_task_t *task) {
419 	sampledb_t *sampledb = (sampledb_t *) db;
420 
421 	REQUIRE(VALID_SAMPLEDB(sampledb));
422 
423 	dns_db_settask(sampledb->rbtdb, task);
424 }
425 
426 static isc_result_t
427 getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
428 	sampledb_t *sampledb = (sampledb_t *) db;
429 
430 	REQUIRE(VALID_SAMPLEDB(sampledb));
431 
432 	return (dns_db_getoriginnode(sampledb->rbtdb, nodep));
433 }
434 
435 static void
436 transfernode(dns_db_t *db, dns_dbnode_t **sourcep, dns_dbnode_t **targetp) {
437 	sampledb_t *sampledb = (sampledb_t *) db;
438 
439 	REQUIRE(VALID_SAMPLEDB(sampledb));
440 
441 	dns_db_transfernode(sampledb->rbtdb, sourcep, targetp);
442 
443 }
444 
445 static isc_result_t
446 getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
447 		   dns_hash_t *hash, uint8_t *flags,
448 		   uint16_t *iterations,
449 		   unsigned char *salt, size_t *salt_length)
450 {
451 	sampledb_t *sampledb = (sampledb_t *) db;
452 
453 	REQUIRE(VALID_SAMPLEDB(sampledb));
454 
455 	return (dns_db_getnsec3parameters(sampledb->rbtdb, version,
456 					  hash, flags, iterations,
457 					  salt, salt_length));
458 
459 }
460 
461 static isc_result_t
462 findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
463 	      dns_dbnode_t **nodep)
464 {
465 	sampledb_t *sampledb = (sampledb_t *) db;
466 
467 	REQUIRE(VALID_SAMPLEDB(sampledb));
468 
469 	return (dns_db_findnsec3node(sampledb->rbtdb, name, create, nodep));
470 }
471 
472 static isc_result_t
473 setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, isc_stdtime_t resign) {
474 	sampledb_t *sampledb = (sampledb_t *) db;
475 
476 	REQUIRE(VALID_SAMPLEDB(sampledb));
477 
478 	return (dns_db_setsigningtime(sampledb->rbtdb, rdataset, resign));
479 }
480 
481 static isc_result_t
482 getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset, dns_name_t *name) {
483 	sampledb_t *sampledb = (sampledb_t *) db;
484 
485 	REQUIRE(VALID_SAMPLEDB(sampledb));
486 
487 	return (dns_db_getsigningtime(sampledb->rbtdb, rdataset, name));
488 }
489 
490 static void
491 resigned(dns_db_t *db, dns_rdataset_t *rdataset, dns_dbversion_t *version) {
492 	sampledb_t *sampledb = (sampledb_t *) db;
493 
494 	REQUIRE(VALID_SAMPLEDB(sampledb));
495 
496 	dns_db_resigned(sampledb->rbtdb, rdataset, version);
497 }
498 
499 static bool
500 isdnssec(dns_db_t *db) {
501 	sampledb_t *sampledb = (sampledb_t *) db;
502 
503 	REQUIRE(VALID_SAMPLEDB(sampledb));
504 
505 	return (dns_db_isdnssec(sampledb->rbtdb));
506 }
507 
508 static dns_stats_t *
509 getrrsetstats(dns_db_t *db) {
510 	sampledb_t *sampledb = (sampledb_t *) db;
511 
512 	REQUIRE(VALID_SAMPLEDB(sampledb));
513 
514 	return (dns_db_getrrsetstats(sampledb->rbtdb));
515 
516 }
517 
518 static isc_result_t
519 findnodeext(dns_db_t *db, const dns_name_t *name,
520 	    bool create, dns_clientinfomethods_t *methods,
521 	    dns_clientinfo_t *clientinfo, dns_dbnode_t **nodep)
522 {
523 	sampledb_t *sampledb = (sampledb_t *) db;
524 
525 	REQUIRE(VALID_SAMPLEDB(sampledb));
526 
527 	return (dns_db_findnodeext(sampledb->rbtdb, name, create,
528 				   methods, clientinfo, nodep));
529 }
530 
531 static isc_result_t
532 findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
533 	dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
534 	dns_dbnode_t **nodep, dns_name_t *foundname,
535 	dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
536 	dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
537 {
538 	sampledb_t *sampledb = (sampledb_t *) db;
539 
540 	REQUIRE(VALID_SAMPLEDB(sampledb));
541 
542 	return (dns_db_findext(sampledb->rbtdb, name, version, type,
543 			       options, now, nodep, foundname, methods,
544 			       clientinfo, rdataset, sigrdataset));
545 }
546 
547 static isc_result_t
548 setcachestats(dns_db_t *db, isc_stats_t *stats) {
549 	sampledb_t *sampledb = (sampledb_t *) db;
550 
551 	REQUIRE(VALID_SAMPLEDB(sampledb));
552 
553 	return (dns_db_setcachestats(sampledb->rbtdb, stats));
554 }
555 
556 static size_t
557 hashsize(dns_db_t *db) {
558 	sampledb_t *sampledb = (sampledb_t *) db;
559 
560 	REQUIRE(VALID_SAMPLEDB(sampledb));
561 
562 	return (dns_db_hashsize(sampledb->rbtdb));
563 }
564 
565 /*
566  * DB interface definition. Database driver uses this structure to
567  * determine which implementation of dns_db_*() function to call.
568  */
569 static dns_dbmethods_t sampledb_methods = {
570 	attach,
571 	detach,
572 	beginload,
573 	endload,
574 	serialize,
575 	dump,
576 	currentversion,
577 	newversion,
578 	attachversion,
579 	closeversion,
580 	findnode,
581 	find,
582 	findzonecut,
583 	attachnode,
584 	detachnode,
585 	expirenode,
586 	printnode,
587 	createiterator,
588 	findrdataset,
589 	allrdatasets,
590 	addrdataset,
591 	subtractrdataset,
592 	deleterdataset,
593 	issecure,
594 	nodecount,
595 	ispersistent,
596 	overmem,
597 	settask,
598 	getoriginnode,
599 	transfernode,
600 	getnsec3parameters,
601 	findnsec3node,
602 	setsigningtime,
603 	getsigningtime,
604 	resigned,
605 	isdnssec,
606 	getrrsetstats,
607 	NULL,			/* rpz_attach */
608 	NULL,			/* rpz_ready */
609 	findnodeext,
610 	findext,
611 	setcachestats,
612 	hashsize,
613 	NULL,			/* nodefullname */
614 	NULL,			/* getsize */
615 	NULL,			/* setservestalettl */
616 	NULL,			/* getservestalettl */
617 	NULL			/* setgluecachestats */
618 };
619 
620 /* Auxiliary driver functions. */
621 
622 /*
623  * Auxiliary functions add_*() create minimal database which can be loaded.
624  * This is necessary because this driver create empty 'fake' zone which
625  * is not loaded from disk so there is no way for user to supply SOA, NS and A
626  * records.
627  *
628  * Following functions were copied from BIND 9.10.2rc1 named/server.c,
629  * credit goes to ISC.
630  */
631 static isc_result_t
632 add_soa(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
633 	const dns_name_t *origin, const dns_name_t *contact)
634 {
635 	dns_dbnode_t *node = NULL;
636 	dns_rdata_t rdata = DNS_RDATA_INIT;
637 	dns_rdatalist_t rdatalist;
638 	dns_rdataset_t rdataset;
639 	isc_result_t result;
640 	unsigned char buf[DNS_SOA_BUFFERSIZE];
641 
642 	dns_rdataset_init(&rdataset);
643 	dns_rdatalist_init(&rdatalist);
644 	CHECK(dns_soa_buildrdata(origin, contact, dns_db_class(db),
645 				 0, 28800, 7200, 604800, 86400, buf, &rdata));
646 	rdatalist.type = rdata.type;
647 	rdatalist.covers = 0;
648 	rdatalist.rdclass = rdata.rdclass;
649 	rdatalist.ttl = 86400;
650 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
651 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
652 	CHECK(dns_db_findnode(db, name, true, &node));
653 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
654  cleanup:
655 	if (node != NULL)
656 		dns_db_detachnode(db, &node);
657 	return (result);
658 }
659 
660 
661 static isc_result_t
662 add_ns(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
663        const dns_name_t *nsname)
664 {
665 	dns_dbnode_t *node = NULL;
666 	dns_rdata_ns_t ns;
667 	dns_rdata_t rdata = DNS_RDATA_INIT;
668 	dns_rdatalist_t rdatalist;
669 	dns_rdataset_t rdataset;
670 	isc_result_t result;
671 	isc_buffer_t b;
672 	unsigned char buf[DNS_NAME_MAXWIRE];
673 
674 	isc_buffer_init(&b, buf, sizeof(buf));
675 
676 	dns_rdataset_init(&rdataset);
677 	dns_rdatalist_init(&rdatalist);
678 	ns.common.rdtype = dns_rdatatype_ns;
679 	ns.common.rdclass = dns_db_class(db);
680 	ns.mctx = NULL;
681 	dns_name_init(&ns.name, NULL);
682 	dns_name_clone(nsname, &ns.name);
683 	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_ns,
684 				   &ns, &b));
685 	rdatalist.type = rdata.type;
686 	rdatalist.covers = 0;
687 	rdatalist.rdclass = rdata.rdclass;
688 	rdatalist.ttl = 86400;
689 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
690 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
691 	CHECK(dns_db_findnode(db, name, true, &node));
692 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
693  cleanup:
694 	if (node != NULL)
695 		dns_db_detachnode(db, &node);
696 	return (result);
697 }
698 
699 static isc_result_t
700 add_a(dns_db_t *db, dns_dbversion_t *version, const dns_name_t *name,
701       struct in_addr addr)
702 {
703 	dns_dbnode_t *node = NULL;
704 	dns_rdata_in_a_t a;
705 	dns_rdata_t rdata = DNS_RDATA_INIT;
706 	dns_rdatalist_t rdatalist;
707 	dns_rdataset_t rdataset;
708 	isc_result_t result;
709 	isc_buffer_t b;
710 	unsigned char buf[DNS_NAME_MAXWIRE];
711 
712 	isc_buffer_init(&b, buf, sizeof(buf));
713 
714 	dns_rdataset_init(&rdataset);
715 	dns_rdatalist_init(&rdatalist);
716 	a.common.rdtype = dns_rdatatype_a;
717 	a.common.rdclass = dns_db_class(db);
718 	a.in_addr = addr;
719 	CHECK(dns_rdata_fromstruct(&rdata, dns_db_class(db), dns_rdatatype_a,
720 				   &a, &b));
721 	rdatalist.type = rdata.type;
722 	rdatalist.covers = 0;
723 	rdatalist.rdclass = rdata.rdclass;
724 	rdatalist.ttl = 86400;
725 	ISC_LIST_APPEND(rdatalist.rdata, &rdata, link);
726 	CHECK(dns_rdatalist_tordataset(&rdatalist, &rdataset));
727 	CHECK(dns_db_findnode(db, name, true, &node));
728 	CHECK(dns_db_addrdataset(db, node, version, 0, &rdataset, 0, NULL));
729  cleanup:
730 	if (node != NULL)
731 		dns_db_detachnode(db, &node);
732 	return (result);
733 }
734 
735 /*
736  * Driver-specific implementation of dns_db_create().
737  *
738  * @param[in] argv      Database-specific parameters from dns_db_create().
739  * @param[in] driverarg Driver-specific parameter from dns_db_register().
740  */
741 isc_result_t
742 create_db(isc_mem_t *mctx, const dns_name_t *origin, dns_dbtype_t type,
743 	  dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
744 	  void *driverarg, dns_db_t **dbp)
745 {
746 	sampledb_t *sampledb = NULL;
747 	isc_result_t result;
748 	dns_dbversion_t *version = NULL;
749 	struct in_addr a_addr;
750 
751 	REQUIRE(type == dns_dbtype_zone);
752 	REQUIRE(rdclass == dns_rdataclass_in);
753 	REQUIRE(argc == 0);
754 	REQUIRE(argv != NULL);
755 	REQUIRE(driverarg != NULL); /* pointer to driver instance */
756 	REQUIRE(dbp != NULL && *dbp == NULL);
757 
758 	UNUSED(driverarg); /* no driver-specific configuration */
759 
760 	a_addr.s_addr = 0x0100007fU;
761 
762 	CHECKED_MEM_GET_PTR(mctx, sampledb);
763 	ZERO_PTR(sampledb);
764 
765 	isc_mem_attach(mctx, &sampledb->common.mctx);
766 	dns_name_init(&sampledb->common.origin, NULL);
767 
768 	sampledb->common.magic = DNS_DB_MAGIC;
769 	sampledb->common.impmagic = SAMPLEDB_MAGIC;
770 
771 	sampledb->common.methods = &sampledb_methods;
772 	sampledb->common.attributes = 0;
773 	sampledb->common.rdclass = rdclass;
774 
775 	CHECK(dns_name_dupwithoffsets(origin, mctx, &sampledb->common.origin));
776 
777 	isc_refcount_init(&sampledb->refs, 1);
778 
779 	/* Translate instance name to instance pointer. */
780 	sampledb->inst = driverarg;
781 
782 	/* Create internal instance of RBT DB implementation from BIND. */
783 	CHECK(dns_db_create(mctx, "rbt", origin, dns_dbtype_zone,
784 			    dns_rdataclass_in, 0, NULL, &sampledb->rbtdb));
785 
786 	/* Create fake SOA, NS, and A records to make database loadable. */
787 	CHECK(dns_db_newversion(sampledb->rbtdb, &version));
788 	CHECK(add_soa(sampledb->rbtdb, version, origin, origin, origin));
789 	CHECK(add_ns(sampledb->rbtdb, version, origin, origin));
790 	CHECK(add_a(sampledb->rbtdb, version, origin, a_addr));
791 	dns_db_closeversion(sampledb->rbtdb, &version, true);
792 
793 	*dbp = (dns_db_t *)sampledb;
794 
795 	return (ISC_R_SUCCESS);
796 
797 cleanup:
798 	if (sampledb != NULL) {
799 		if (dns_name_dynamic(&sampledb->common.origin))
800 			dns_name_free(&sampledb->common.origin, mctx);
801 
802 		isc_mem_putanddetach(&sampledb->common.mctx, sampledb,
803 				     sizeof(*sampledb));
804 	}
805 
806 	return (result);
807 }
808