xref: /netbsd/external/mpl/bind/dist/lib/dns/db.c (revision 4ac1c27e)
1 /*	$NetBSD: db.c,v 1.9 2023/01/25 21:43:30 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 /***
19  *** Imports
20  ***/
21 
22 #include <inttypes.h>
23 #include <stdbool.h>
24 
25 #include <isc/buffer.h>
26 #include <isc/mem.h>
27 #include <isc/once.h>
28 #include <isc/rwlock.h>
29 #include <isc/string.h>
30 #include <isc/util.h>
31 
32 #include <dns/callbacks.h>
33 #include <dns/clientinfo.h>
34 #include <dns/db.h>
35 #include <dns/dbiterator.h>
36 #include <dns/log.h>
37 #include <dns/master.h>
38 #include <dns/rdata.h>
39 #include <dns/rdataset.h>
40 #include <dns/rdatasetiter.h>
41 #include <dns/result.h>
42 
43 /***
44  *** Private Types
45  ***/
46 
47 struct dns_dbimplementation {
48 	const char *name;
49 	dns_dbcreatefunc_t create;
50 	isc_mem_t *mctx;
51 	void *driverarg;
52 	ISC_LINK(dns_dbimplementation_t) link;
53 };
54 
55 /***
56  *** Supported DB Implementations Registry
57  ***/
58 
59 /*
60  * Built in database implementations are registered here.
61  */
62 
63 #include "rbtdb.h"
64 
65 static ISC_LIST(dns_dbimplementation_t) implementations;
66 static isc_rwlock_t implock;
67 static isc_once_t once = ISC_ONCE_INIT;
68 
69 static dns_dbimplementation_t rbtimp;
70 
71 static void
initialize(void)72 initialize(void) {
73 	isc_rwlock_init(&implock, 0, 0);
74 
75 	rbtimp.name = "rbt";
76 	rbtimp.create = dns_rbtdb_create;
77 	rbtimp.mctx = NULL;
78 	rbtimp.driverarg = NULL;
79 	ISC_LINK_INIT(&rbtimp, link);
80 
81 	ISC_LIST_INIT(implementations);
82 	ISC_LIST_APPEND(implementations, &rbtimp, link);
83 }
84 
85 static dns_dbimplementation_t *
impfind(const char * name)86 impfind(const char *name) {
87 	dns_dbimplementation_t *imp;
88 
89 	for (imp = ISC_LIST_HEAD(implementations); imp != NULL;
90 	     imp = ISC_LIST_NEXT(imp, link))
91 	{
92 		if (strcasecmp(name, imp->name) == 0) {
93 			return (imp);
94 		}
95 	}
96 	return (NULL);
97 }
98 
99 /***
100  *** Basic DB Methods
101  ***/
102 
103 isc_result_t
dns_db_create(isc_mem_t * mctx,const char * db_type,const dns_name_t * origin,dns_dbtype_t type,dns_rdataclass_t rdclass,unsigned int argc,char * argv[],dns_db_t ** dbp)104 dns_db_create(isc_mem_t *mctx, const char *db_type, const dns_name_t *origin,
105 	      dns_dbtype_t type, dns_rdataclass_t rdclass, unsigned int argc,
106 	      char *argv[], dns_db_t **dbp) {
107 	dns_dbimplementation_t *impinfo;
108 
109 	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
110 
111 	/*
112 	 * Create a new database using implementation 'db_type'.
113 	 */
114 
115 	REQUIRE(dbp != NULL && *dbp == NULL);
116 	REQUIRE(dns_name_isabsolute(origin));
117 
118 	RWLOCK(&implock, isc_rwlocktype_read);
119 	impinfo = impfind(db_type);
120 	if (impinfo != NULL) {
121 		isc_result_t result;
122 		result = ((impinfo->create)(mctx, origin, type, rdclass, argc,
123 					    argv, impinfo->driverarg, dbp));
124 		RWUNLOCK(&implock, isc_rwlocktype_read);
125 		return (result);
126 	}
127 
128 	RWUNLOCK(&implock, isc_rwlocktype_read);
129 
130 	isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB,
131 		      ISC_LOG_ERROR, "unsupported database type '%s'", db_type);
132 
133 	return (ISC_R_NOTFOUND);
134 }
135 
136 void
dns_db_attach(dns_db_t * source,dns_db_t ** targetp)137 dns_db_attach(dns_db_t *source, dns_db_t **targetp) {
138 	/*
139 	 * Attach *targetp to source.
140 	 */
141 
142 	REQUIRE(DNS_DB_VALID(source));
143 	REQUIRE(targetp != NULL && *targetp == NULL);
144 
145 	(source->methods->attach)(source, targetp);
146 
147 	ENSURE(*targetp == source);
148 }
149 
150 void
dns_db_detach(dns_db_t ** dbp)151 dns_db_detach(dns_db_t **dbp) {
152 	/*
153 	 * Detach *dbp from its database.
154 	 */
155 
156 	REQUIRE(dbp != NULL);
157 	REQUIRE(DNS_DB_VALID(*dbp));
158 
159 	((*dbp)->methods->detach)(dbp);
160 
161 	ENSURE(*dbp == NULL);
162 }
163 
164 bool
dns_db_iscache(dns_db_t * db)165 dns_db_iscache(dns_db_t *db) {
166 	/*
167 	 * Does 'db' have cache semantics?
168 	 */
169 
170 	REQUIRE(DNS_DB_VALID(db));
171 
172 	if ((db->attributes & DNS_DBATTR_CACHE) != 0) {
173 		return (true);
174 	}
175 
176 	return (false);
177 }
178 
179 bool
dns_db_iszone(dns_db_t * db)180 dns_db_iszone(dns_db_t *db) {
181 	/*
182 	 * Does 'db' have zone semantics?
183 	 */
184 
185 	REQUIRE(DNS_DB_VALID(db));
186 
187 	if ((db->attributes & (DNS_DBATTR_CACHE | DNS_DBATTR_STUB)) == 0) {
188 		return (true);
189 	}
190 
191 	return (false);
192 }
193 
194 bool
dns_db_isstub(dns_db_t * db)195 dns_db_isstub(dns_db_t *db) {
196 	/*
197 	 * Does 'db' have stub semantics?
198 	 */
199 
200 	REQUIRE(DNS_DB_VALID(db));
201 
202 	if ((db->attributes & DNS_DBATTR_STUB) != 0) {
203 		return (true);
204 	}
205 
206 	return (false);
207 }
208 
209 bool
dns_db_isdnssec(dns_db_t * db)210 dns_db_isdnssec(dns_db_t *db) {
211 	/*
212 	 * Is 'db' secure or partially secure?
213 	 */
214 
215 	REQUIRE(DNS_DB_VALID(db));
216 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
217 
218 	if (db->methods->isdnssec != NULL) {
219 		return ((db->methods->isdnssec)(db));
220 	}
221 	return ((db->methods->issecure)(db));
222 }
223 
224 bool
dns_db_issecure(dns_db_t * db)225 dns_db_issecure(dns_db_t *db) {
226 	/*
227 	 * Is 'db' secure?
228 	 */
229 
230 	REQUIRE(DNS_DB_VALID(db));
231 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
232 
233 	return ((db->methods->issecure)(db));
234 }
235 
236 bool
dns_db_ispersistent(dns_db_t * db)237 dns_db_ispersistent(dns_db_t *db) {
238 	/*
239 	 * Is 'db' persistent?
240 	 */
241 
242 	REQUIRE(DNS_DB_VALID(db));
243 
244 	return ((db->methods->ispersistent)(db));
245 }
246 
247 dns_name_t *
dns_db_origin(dns_db_t * db)248 dns_db_origin(dns_db_t *db) {
249 	/*
250 	 * The origin of the database.
251 	 */
252 
253 	REQUIRE(DNS_DB_VALID(db));
254 
255 	return (&db->origin);
256 }
257 
258 dns_rdataclass_t
dns_db_class(dns_db_t * db)259 dns_db_class(dns_db_t *db) {
260 	/*
261 	 * The class of the database.
262 	 */
263 
264 	REQUIRE(DNS_DB_VALID(db));
265 
266 	return (db->rdclass);
267 }
268 
269 isc_result_t
dns_db_beginload(dns_db_t * db,dns_rdatacallbacks_t * callbacks)270 dns_db_beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
271 	/*
272 	 * Begin loading 'db'.
273 	 */
274 
275 	REQUIRE(DNS_DB_VALID(db));
276 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
277 
278 	return ((db->methods->beginload)(db, callbacks));
279 }
280 
281 isc_result_t
dns_db_endload(dns_db_t * db,dns_rdatacallbacks_t * callbacks)282 dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
283 	dns_dbonupdatelistener_t *listener;
284 
285 	/*
286 	 * Finish loading 'db'.
287 	 */
288 
289 	REQUIRE(DNS_DB_VALID(db));
290 	REQUIRE(DNS_CALLBACK_VALID(callbacks));
291 	REQUIRE(callbacks->add_private != NULL);
292 
293 	for (listener = ISC_LIST_HEAD(db->update_listeners); listener != NULL;
294 	     listener = ISC_LIST_NEXT(listener, link))
295 	{
296 		listener->onupdate(db, listener->onupdate_arg);
297 	}
298 
299 	return ((db->methods->endload)(db, callbacks));
300 }
301 
302 isc_result_t
dns_db_load(dns_db_t * db,const char * filename,dns_masterformat_t format,unsigned int options)303 dns_db_load(dns_db_t *db, const char *filename, dns_masterformat_t format,
304 	    unsigned int options) {
305 	isc_result_t result, eresult;
306 	dns_rdatacallbacks_t callbacks;
307 
308 	/*
309 	 * Load master file 'filename' into 'db'.
310 	 */
311 
312 	REQUIRE(DNS_DB_VALID(db));
313 
314 	if ((db->attributes & DNS_DBATTR_CACHE) != 0) {
315 		options |= DNS_MASTER_AGETTL;
316 	}
317 
318 	dns_rdatacallbacks_init(&callbacks);
319 	result = dns_db_beginload(db, &callbacks);
320 	if (result != ISC_R_SUCCESS) {
321 		return (result);
322 	}
323 	result = dns_master_loadfile(filename, &db->origin, &db->origin,
324 				     db->rdclass, options, 0, &callbacks, NULL,
325 				     NULL, db->mctx, format, 0);
326 	eresult = dns_db_endload(db, &callbacks);
327 	/*
328 	 * We always call dns_db_endload(), but we only want to return its
329 	 * result if dns_master_loadfile() succeeded.  If dns_master_loadfile()
330 	 * failed, we want to return the result code it gave us.
331 	 */
332 	if (eresult != ISC_R_SUCCESS &&
333 	    (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
334 	{
335 		result = eresult;
336 	}
337 
338 	return (result);
339 }
340 
341 isc_result_t
dns_db_serialize(dns_db_t * db,dns_dbversion_t * version,FILE * file)342 dns_db_serialize(dns_db_t *db, dns_dbversion_t *version, FILE *file) {
343 	REQUIRE(DNS_DB_VALID(db));
344 	if (db->methods->serialize == NULL) {
345 		return (ISC_R_NOTIMPLEMENTED);
346 	}
347 	return ((db->methods->serialize)(db, version, file));
348 }
349 
350 isc_result_t
dns_db_dump(dns_db_t * db,dns_dbversion_t * version,const char * filename)351 dns_db_dump(dns_db_t *db, dns_dbversion_t *version, const char *filename) {
352 	return ((db->methods->dump)(db, version, filename,
353 				    dns_masterformat_text));
354 }
355 
356 /***
357  *** Version Methods
358  ***/
359 
360 void
dns_db_currentversion(dns_db_t * db,dns_dbversion_t ** versionp)361 dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
362 	/*
363 	 * Open the current version for reading.
364 	 */
365 
366 	REQUIRE(DNS_DB_VALID(db));
367 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
368 	REQUIRE(versionp != NULL && *versionp == NULL);
369 
370 	(db->methods->currentversion)(db, versionp);
371 }
372 
373 isc_result_t
dns_db_newversion(dns_db_t * db,dns_dbversion_t ** versionp)374 dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp) {
375 	/*
376 	 * Open a new version for reading and writing.
377 	 */
378 
379 	REQUIRE(DNS_DB_VALID(db));
380 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
381 	REQUIRE(versionp != NULL && *versionp == NULL);
382 
383 	return ((db->methods->newversion)(db, versionp));
384 }
385 
386 void
dns_db_attachversion(dns_db_t * db,dns_dbversion_t * source,dns_dbversion_t ** targetp)387 dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source,
388 		     dns_dbversion_t **targetp) {
389 	/*
390 	 * Attach '*targetp' to 'source'.
391 	 */
392 
393 	REQUIRE(DNS_DB_VALID(db));
394 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
395 	REQUIRE(source != NULL);
396 	REQUIRE(targetp != NULL && *targetp == NULL);
397 
398 	(db->methods->attachversion)(db, source, targetp);
399 
400 	ENSURE(*targetp != NULL);
401 }
402 
403 void
dns_db_closeversion(dns_db_t * db,dns_dbversion_t ** versionp,bool commit)404 dns_db_closeversion(dns_db_t *db, dns_dbversion_t **versionp, bool commit) {
405 	dns_dbonupdatelistener_t *listener;
406 
407 	/*
408 	 * Close version '*versionp'.
409 	 */
410 
411 	REQUIRE(DNS_DB_VALID(db));
412 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
413 	REQUIRE(versionp != NULL && *versionp != NULL);
414 
415 	(db->methods->closeversion)(db, versionp, commit);
416 
417 	if (commit) {
418 		for (listener = ISC_LIST_HEAD(db->update_listeners);
419 		     listener != NULL; listener = ISC_LIST_NEXT(listener, link))
420 		{
421 			listener->onupdate(db, listener->onupdate_arg);
422 		}
423 	}
424 
425 	ENSURE(*versionp == NULL);
426 }
427 
428 /***
429  *** Node Methods
430  ***/
431 
432 isc_result_t
dns_db_findnode(dns_db_t * db,const dns_name_t * name,bool create,dns_dbnode_t ** nodep)433 dns_db_findnode(dns_db_t *db, const dns_name_t *name, bool create,
434 		dns_dbnode_t **nodep) {
435 	/*
436 	 * Find the node with name 'name'.
437 	 */
438 
439 	REQUIRE(DNS_DB_VALID(db));
440 	REQUIRE(nodep != NULL && *nodep == NULL);
441 
442 	if (db->methods->findnode != NULL) {
443 		return ((db->methods->findnode)(db, name, create, nodep));
444 	} else {
445 		return ((db->methods->findnodeext)(db, name, create, NULL, NULL,
446 						   nodep));
447 	}
448 }
449 
450 isc_result_t
dns_db_findnodeext(dns_db_t * db,const dns_name_t * name,bool create,dns_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo,dns_dbnode_t ** nodep)451 dns_db_findnodeext(dns_db_t *db, const dns_name_t *name, bool create,
452 		   dns_clientinfomethods_t *methods,
453 		   dns_clientinfo_t *clientinfo, dns_dbnode_t **nodep) {
454 	/*
455 	 * Find the node with name 'name', passing 'arg' to the database
456 	 * implementation.
457 	 */
458 
459 	REQUIRE(DNS_DB_VALID(db));
460 	REQUIRE(nodep != NULL && *nodep == NULL);
461 
462 	if (db->methods->findnodeext != NULL) {
463 		return ((db->methods->findnodeext)(db, name, create, methods,
464 						   clientinfo, nodep));
465 	} else {
466 		return ((db->methods->findnode)(db, name, create, nodep));
467 	}
468 }
469 
470 isc_result_t
dns_db_findnsec3node(dns_db_t * db,const dns_name_t * name,bool create,dns_dbnode_t ** nodep)471 dns_db_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
472 		     dns_dbnode_t **nodep) {
473 	/*
474 	 * Find the node with name 'name'.
475 	 */
476 
477 	REQUIRE(DNS_DB_VALID(db));
478 	REQUIRE(nodep != NULL && *nodep == NULL);
479 
480 	return ((db->methods->findnsec3node)(db, name, create, nodep));
481 }
482 
483 isc_result_t
dns_db_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)484 dns_db_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
485 	    dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
486 	    dns_dbnode_t **nodep, dns_name_t *foundname,
487 	    dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
488 	/*
489 	 * Find the best match for 'name' and 'type' in version 'version'
490 	 * of 'db'.
491 	 */
492 
493 	REQUIRE(DNS_DB_VALID(db));
494 	REQUIRE(type != dns_rdatatype_rrsig);
495 	REQUIRE(nodep == NULL || *nodep == NULL);
496 	REQUIRE(dns_name_hasbuffer(foundname));
497 	REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) &&
498 				     !dns_rdataset_isassociated(rdataset)));
499 	REQUIRE(sigrdataset == NULL ||
500 		(DNS_RDATASET_VALID(sigrdataset) &&
501 		 !dns_rdataset_isassociated(sigrdataset)));
502 
503 	if (db->methods->find != NULL) {
504 		return ((db->methods->find)(db, name, version, type, options,
505 					    now, nodep, foundname, rdataset,
506 					    sigrdataset));
507 	} else {
508 		return ((db->methods->findext)(db, name, version, type, options,
509 					       now, nodep, foundname, NULL,
510 					       NULL, rdataset, sigrdataset));
511 	}
512 }
513 
514 isc_result_t
dns_db_findext(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_clientinfomethods_t * methods,dns_clientinfo_t * clientinfo,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)515 dns_db_findext(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
516 	       dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
517 	       dns_dbnode_t **nodep, dns_name_t *foundname,
518 	       dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
519 	       dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
520 	/*
521 	 * Find the best match for 'name' and 'type' in version 'version'
522 	 * of 'db', passing in 'arg'.
523 	 */
524 
525 	REQUIRE(DNS_DB_VALID(db));
526 	REQUIRE(type != dns_rdatatype_rrsig);
527 	REQUIRE(nodep == NULL || *nodep == NULL);
528 	REQUIRE(dns_name_hasbuffer(foundname));
529 	REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) &&
530 				     !dns_rdataset_isassociated(rdataset)));
531 	REQUIRE(sigrdataset == NULL ||
532 		(DNS_RDATASET_VALID(sigrdataset) &&
533 		 !dns_rdataset_isassociated(sigrdataset)));
534 
535 	if (db->methods->findext != NULL) {
536 		return ((db->methods->findext)(
537 			db, name, version, type, options, now, nodep, foundname,
538 			methods, clientinfo, rdataset, sigrdataset));
539 	} else {
540 		return ((db->methods->find)(db, name, version, type, options,
541 					    now, nodep, foundname, rdataset,
542 					    sigrdataset));
543 	}
544 }
545 
546 isc_result_t
dns_db_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)547 dns_db_findzonecut(dns_db_t *db, const dns_name_t *name, unsigned int options,
548 		   isc_stdtime_t now, dns_dbnode_t **nodep,
549 		   dns_name_t *foundname, dns_name_t *dcname,
550 		   dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset) {
551 	/*
552 	 * Find the deepest known zonecut which encloses 'name' in 'db'.
553 	 * foundname is the zonecut, dcname is the deepest name we have
554 	 * in database that is part of queried name.
555 	 */
556 
557 	REQUIRE(DNS_DB_VALID(db));
558 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
559 	REQUIRE(nodep == NULL || *nodep == NULL);
560 	REQUIRE(dns_name_hasbuffer(foundname));
561 	REQUIRE(sigrdataset == NULL ||
562 		(DNS_RDATASET_VALID(sigrdataset) &&
563 		 !dns_rdataset_isassociated(sigrdataset)));
564 
565 	return ((db->methods->findzonecut)(db, name, options, now, nodep,
566 					   foundname, dcname, rdataset,
567 					   sigrdataset));
568 }
569 
570 void
dns_db_attachnode(dns_db_t * db,dns_dbnode_t * source,dns_dbnode_t ** targetp)571 dns_db_attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
572 	/*
573 	 * Attach *targetp to source.
574 	 */
575 
576 	REQUIRE(DNS_DB_VALID(db));
577 	REQUIRE(source != NULL);
578 	REQUIRE(targetp != NULL && *targetp == NULL);
579 
580 	(db->methods->attachnode)(db, source, targetp);
581 }
582 
583 void
dns_db_detachnode(dns_db_t * db,dns_dbnode_t ** nodep)584 dns_db_detachnode(dns_db_t *db, dns_dbnode_t **nodep) {
585 	/*
586 	 * Detach *nodep from its node.
587 	 */
588 
589 	REQUIRE(DNS_DB_VALID(db));
590 	REQUIRE(nodep != NULL && *nodep != NULL);
591 
592 	(db->methods->detachnode)(db, nodep);
593 
594 	ENSURE(*nodep == NULL);
595 }
596 
597 void
dns_db_transfernode(dns_db_t * db,dns_dbnode_t ** sourcep,dns_dbnode_t ** targetp)598 dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep,
599 		    dns_dbnode_t **targetp) {
600 	REQUIRE(DNS_DB_VALID(db));
601 	REQUIRE(targetp != NULL && *targetp == NULL);
602 	/*
603 	 * This doesn't check the implementation magic.  If we find that
604 	 * we need such checks in future then this will be done in the
605 	 * method.
606 	 */
607 	REQUIRE(sourcep != NULL && *sourcep != NULL);
608 
609 	UNUSED(db);
610 
611 	if (db->methods->transfernode == NULL) {
612 		*targetp = *sourcep;
613 		*sourcep = NULL;
614 	} else {
615 		(db->methods->transfernode)(db, sourcep, targetp);
616 	}
617 
618 	ENSURE(*sourcep == NULL);
619 }
620 
621 isc_result_t
dns_db_expirenode(dns_db_t * db,dns_dbnode_t * node,isc_stdtime_t now)622 dns_db_expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
623 	/*
624 	 * Mark as stale all records at 'node' which expire at or before 'now'.
625 	 */
626 
627 	REQUIRE(DNS_DB_VALID(db));
628 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
629 	REQUIRE(node != NULL);
630 
631 	return ((db->methods->expirenode)(db, node, now));
632 }
633 
634 void
dns_db_printnode(dns_db_t * db,dns_dbnode_t * node,FILE * out)635 dns_db_printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
636 	/*
637 	 * Print a textual representation of the contents of the node to
638 	 * 'out'.
639 	 */
640 
641 	REQUIRE(DNS_DB_VALID(db));
642 	REQUIRE(node != NULL);
643 
644 	(db->methods->printnode)(db, node, out);
645 }
646 
647 /***
648  *** DB Iterator Creation
649  ***/
650 
651 isc_result_t
dns_db_createiterator(dns_db_t * db,unsigned int flags,dns_dbiterator_t ** iteratorp)652 dns_db_createiterator(dns_db_t *db, unsigned int flags,
653 		      dns_dbiterator_t **iteratorp) {
654 	/*
655 	 * Create an iterator for version 'version' of 'db'.
656 	 */
657 
658 	REQUIRE(DNS_DB_VALID(db));
659 	REQUIRE(iteratorp != NULL && *iteratorp == NULL);
660 
661 	return (db->methods->createiterator(db, flags, iteratorp));
662 }
663 
664 /***
665  *** Rdataset Methods
666  ***/
667 
668 isc_result_t
dns_db_findrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdatatype_t type,dns_rdatatype_t covers,isc_stdtime_t now,dns_rdataset_t * rdataset,dns_rdataset_t * sigrdataset)669 dns_db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
670 		    dns_rdatatype_t type, dns_rdatatype_t covers,
671 		    isc_stdtime_t now, dns_rdataset_t *rdataset,
672 		    dns_rdataset_t *sigrdataset) {
673 	REQUIRE(DNS_DB_VALID(db));
674 	REQUIRE(node != NULL);
675 	REQUIRE(DNS_RDATASET_VALID(rdataset));
676 	REQUIRE(!dns_rdataset_isassociated(rdataset));
677 	REQUIRE(covers == 0 || type == dns_rdatatype_rrsig);
678 	REQUIRE(type != dns_rdatatype_any);
679 	REQUIRE(sigrdataset == NULL ||
680 		(DNS_RDATASET_VALID(sigrdataset) &&
681 		 !dns_rdataset_isassociated(sigrdataset)));
682 
683 	return ((db->methods->findrdataset)(db, node, version, type, covers,
684 					    now, rdataset, sigrdataset));
685 }
686 
687 isc_result_t
dns_db_allrdatasets(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,unsigned int options,isc_stdtime_t now,dns_rdatasetiter_t ** iteratorp)688 dns_db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
689 		    unsigned int options, isc_stdtime_t now,
690 		    dns_rdatasetiter_t **iteratorp) {
691 	/*
692 	 * Make '*iteratorp' an rdataset iteratator for all rdatasets at
693 	 * 'node' in version 'version' of 'db'.
694 	 */
695 
696 	REQUIRE(DNS_DB_VALID(db));
697 	REQUIRE(iteratorp != NULL && *iteratorp == NULL);
698 
699 	return ((db->methods->allrdatasets)(db, node, version, options, now,
700 					    iteratorp));
701 }
702 
703 isc_result_t
dns_db_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)704 dns_db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
705 		   isc_stdtime_t now, dns_rdataset_t *rdataset,
706 		   unsigned int options, dns_rdataset_t *addedrdataset) {
707 	/*
708 	 * Add 'rdataset' to 'node' in version 'version' of 'db'.
709 	 */
710 
711 	REQUIRE(DNS_DB_VALID(db));
712 	REQUIRE(node != NULL);
713 	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
714 		((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL &&
715 		 (options & DNS_DBADD_MERGE) == 0));
716 	REQUIRE((options & DNS_DBADD_EXACT) == 0 ||
717 		(options & DNS_DBADD_MERGE) != 0);
718 	REQUIRE(DNS_RDATASET_VALID(rdataset));
719 	REQUIRE(dns_rdataset_isassociated(rdataset));
720 	REQUIRE(rdataset->rdclass == db->rdclass);
721 	REQUIRE(addedrdataset == NULL ||
722 		(DNS_RDATASET_VALID(addedrdataset) &&
723 		 !dns_rdataset_isassociated(addedrdataset)));
724 
725 	return ((db->methods->addrdataset)(db, node, version, now, rdataset,
726 					   options, addedrdataset));
727 }
728 
729 isc_result_t
dns_db_subtractrdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdataset_t * rdataset,unsigned int options,dns_rdataset_t * newrdataset)730 dns_db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
731 			dns_dbversion_t *version, dns_rdataset_t *rdataset,
732 			unsigned int options, dns_rdataset_t *newrdataset) {
733 	/*
734 	 * Remove any rdata in 'rdataset' from 'node' in version 'version' of
735 	 * 'db'.
736 	 */
737 
738 	REQUIRE(DNS_DB_VALID(db));
739 	REQUIRE(node != NULL);
740 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL);
741 	REQUIRE(DNS_RDATASET_VALID(rdataset));
742 	REQUIRE(dns_rdataset_isassociated(rdataset));
743 	REQUIRE(rdataset->rdclass == db->rdclass);
744 	REQUIRE(newrdataset == NULL ||
745 		(DNS_RDATASET_VALID(newrdataset) &&
746 		 !dns_rdataset_isassociated(newrdataset)));
747 
748 	return ((db->methods->subtractrdataset)(db, node, version, rdataset,
749 						options, newrdataset));
750 }
751 
752 isc_result_t
dns_db_deleterdataset(dns_db_t * db,dns_dbnode_t * node,dns_dbversion_t * version,dns_rdatatype_t type,dns_rdatatype_t covers)753 dns_db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
754 		      dns_dbversion_t *version, dns_rdatatype_t type,
755 		      dns_rdatatype_t covers) {
756 	/*
757 	 * Make it so that no rdataset of type 'type' exists at 'node' in
758 	 * version version 'version' of 'db'.
759 	 */
760 
761 	REQUIRE(DNS_DB_VALID(db));
762 	REQUIRE(node != NULL);
763 	REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
764 		((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL));
765 
766 	return ((db->methods->deleterdataset)(db, node, version, type, covers));
767 }
768 
769 void
dns_db_overmem(dns_db_t * db,bool overmem)770 dns_db_overmem(dns_db_t *db, bool overmem) {
771 	REQUIRE(DNS_DB_VALID(db));
772 
773 	(db->methods->overmem)(db, overmem);
774 }
775 
776 isc_result_t
dns_db_getsoaserial(dns_db_t * db,dns_dbversion_t * ver,uint32_t * serialp)777 dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, uint32_t *serialp) {
778 	isc_result_t result;
779 	dns_dbnode_t *node = NULL;
780 	dns_rdataset_t rdataset;
781 	dns_rdata_t rdata = DNS_RDATA_INIT;
782 	isc_buffer_t buffer;
783 
784 	REQUIRE(dns_db_iszone(db) || dns_db_isstub(db));
785 
786 	result = dns_db_findnode(db, dns_db_origin(db), false, &node);
787 	if (result != ISC_R_SUCCESS) {
788 		return (result);
789 	}
790 
791 	dns_rdataset_init(&rdataset);
792 	result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
793 				     (isc_stdtime_t)0, &rdataset, NULL);
794 	if (result != ISC_R_SUCCESS) {
795 		goto freenode;
796 	}
797 
798 	result = dns_rdataset_first(&rdataset);
799 	if (result != ISC_R_SUCCESS) {
800 		goto freerdataset;
801 	}
802 	dns_rdataset_current(&rdataset, &rdata);
803 	result = dns_rdataset_next(&rdataset);
804 	INSIST(result == ISC_R_NOMORE);
805 
806 	INSIST(rdata.length > 20);
807 	isc_buffer_init(&buffer, rdata.data, rdata.length);
808 	isc_buffer_add(&buffer, rdata.length);
809 	isc_buffer_forward(&buffer, rdata.length - 20);
810 	*serialp = isc_buffer_getuint32(&buffer);
811 
812 	result = ISC_R_SUCCESS;
813 
814 freerdataset:
815 	dns_rdataset_disassociate(&rdataset);
816 
817 freenode:
818 	dns_db_detachnode(db, &node);
819 	return (result);
820 }
821 
822 unsigned int
dns_db_nodecount(dns_db_t * db)823 dns_db_nodecount(dns_db_t *db) {
824 	REQUIRE(DNS_DB_VALID(db));
825 
826 	return ((db->methods->nodecount)(db));
827 }
828 
829 size_t
dns_db_hashsize(dns_db_t * db)830 dns_db_hashsize(dns_db_t *db) {
831 	REQUIRE(DNS_DB_VALID(db));
832 
833 	if (db->methods->hashsize == NULL) {
834 		return (0);
835 	}
836 
837 	return ((db->methods->hashsize)(db));
838 }
839 
840 isc_result_t
dns_db_adjusthashsize(dns_db_t * db,size_t size)841 dns_db_adjusthashsize(dns_db_t *db, size_t size) {
842 	REQUIRE(DNS_DB_VALID(db));
843 
844 	if (db->methods->adjusthashsize != NULL) {
845 		return ((db->methods->adjusthashsize)(db, size));
846 	}
847 
848 	return (ISC_R_NOTIMPLEMENTED);
849 }
850 
851 void
dns_db_settask(dns_db_t * db,isc_task_t * task)852 dns_db_settask(dns_db_t *db, isc_task_t *task) {
853 	REQUIRE(DNS_DB_VALID(db));
854 
855 	(db->methods->settask)(db, task);
856 }
857 
858 isc_result_t
dns_db_register(const char * name,dns_dbcreatefunc_t create,void * driverarg,isc_mem_t * mctx,dns_dbimplementation_t ** dbimp)859 dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
860 		isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
861 	dns_dbimplementation_t *imp;
862 
863 	REQUIRE(name != NULL);
864 	REQUIRE(dbimp != NULL && *dbimp == NULL);
865 
866 	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
867 
868 	RWLOCK(&implock, isc_rwlocktype_write);
869 	imp = impfind(name);
870 	if (imp != NULL) {
871 		RWUNLOCK(&implock, isc_rwlocktype_write);
872 		return (ISC_R_EXISTS);
873 	}
874 
875 	imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t));
876 	imp->name = name;
877 	imp->create = create;
878 	imp->mctx = NULL;
879 	imp->driverarg = driverarg;
880 	isc_mem_attach(mctx, &imp->mctx);
881 	ISC_LINK_INIT(imp, link);
882 	ISC_LIST_APPEND(implementations, imp, link);
883 	RWUNLOCK(&implock, isc_rwlocktype_write);
884 
885 	*dbimp = imp;
886 
887 	return (ISC_R_SUCCESS);
888 }
889 
890 void
dns_db_unregister(dns_dbimplementation_t ** dbimp)891 dns_db_unregister(dns_dbimplementation_t **dbimp) {
892 	dns_dbimplementation_t *imp;
893 
894 	REQUIRE(dbimp != NULL && *dbimp != NULL);
895 
896 	RUNTIME_CHECK(isc_once_do(&once, initialize) == ISC_R_SUCCESS);
897 
898 	imp = *dbimp;
899 	*dbimp = NULL;
900 	RWLOCK(&implock, isc_rwlocktype_write);
901 	ISC_LIST_UNLINK(implementations, imp, link);
902 	isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_dbimplementation_t));
903 	RWUNLOCK(&implock, isc_rwlocktype_write);
904 	ENSURE(*dbimp == NULL);
905 }
906 
907 isc_result_t
dns_db_getoriginnode(dns_db_t * db,dns_dbnode_t ** nodep)908 dns_db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep) {
909 	REQUIRE(DNS_DB_VALID(db));
910 	REQUIRE(dns_db_iszone(db));
911 	REQUIRE(nodep != NULL && *nodep == NULL);
912 
913 	if (db->methods->getoriginnode != NULL) {
914 		return ((db->methods->getoriginnode)(db, nodep));
915 	}
916 
917 	return (ISC_R_NOTFOUND);
918 }
919 
920 dns_stats_t *
dns_db_getrrsetstats(dns_db_t * db)921 dns_db_getrrsetstats(dns_db_t *db) {
922 	REQUIRE(DNS_DB_VALID(db));
923 
924 	if (db->methods->getrrsetstats != NULL) {
925 		return ((db->methods->getrrsetstats)(db));
926 	}
927 
928 	return (NULL);
929 }
930 
931 isc_result_t
dns_db_setcachestats(dns_db_t * db,isc_stats_t * stats)932 dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) {
933 	REQUIRE(DNS_DB_VALID(db));
934 
935 	if (db->methods->setcachestats != NULL) {
936 		return ((db->methods->setcachestats)(db, stats));
937 	}
938 
939 	return (ISC_R_NOTIMPLEMENTED);
940 }
941 
942 isc_result_t
dns_db_getnsec3parameters(dns_db_t * db,dns_dbversion_t * version,dns_hash_t * hash,uint8_t * flags,uint16_t * iterations,unsigned char * salt,size_t * salt_length)943 dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
944 			  dns_hash_t *hash, uint8_t *flags,
945 			  uint16_t *iterations, unsigned char *salt,
946 			  size_t *salt_length) {
947 	REQUIRE(DNS_DB_VALID(db));
948 	REQUIRE(dns_db_iszone(db));
949 
950 	if (db->methods->getnsec3parameters != NULL) {
951 		return ((db->methods->getnsec3parameters)(db, version, hash,
952 							  flags, iterations,
953 							  salt, salt_length));
954 	}
955 
956 	return (ISC_R_NOTFOUND);
957 }
958 
959 isc_result_t
dns_db_getsize(dns_db_t * db,dns_dbversion_t * version,uint64_t * records,uint64_t * bytes)960 dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
961 	       uint64_t *bytes) {
962 	REQUIRE(DNS_DB_VALID(db));
963 	REQUIRE(dns_db_iszone(db));
964 
965 	if (db->methods->getsize != NULL) {
966 		return ((db->methods->getsize)(db, version, records, bytes));
967 	}
968 
969 	return (ISC_R_NOTFOUND);
970 }
971 
972 isc_result_t
dns_db_setsigningtime(dns_db_t * db,dns_rdataset_t * rdataset,isc_stdtime_t resign)973 dns_db_setsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
974 		      isc_stdtime_t resign) {
975 	if (db->methods->setsigningtime != NULL) {
976 		return ((db->methods->setsigningtime)(db, rdataset, resign));
977 	}
978 	return (ISC_R_NOTIMPLEMENTED);
979 }
980 
981 isc_result_t
dns_db_getsigningtime(dns_db_t * db,dns_rdataset_t * rdataset,dns_name_t * name)982 dns_db_getsigningtime(dns_db_t *db, dns_rdataset_t *rdataset,
983 		      dns_name_t *name) {
984 	if (db->methods->getsigningtime != NULL) {
985 		return ((db->methods->getsigningtime)(db, rdataset, name));
986 	}
987 	return (ISC_R_NOTFOUND);
988 }
989 
990 void
dns_db_resigned(dns_db_t * db,dns_rdataset_t * rdataset,dns_dbversion_t * version)991 dns_db_resigned(dns_db_t *db, dns_rdataset_t *rdataset,
992 		dns_dbversion_t *version) {
993 	if (db->methods->resigned != NULL) {
994 		(db->methods->resigned)(db, rdataset, version);
995 	}
996 }
997 
998 /*
999  * Attach a database to policy zone databases.
1000  * This should only happen when the caller has already ensured that
1001  * it is dealing with a database that understands response policy zones.
1002  */
1003 void
dns_db_rpz_attach(dns_db_t * db,void * rpzs,uint8_t rpz_num)1004 dns_db_rpz_attach(dns_db_t *db, void *rpzs, uint8_t rpz_num) {
1005 	REQUIRE(db->methods->rpz_attach != NULL);
1006 	(db->methods->rpz_attach)(db, rpzs, rpz_num);
1007 }
1008 
1009 /*
1010  * Finish loading a response policy zone.
1011  */
1012 isc_result_t
dns_db_rpz_ready(dns_db_t * db)1013 dns_db_rpz_ready(dns_db_t *db) {
1014 	if (db->methods->rpz_ready == NULL) {
1015 		return (ISC_R_SUCCESS);
1016 	}
1017 	return ((db->methods->rpz_ready)(db));
1018 }
1019 
1020 /*
1021  * Attach a notify-on-update function the database
1022  */
1023 isc_result_t
dns_db_updatenotify_register(dns_db_t * db,dns_dbupdate_callback_t fn,void * fn_arg)1024 dns_db_updatenotify_register(dns_db_t *db, dns_dbupdate_callback_t fn,
1025 			     void *fn_arg) {
1026 	dns_dbonupdatelistener_t *listener;
1027 
1028 	REQUIRE(db != NULL);
1029 	REQUIRE(fn != NULL);
1030 
1031 	for (listener = ISC_LIST_HEAD(db->update_listeners); listener != NULL;
1032 	     listener = ISC_LIST_NEXT(listener, link))
1033 	{
1034 		if ((listener->onupdate == fn) &&
1035 		    (listener->onupdate_arg == fn_arg))
1036 		{
1037 			return (ISC_R_SUCCESS);
1038 		}
1039 	}
1040 
1041 	listener = isc_mem_get(db->mctx, sizeof(dns_dbonupdatelistener_t));
1042 
1043 	listener->onupdate = fn;
1044 	listener->onupdate_arg = fn_arg;
1045 
1046 	ISC_LINK_INIT(listener, link);
1047 	ISC_LIST_APPEND(db->update_listeners, listener, link);
1048 
1049 	return (ISC_R_SUCCESS);
1050 }
1051 
1052 isc_result_t
dns_db_updatenotify_unregister(dns_db_t * db,dns_dbupdate_callback_t fn,void * fn_arg)1053 dns_db_updatenotify_unregister(dns_db_t *db, dns_dbupdate_callback_t fn,
1054 			       void *fn_arg) {
1055 	dns_dbonupdatelistener_t *listener;
1056 
1057 	REQUIRE(db != NULL);
1058 
1059 	for (listener = ISC_LIST_HEAD(db->update_listeners); listener != NULL;
1060 	     listener = ISC_LIST_NEXT(listener, link))
1061 	{
1062 		if ((listener->onupdate == fn) &&
1063 		    (listener->onupdate_arg == fn_arg))
1064 		{
1065 			ISC_LIST_UNLINK(db->update_listeners, listener, link);
1066 			isc_mem_put(db->mctx, listener,
1067 				    sizeof(dns_dbonupdatelistener_t));
1068 			return (ISC_R_SUCCESS);
1069 		}
1070 	}
1071 
1072 	return (ISC_R_NOTFOUND);
1073 }
1074 
1075 isc_result_t
dns_db_nodefullname(dns_db_t * db,dns_dbnode_t * node,dns_name_t * name)1076 dns_db_nodefullname(dns_db_t *db, dns_dbnode_t *node, dns_name_t *name) {
1077 	REQUIRE(db != NULL);
1078 	REQUIRE(node != NULL);
1079 	REQUIRE(name != NULL);
1080 
1081 	if (db->methods->nodefullname == NULL) {
1082 		return (ISC_R_NOTIMPLEMENTED);
1083 	}
1084 	return ((db->methods->nodefullname)(db, node, name));
1085 }
1086 
1087 isc_result_t
dns_db_setservestalettl(dns_db_t * db,dns_ttl_t ttl)1088 dns_db_setservestalettl(dns_db_t *db, dns_ttl_t ttl) {
1089 	REQUIRE(DNS_DB_VALID(db));
1090 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1091 
1092 	if (db->methods->setservestalettl != NULL) {
1093 		return ((db->methods->setservestalettl)(db, ttl));
1094 	}
1095 	return (ISC_R_NOTIMPLEMENTED);
1096 }
1097 
1098 isc_result_t
dns_db_getservestalettl(dns_db_t * db,dns_ttl_t * ttl)1099 dns_db_getservestalettl(dns_db_t *db, dns_ttl_t *ttl) {
1100 	REQUIRE(DNS_DB_VALID(db));
1101 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1102 
1103 	if (db->methods->getservestalettl != NULL) {
1104 		return ((db->methods->getservestalettl)(db, ttl));
1105 	}
1106 	return (ISC_R_NOTIMPLEMENTED);
1107 }
1108 
1109 isc_result_t
dns_db_setservestalerefresh(dns_db_t * db,uint32_t interval)1110 dns_db_setservestalerefresh(dns_db_t *db, uint32_t interval) {
1111 	REQUIRE(DNS_DB_VALID(db));
1112 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1113 
1114 	if (db->methods->setservestalerefresh != NULL) {
1115 		return ((db->methods->setservestalerefresh)(db, interval));
1116 	}
1117 	return (ISC_R_NOTIMPLEMENTED);
1118 }
1119 
1120 isc_result_t
dns_db_getservestalerefresh(dns_db_t * db,uint32_t * interval)1121 dns_db_getservestalerefresh(dns_db_t *db, uint32_t *interval) {
1122 	REQUIRE(DNS_DB_VALID(db));
1123 	REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1124 
1125 	if (db->methods->getservestalerefresh != NULL) {
1126 		return ((db->methods->getservestalerefresh)(db, interval));
1127 	}
1128 	return (ISC_R_NOTIMPLEMENTED);
1129 }
1130 
1131 isc_result_t
dns_db_setgluecachestats(dns_db_t * db,isc_stats_t * stats)1132 dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
1133 	REQUIRE(dns_db_iszone(db));
1134 	REQUIRE(stats != NULL);
1135 
1136 	if (db->methods->setgluecachestats != NULL) {
1137 		return ((db->methods->setgluecachestats)(db, stats));
1138 	}
1139 
1140 	return (ISC_R_NOTIMPLEMENTED);
1141 }
1142