Coverage Report

Created: 2026-06-15 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/dns/db.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
/*! \file */
15
16
/***
17
 *** Imports
18
 ***/
19
20
#include <inttypes.h>
21
#include <stdbool.h>
22
23
#include <isc/buffer.h>
24
#include <isc/hash.h>
25
#include <isc/log.h>
26
#include <isc/mem.h>
27
#include <isc/result.h>
28
#include <isc/rwlock.h>
29
#include <isc/string.h>
30
#include <isc/tid.h>
31
#include <isc/urcu.h>
32
#include <isc/util.h>
33
34
#include <dns/callbacks.h>
35
#include <dns/clientinfo.h>
36
#include <dns/db.h>
37
#include <dns/master.h>
38
#include <dns/rdata.h>
39
#include <dns/rdataclass.h>
40
#include <dns/rdataset.h>
41
#include <dns/rdatasetiter.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 "db_p.h"
64
#include "qpcache_p.h"
65
#include "qpzone_p.h"
66
67
unsigned int dns_pps = 0U;
68
69
static ISC_LIST(dns_dbimplementation_t) implementations;
70
static isc_rwlock_t implock;
71
72
static dns_dbimplementation_t qpimp;
73
static dns_dbimplementation_t qpzoneimp;
74
75
void
76
22
dns__db_initialize(void) {
77
22
  isc_rwlock_init(&implock);
78
79
22
  ISC_LIST_INIT(implementations);
80
81
22
  qpimp = (dns_dbimplementation_t){
82
22
    .name = "qpcache",
83
22
    .create = dns__qpcache_create,
84
22
    .link = ISC_LINK_INITIALIZER,
85
22
  };
86
87
22
  qpzoneimp = (dns_dbimplementation_t){
88
22
    .name = "qpzone",
89
22
    .create = dns__qpzone_create,
90
22
    .link = ISC_LINK_INITIALIZER,
91
22
  };
92
93
22
  ISC_LIST_APPEND(implementations, &qpimp, link);
94
22
  ISC_LIST_APPEND(implementations, &qpzoneimp, link);
95
22
}
96
97
void
98
0
dns__db_shutdown(void) {
99
0
  isc_rwlock_destroy(&implock);
100
0
}
101
102
static dns_dbimplementation_t *
103
17.6k
impfind(const char *name) {
104
35.2k
  ISC_LIST_FOREACH(implementations, imp, link) {
105
35.2k
    if (strcasecmp(name, imp->name) == 0) {
106
17.6k
      return imp;
107
17.6k
    }
108
35.2k
  }
109
0
  return NULL;
110
17.6k
}
111
112
static void
113
call_updatenotify(dns_db_t *db);
114
115
/***
116
 *** Basic DB Methods
117
 ***/
118
119
isc_result_t
120
dns_db_create(isc_mem_t *mctx, const char *db_type, const dns_name_t *origin,
121
        dns_dbtype_t type, dns_rdataclass_t rdclass, unsigned int argc,
122
17.6k
        char *argv[], dns_db_t **dbp) {
123
17.6k
  dns_dbimplementation_t *impinfo = NULL;
124
125
  /*
126
   * Create a new database using implementation 'db_type'.
127
   */
128
129
17.6k
  REQUIRE(dbp != NULL && *dbp == NULL);
130
17.6k
  REQUIRE(dns_name_isabsolute(origin));
131
132
17.6k
  RWLOCK(&implock, isc_rwlocktype_read);
133
17.6k
  impinfo = impfind(db_type);
134
17.6k
  if (impinfo != NULL) {
135
17.6k
    isc_result_t result;
136
17.6k
    result = ((impinfo->create)(mctx, origin, type, rdclass, argc,
137
17.6k
              argv, impinfo->driverarg, dbp));
138
17.6k
    RWUNLOCK(&implock, isc_rwlocktype_read);
139
140
#if DNS_DB_TRACE
141
    fprintf(stderr, "dns_db_create:%s:%s:%d:%p->references = 1\n",
142
      __func__, __FILE__, __LINE__ + 1, *dbp);
143
#endif
144
17.6k
    return result;
145
17.6k
  }
146
147
0
  RWUNLOCK(&implock, isc_rwlocktype_read);
148
149
0
  isc_log_write(DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB, ISC_LOG_ERROR,
150
0
          "unsupported database type '%s'", db_type);
151
152
0
  return ISC_R_NOTFOUND;
153
0
}
154
155
static void
156
17.6k
dns__db_destroy(dns_db_t *db) {
157
17.6k
  (db->methods->destroy)(db);
158
17.6k
}
159
160
#if DNS_DB_TRACE
161
ISC_REFCOUNT_TRACE_IMPL(dns_db, dns__db_destroy);
162
#else
163
35.8k
ISC_REFCOUNT_IMPL(dns_db, dns__db_destroy);
dns_db_ref
Line
Count
Source
163
ISC_REFCOUNT_IMPL(dns_db, dns__db_destroy);
dns_db_unref
Line
Count
Source
163
ISC_REFCOUNT_IMPL(dns_db, dns__db_destroy);
dns_db_detach
Line
Count
Source
163
ISC_REFCOUNT_IMPL(dns_db, dns__db_destroy);
164
35.8k
#endif
165
35.8k
166
35.8k
bool
167
35.8k
dns_db_iscache(dns_db_t *db) {
168
  /*
169
   * Does 'db' have cache semantics?
170
   */
171
172
209
  REQUIRE(DNS_DB_VALID(db));
173
174
209
  if ((db->attributes & DNS_DBATTR_CACHE) != 0) {
175
0
    return true;
176
0
  }
177
178
209
  return false;
179
209
}
180
181
bool
182
4
dns_db_iszone(dns_db_t *db) {
183
  /*
184
   * Does 'db' have zone semantics?
185
   */
186
187
4
  REQUIRE(DNS_DB_VALID(db));
188
189
4
  if ((db->attributes & (DNS_DBATTR_CACHE | DNS_DBATTR_STUB)) == 0) {
190
4
    return true;
191
4
  }
192
193
0
  return false;
194
4
}
195
196
bool
197
0
dns_db_isstub(dns_db_t *db) {
198
  /*
199
   * Does 'db' have stub semantics?
200
   */
201
202
0
  REQUIRE(DNS_DB_VALID(db));
203
204
0
  if ((db->attributes & DNS_DBATTR_STUB) != 0) {
205
0
    return true;
206
0
  }
207
208
0
  return false;
209
0
}
210
211
bool
212
2
dns_db_issecure(dns_db_t *db) {
213
  /*
214
   * Is 'db' secure?
215
   */
216
217
2
  REQUIRE(DNS_DB_VALID(db));
218
2
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
219
220
2
  if (db->methods->issecure != NULL) {
221
2
    return (db->methods->issecure)(db);
222
2
  }
223
0
  return false;
224
2
}
225
226
bool
227
4
dns_db_ispersistent(dns_db_t *db) {
228
  /*
229
   * Is 'db' persistent?
230
   */
231
232
4
  REQUIRE(DNS_DB_VALID(db));
233
234
4
  if (db->methods->beginload == NULL) {
235
    /* If the database can't be loaded, assume it's persistent */
236
0
    return true;
237
0
  }
238
239
4
  return false;
240
4
}
241
242
dns_name_t *
243
0
dns_db_origin(dns_db_t *db) {
244
  /*
245
   * The origin of the database.
246
   */
247
248
0
  REQUIRE(DNS_DB_VALID(db));
249
250
0
  return &db->origin;
251
0
}
252
253
dns_rdataclass_t
254
0
dns_db_class(dns_db_t *db) {
255
  /*
256
   * The class of the database.
257
   */
258
259
0
  REQUIRE(DNS_DB_VALID(db));
260
261
0
  return db->rdclass;
262
0
}
263
264
isc_result_t
265
17.6k
dns_db_beginload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
266
  /*
267
   * Begin loading 'db'.
268
   */
269
270
17.6k
  REQUIRE(DNS_DB_VALID(db));
271
17.6k
  REQUIRE(DNS_CALLBACK_VALID(callbacks));
272
273
17.6k
  if (db->methods->beginload != NULL) {
274
17.6k
    return (db->methods->beginload)(db, callbacks);
275
17.6k
  }
276
0
  return ISC_R_NOTIMPLEMENTED;
277
17.6k
}
278
279
isc_result_t
280
17.6k
dns_db_endload(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
281
  /*
282
   * Finish loading 'db'.
283
   */
284
285
17.6k
  REQUIRE(DNS_DB_VALID(db));
286
17.6k
  REQUIRE(DNS_CALLBACK_VALID(callbacks));
287
17.6k
  REQUIRE(callbacks->add_private != NULL);
288
289
  /*
290
   * When dns_db_endload() is called, we call the onupdate function
291
   * for all registered listeners, regardless of whether the underlying
292
   * database has an 'endload' implementation.
293
   */
294
17.6k
  call_updatenotify(db);
295
296
17.6k
  if (db->methods->endload != NULL) {
297
17.6k
    return (db->methods->endload)(db, callbacks);
298
17.6k
  }
299
300
0
  return ISC_R_NOTIMPLEMENTED;
301
17.6k
}
302
303
isc_result_t
304
dns_db_beginupdate(dns_db_t *db, dns_dbversion_t *ver,
305
0
       dns_rdatacallbacks_t *callbacks) {
306
  /*
307
   * Begin updating 'db'.
308
   */
309
310
0
  REQUIRE(DNS_DB_VALID(db));
311
0
  REQUIRE(dns_db_iszone(db));
312
0
  REQUIRE(DNS_CALLBACK_VALID(callbacks));
313
314
0
  if (db->methods->beginupdate != NULL) {
315
0
    return (db->methods->beginupdate)(db, ver, callbacks);
316
0
  }
317
0
  return ISC_R_NOTIMPLEMENTED;
318
0
}
319
320
isc_result_t
321
0
dns_db_commitupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
322
  /*
323
   * Commit the update to 'db'.
324
   */
325
326
0
  REQUIRE(DNS_DB_VALID(db));
327
0
  REQUIRE(dns_db_iszone(db));
328
0
  REQUIRE(DNS_CALLBACK_VALID(callbacks));
329
330
0
  if (db->methods->commitupdate != NULL) {
331
0
    return (db->methods->commitupdate)(db, callbacks);
332
0
  }
333
334
0
  return ISC_R_NOTIMPLEMENTED;
335
0
}
336
337
isc_result_t
338
0
dns_db_abortupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks) {
339
  /*
340
   * Abort the update to 'db'.
341
   */
342
343
0
  REQUIRE(DNS_DB_VALID(db));
344
0
  REQUIRE(dns_db_iszone(db));
345
0
  REQUIRE(DNS_CALLBACK_VALID(callbacks));
346
347
0
  if (db->methods->abortupdate != NULL) {
348
0
    return (db->methods->abortupdate)(db, callbacks);
349
0
  }
350
351
0
  return ISC_R_NOTIMPLEMENTED;
352
0
}
353
354
isc_result_t
355
dns_db_load(dns_db_t *db, const char *filename, dns_masterformat_t format,
356
0
      unsigned int options) {
357
0
  isc_result_t result, eresult;
358
0
  dns_rdatacallbacks_t callbacks;
359
360
  /*
361
   * Load master file 'filename' into 'db'.
362
   */
363
364
0
  REQUIRE(DNS_DB_VALID(db));
365
366
0
  if ((db->attributes & DNS_DBATTR_CACHE) != 0) {
367
0
    options |= DNS_MASTER_AGETTL;
368
0
  }
369
370
0
  dns_rdatacallbacks_init(&callbacks);
371
0
  RETERR(dns_db_beginload(db, &callbacks));
372
0
  result = dns_master_loadfile(filename, &db->origin, &db->origin,
373
0
             db->rdclass, options, 0, &callbacks, NULL,
374
0
             NULL, db->mctx, format, 0);
375
0
  eresult = dns_db_endload(db, &callbacks);
376
  /*
377
   * We always call dns_db_endload(), but we only want to return its
378
   * result if dns_master_loadfile() succeeded.  If dns_master_loadfile()
379
   * failed, we want to return the result code it gave us.
380
   */
381
0
  if (eresult != ISC_R_SUCCESS &&
382
0
      (result == ISC_R_SUCCESS || result == DNS_R_SEENINCLUDE))
383
0
  {
384
0
    result = eresult;
385
0
  }
386
387
0
  return result;
388
0
}
389
390
/***
391
 *** Version Methods
392
 ***/
393
394
void
395
6
dns_db_currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
396
  /*
397
   * Open the current version for reading.
398
   */
399
400
6
  REQUIRE(DNS_DB_VALID(db));
401
6
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
402
6
  REQUIRE(versionp != NULL && *versionp == NULL);
403
404
6
  (db->methods->currentversion)(db, versionp);
405
6
}
406
407
isc_result_t
408
0
dns_db_newversion(dns_db_t *db, dns_dbversion_t **versionp) {
409
  /*
410
   * Open a new version for reading and writing.
411
   */
412
413
0
  REQUIRE(DNS_DB_VALID(db));
414
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
415
0
  REQUIRE(versionp != NULL && *versionp == NULL);
416
417
0
  if (db->methods->newversion != NULL) {
418
0
    return (db->methods->newversion)(db, versionp);
419
0
  }
420
0
  return ISC_R_NOTIMPLEMENTED;
421
0
}
422
423
void
424
dns_db_attachversion(dns_db_t *db, dns_dbversion_t *source,
425
0
         dns_dbversion_t **targetp) {
426
  /*
427
   * Attach '*targetp' to 'source'.
428
   */
429
430
0
  REQUIRE(DNS_DB_VALID(db));
431
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
432
0
  REQUIRE(source != NULL);
433
0
  REQUIRE(targetp != NULL && *targetp == NULL);
434
435
0
  (db->methods->attachversion)(db, source, targetp);
436
437
0
  ENSURE(*targetp != NULL);
438
0
}
439
440
void
441
dns__db_closeversion(dns_db_t *db, dns_dbversion_t **versionp,
442
6
         bool commit DNS__DB_FLARG) {
443
  /*
444
   * Close version '*versionp'.
445
   */
446
447
6
  REQUIRE(DNS_DB_VALID(db));
448
6
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
449
6
  REQUIRE(versionp != NULL && *versionp != NULL);
450
451
6
  (db->methods->closeversion)(db, versionp, commit DNS__DB_FLARG_PASS);
452
453
6
  if (commit) {
454
0
    call_updatenotify(db);
455
0
  }
456
457
6
  ENSURE(*versionp == NULL);
458
6
}
459
460
/***
461
 *** Node Methods
462
 ***/
463
464
isc_result_t
465
dns__db_findnode(dns_db_t *db, const dns_name_t *name, bool create,
466
     dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
467
6
     dns_dbnode_t **nodep DNS__DB_FLARG) {
468
  /*
469
   * Find the node with name 'name', passing 'arg' to the database
470
   * implementation.
471
   */
472
473
6
  REQUIRE(DNS_DB_VALID(db));
474
6
  REQUIRE(nodep != NULL && *nodep == NULL);
475
476
6
  if (db->methods->findnode != NULL) {
477
6
    return (db->methods->findnode)(db, name, create, methods,
478
6
                 clientinfo,
479
6
                 nodep DNS__DB_FLARG_PASS);
480
6
  }
481
0
  return ISC_R_NOTIMPLEMENTED;
482
6
}
483
484
isc_result_t
485
dns__db_findnsec3node(dns_db_t *db, const dns_name_t *name, bool create,
486
0
          dns_dbnode_t **nodep DNS__DB_FLARG) {
487
  /*
488
   * Find the node with name 'name'.
489
   */
490
491
0
  REQUIRE(DNS_DB_VALID(db));
492
0
  REQUIRE(nodep != NULL && *nodep == NULL);
493
494
0
  return (db->methods->findnsec3node)(db, name, create,
495
0
              nodep DNS__DB_FLARG_PASS);
496
0
}
497
498
isc_result_t
499
dns__db_find(dns_db_t *db, const dns_name_t *name, dns_dbversion_t *version,
500
       dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
501
       dns_dbnode_t **nodep, dns_name_t *foundname,
502
       dns_clientinfomethods_t *methods, dns_clientinfo_t *clientinfo,
503
       dns_rdataset_t *rdataset,
504
209
       dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
505
  /*
506
   * Find the best match for 'name' and 'type' in version 'version'
507
   * of 'db', passing in 'arg'.
508
   */
509
510
209
  REQUIRE(DNS_DB_VALID(db));
511
209
  REQUIRE(type != dns_rdatatype_rrsig);
512
209
  REQUIRE(nodep == NULL || *nodep == NULL);
513
209
  REQUIRE(dns_name_hasbuffer(foundname));
514
209
  REQUIRE(rdataset == NULL || (DNS_RDATASET_VALID(rdataset) &&
515
209
             !dns_rdataset_isassociated(rdataset)));
516
209
  REQUIRE(sigrdataset == NULL ||
517
209
    (DNS_RDATASET_VALID(sigrdataset) &&
518
209
     !dns_rdataset_isassociated(sigrdataset)));
519
520
209
  if (db->methods->find != NULL) {
521
209
    return (db->methods->find)(db, name, version, type, options,
522
209
             now, nodep, foundname, methods,
523
209
             clientinfo, rdataset,
524
209
             sigrdataset DNS__DB_FLARG_PASS);
525
209
  }
526
0
  return ISC_R_NOTIMPLEMENTED;
527
209
}
528
529
void
530
0
dns__db_attachnode(dns_dbnode_t *source, dns_dbnode_t **targetp DNS__DB_FLARG) {
531
  /*
532
   * Attach *targetp to source.
533
   */
534
535
0
  REQUIRE(source != NULL);
536
0
  REQUIRE(targetp != NULL && *targetp == NULL);
537
0
  REQUIRE(source->methods != NULL && source->methods->attachnode != NULL);
538
539
0
  (source->methods->attachnode)(source, targetp DNS__DB_FLARG_PASS);
540
0
}
541
542
void
543
140
dns__db_detachnode(dns_dbnode_t **nodep DNS__DB_FLARG) {
544
  /*
545
   * Detach *nodep from its node.
546
   */
547
548
140
  REQUIRE(nodep != NULL && *nodep != NULL);
549
140
  dns_dbnode_t *node = *nodep;
550
140
  REQUIRE(node->methods != NULL && node->methods->detachnode != NULL);
551
552
140
  (node->methods->detachnode)(nodep DNS__DB_FLARG_PASS);
553
554
140
  ENSURE(*nodep == NULL);
555
140
}
556
557
void
558
dns_db_transfernode(dns_db_t *db, dns_dbnode_t **sourcep,
559
0
        dns_dbnode_t **targetp) {
560
0
  REQUIRE(DNS_DB_VALID(db));
561
0
  REQUIRE(targetp != NULL && *targetp == NULL);
562
0
  REQUIRE(sourcep != NULL && *sourcep != NULL);
563
564
0
  *targetp = *sourcep;
565
0
  *sourcep = NULL;
566
0
}
567
568
/***
569
 *** DB Iterator Creation
570
 ***/
571
572
isc_result_t
573
dns_db_createiterator(dns_db_t *db, unsigned int flags,
574
0
          dns_dbiterator_t **iteratorp) {
575
  /*
576
   * Create an iterator for version 'version' of 'db'.
577
   */
578
579
0
  REQUIRE(DNS_DB_VALID(db));
580
0
  REQUIRE(iteratorp != NULL && *iteratorp == NULL);
581
0
  REQUIRE((flags & (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3)) !=
582
0
    (DNS_DB_NSEC3ONLY | DNS_DB_NONSEC3));
583
584
0
  if (db->methods->createiterator != NULL) {
585
0
    return db->methods->createiterator(db, flags, iteratorp);
586
0
  }
587
0
  return ISC_R_NOTIMPLEMENTED;
588
0
}
589
590
/***
591
 *** Rdataset Methods
592
 ***/
593
594
isc_result_t
595
dns__db_findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
596
         dns_rdatatype_t type, dns_rdatatype_t covers,
597
         isc_stdtime_t now, dns_rdataset_t *rdataset,
598
17.6k
         dns_rdataset_t *sigrdataset DNS__DB_FLARG) {
599
17.6k
  REQUIRE(DNS_DB_VALID(db));
600
17.6k
  REQUIRE(node != NULL);
601
17.6k
  REQUIRE(DNS_RDATASET_VALID(rdataset));
602
17.6k
  REQUIRE(!dns_rdataset_isassociated(rdataset));
603
17.6k
  REQUIRE(covers == dns_rdatatype_none || dns_rdatatype_issig(type));
604
17.6k
  REQUIRE(type != dns_rdatatype_any);
605
17.6k
  REQUIRE(sigrdataset == NULL ||
606
17.6k
    (DNS_RDATASET_VALID(sigrdataset) &&
607
17.6k
     !dns_rdataset_isassociated(sigrdataset)));
608
609
17.6k
  return (db->methods->findrdataset)(db, node, version, type, covers, now,
610
17.6k
             rdataset,
611
17.6k
             sigrdataset DNS__DB_FLARG_PASS);
612
17.6k
}
613
614
isc_result_t
615
dns__db_allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
616
         unsigned int options, isc_stdtime_t now,
617
0
         dns_rdatasetiter_t **iteratorp DNS__DB_FLARG) {
618
  /*
619
   * Make '*iteratorp' an rdataset iteratator for all rdatasets at
620
   * 'node' in version 'version' of 'db'.
621
   */
622
623
0
  REQUIRE(DNS_DB_VALID(db));
624
0
  REQUIRE(iteratorp != NULL && *iteratorp == NULL);
625
626
0
  return (db->methods->allrdatasets)(db, node, version, options, now,
627
0
             iteratorp DNS__DB_FLARG_PASS);
628
0
}
629
630
isc_result_t
631
dns__db_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
632
        isc_stdtime_t now, dns_rdataset_t *rdataset,
633
        unsigned int options,
634
0
        dns_rdataset_t *addedrdataset DNS__DB_FLARG) {
635
  /*
636
   * Add 'rdataset' to 'node' in version 'version' of 'db'.
637
   */
638
639
0
  REQUIRE(DNS_DB_VALID(db));
640
0
  REQUIRE(node != NULL);
641
0
  REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
642
0
    ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL &&
643
0
     (options & DNS_DBADD_MERGE) == 0));
644
0
  REQUIRE((options & DNS_DBADD_EXACT) == 0 ||
645
0
    (options & DNS_DBADD_MERGE) != 0);
646
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
647
0
  REQUIRE(dns_rdataset_isassociated(rdataset));
648
0
  REQUIRE(rdataset->rdclass == db->rdclass);
649
0
  REQUIRE(addedrdataset == NULL ||
650
0
    (DNS_RDATASET_VALID(addedrdataset) &&
651
0
     !dns_rdataset_isassociated(addedrdataset)));
652
653
0
  if (db->methods->addrdataset != NULL) {
654
0
    return (db->methods->addrdataset)(
655
0
      db, node, version, now, rdataset, options,
656
0
      addedrdataset DNS__DB_FLARG_PASS);
657
0
  }
658
0
  return ISC_R_NOTIMPLEMENTED;
659
0
}
660
661
isc_result_t
662
dns__db_subtractrdataset(dns_db_t *db, dns_dbnode_t *node,
663
       dns_dbversion_t *version, dns_rdataset_t *rdataset,
664
       unsigned int options,
665
0
       dns_rdataset_t *newrdataset DNS__DB_FLARG) {
666
  /*
667
   * Remove any rdata in 'rdataset' from 'node' in version 'version' of
668
   * 'db'.
669
   */
670
671
0
  REQUIRE(DNS_DB_VALID(db));
672
0
  REQUIRE(node != NULL);
673
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL);
674
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
675
0
  REQUIRE(dns_rdataset_isassociated(rdataset));
676
0
  REQUIRE(rdataset->rdclass == db->rdclass);
677
0
  REQUIRE(newrdataset == NULL ||
678
0
    (DNS_RDATASET_VALID(newrdataset) &&
679
0
     !dns_rdataset_isassociated(newrdataset)));
680
681
0
  if (db->methods->subtractrdataset != NULL) {
682
0
    return (db->methods->subtractrdataset)(
683
0
      db, node, version, rdataset, options,
684
0
      newrdataset DNS__DB_FLARG_PASS);
685
0
  }
686
0
  return ISC_R_NOTIMPLEMENTED;
687
0
}
688
689
isc_result_t
690
dns__db_deleterdataset(dns_db_t *db, dns_dbnode_t *node,
691
           dns_dbversion_t *version, dns_rdatatype_t type,
692
0
           dns_rdatatype_t covers DNS__DB_FLARG) {
693
  /*
694
   * Make it so that no rdataset of type 'type' exists at 'node' in
695
   * version version 'version' of 'db'.
696
   */
697
698
0
  REQUIRE(DNS_DB_VALID(db));
699
0
  REQUIRE(node != NULL);
700
0
  REQUIRE(((db->attributes & DNS_DBATTR_CACHE) == 0 && version != NULL) ||
701
0
    ((db->attributes & DNS_DBATTR_CACHE) != 0 && version == NULL));
702
703
0
  if (db->methods->deleterdataset != NULL) {
704
0
    return (db->methods->deleterdataset)(db, node, version, type,
705
0
                 covers DNS__DB_FLARG_PASS);
706
0
  }
707
0
  return ISC_R_NOTIMPLEMENTED;
708
0
}
709
710
isc_result_t
711
0
dns_db_getsoaserial(dns_db_t *db, dns_dbversion_t *ver, uint32_t *serialp) {
712
0
  isc_result_t result;
713
0
  dns_dbnode_t *node = NULL;
714
0
  dns_rdataset_t rdataset;
715
0
  dns_rdata_t rdata = DNS_RDATA_INIT;
716
0
  isc_buffer_t buffer;
717
718
0
  REQUIRE(dns_db_iszone(db) || dns_db_isstub(db));
719
720
0
  RETERR(dns_db_findnode(db, dns_db_origin(db), false, &node));
721
722
0
  dns_rdataset_init(&rdataset);
723
0
  result = dns_db_findrdataset(db, node, ver, dns_rdatatype_soa, 0,
724
0
             (isc_stdtime_t)0, &rdataset, NULL);
725
0
  if (result != ISC_R_SUCCESS) {
726
0
    goto freenode;
727
0
  }
728
729
0
  result = dns_rdataset_first(&rdataset);
730
0
  if (result != ISC_R_SUCCESS) {
731
0
    goto freerdataset;
732
0
  }
733
0
  dns_rdataset_current(&rdataset, &rdata);
734
0
  result = dns_rdataset_next(&rdataset);
735
0
  INSIST(result == ISC_R_NOMORE);
736
737
0
  INSIST(rdata.length > 20);
738
0
  isc_buffer_init(&buffer, rdata.data, rdata.length);
739
0
  isc_buffer_add(&buffer, rdata.length);
740
0
  isc_buffer_forward(&buffer, rdata.length - 20);
741
0
  *serialp = isc_buffer_getuint32(&buffer);
742
743
0
  result = ISC_R_SUCCESS;
744
745
0
freerdataset:
746
0
  dns_rdataset_disassociate(&rdataset);
747
748
0
freenode:
749
0
  dns_db_detachnode(&node);
750
0
  return result;
751
0
}
752
753
unsigned int
754
2
dns_db_nodecount(dns_db_t *db) {
755
2
  REQUIRE(DNS_DB_VALID(db));
756
757
2
  if (db->methods->nodecount != NULL) {
758
2
    return (db->methods->nodecount)(db);
759
2
  }
760
0
  return 0;
761
2
}
762
763
isc_result_t
764
dns_db_register(const char *name, dns_dbcreatefunc_t create, void *driverarg,
765
0
    isc_mem_t *mctx, dns_dbimplementation_t **dbimp) {
766
0
  dns_dbimplementation_t *imp;
767
768
0
  REQUIRE(name != NULL);
769
0
  REQUIRE(dbimp != NULL && *dbimp == NULL);
770
771
0
  RWLOCK(&implock, isc_rwlocktype_write);
772
0
  imp = impfind(name);
773
0
  if (imp != NULL) {
774
0
    RWUNLOCK(&implock, isc_rwlocktype_write);
775
0
    return ISC_R_EXISTS;
776
0
  }
777
778
0
  imp = isc_mem_get(mctx, sizeof(dns_dbimplementation_t));
779
0
  imp->name = name;
780
0
  imp->create = create;
781
0
  imp->mctx = NULL;
782
0
  imp->driverarg = driverarg;
783
0
  isc_mem_attach(mctx, &imp->mctx);
784
0
  ISC_LINK_INIT(imp, link);
785
0
  ISC_LIST_APPEND(implementations, imp, link);
786
0
  RWUNLOCK(&implock, isc_rwlocktype_write);
787
788
0
  *dbimp = imp;
789
790
0
  return ISC_R_SUCCESS;
791
0
}
792
793
void
794
0
dns_db_unregister(dns_dbimplementation_t **dbimp) {
795
0
  dns_dbimplementation_t *imp;
796
797
0
  REQUIRE(dbimp != NULL && *dbimp != NULL);
798
799
0
  imp = *dbimp;
800
0
  *dbimp = NULL;
801
0
  RWLOCK(&implock, isc_rwlocktype_write);
802
0
  ISC_LIST_UNLINK(implementations, imp, link);
803
0
  isc_mem_putanddetach(&imp->mctx, imp, sizeof(dns_dbimplementation_t));
804
0
  RWUNLOCK(&implock, isc_rwlocktype_write);
805
0
  ENSURE(*dbimp == NULL);
806
0
}
807
808
isc_result_t
809
2
dns__db_getoriginnode(dns_db_t *db, dns_dbnode_t **nodep DNS__DB_FLARG) {
810
2
  REQUIRE(DNS_DB_VALID(db));
811
2
  REQUIRE(dns_db_iszone(db));
812
2
  REQUIRE(nodep != NULL && *nodep == NULL);
813
814
2
  if (db->methods->getoriginnode != NULL) {
815
2
    return (db->methods->getoriginnode)(db,
816
2
                nodep DNS__DB_FLARG_PASS);
817
2
  } else if (db->methods->findnode != NULL) {
818
0
    return (db->methods->findnode)(db, &db->origin, false, NULL,
819
0
                 NULL, nodep DNS__DB_FLARG_PASS);
820
0
  }
821
822
0
  return ISC_R_NOTFOUND;
823
2
}
824
825
dns_stats_t *
826
0
dns_db_getrrsetstats(dns_db_t *db) {
827
0
  REQUIRE(DNS_DB_VALID(db));
828
829
0
  if (db->methods->getrrsetstats != NULL) {
830
0
    return (db->methods->getrrsetstats)(db);
831
0
  }
832
833
0
  return NULL;
834
0
}
835
836
isc_result_t
837
0
dns_db_setcachestats(dns_db_t *db, isc_stats_t *stats) {
838
0
  REQUIRE(DNS_DB_VALID(db));
839
840
0
  if (db->methods->setcachestats != NULL) {
841
0
    return (db->methods->setcachestats)(db, stats);
842
0
  }
843
844
0
  return ISC_R_NOTIMPLEMENTED;
845
0
}
846
847
isc_result_t
848
dns_db_getnsec3parameters(dns_db_t *db, dns_dbversion_t *version,
849
        dns_hash_t *hash, uint8_t *flags,
850
        uint16_t *iterations, unsigned char *salt,
851
0
        size_t *salt_length) {
852
0
  REQUIRE(DNS_DB_VALID(db));
853
0
  REQUIRE(dns_db_iszone(db));
854
855
0
  if (db->methods->getnsec3parameters != NULL) {
856
0
    return (db->methods->getnsec3parameters)(db, version, hash,
857
0
               flags, iterations,
858
0
               salt, salt_length);
859
0
  }
860
861
0
  return ISC_R_NOTFOUND;
862
0
}
863
864
isc_result_t
865
dns_db_getsize(dns_db_t *db, dns_dbversion_t *version, uint64_t *records,
866
0
         uint64_t *bytes) {
867
0
  REQUIRE(DNS_DB_VALID(db));
868
0
  REQUIRE(dns_db_iszone(db));
869
870
0
  if (db->methods->getsize != NULL) {
871
0
    return (db->methods->getsize)(db, version, records, bytes);
872
0
  }
873
874
0
  return ISC_R_NOTFOUND;
875
0
}
876
877
isc_result_t
878
dns_db_setsigningtime(dns_db_t *db, dns_dbnode_t *node,
879
0
          dns_rdataset_t *rdataset, isc_stdtime_t resign) {
880
0
  if (db->methods->setsigningtime != NULL) {
881
0
    return (db->methods->setsigningtime)(db, node, rdataset,
882
0
                 resign);
883
0
  }
884
0
  return ISC_R_NOTIMPLEMENTED;
885
0
}
886
887
isc_result_t
888
dns_db_getsigningtime(dns_db_t *db, isc_stdtime_t *resign, dns_name_t *name,
889
0
          dns_typepair_t *typepair) {
890
0
  if (db->methods->getsigningtime != NULL) {
891
0
    return (db->methods->getsigningtime)(db, resign, name,
892
0
                 typepair);
893
0
  }
894
0
  return ISC_R_NOTFOUND;
895
0
}
896
897
static void
898
17.6k
call_updatenotify(dns_db_t *db) {
899
17.6k
  rcu_read_lock();
900
17.6k
  struct cds_lfht *update_listeners =
901
17.6k
    rcu_dereference(db->update_listeners);
902
17.6k
  if (update_listeners != NULL) {
903
17.6k
    struct cds_lfht_iter iter;
904
17.6k
    dns_dbonupdatelistener_t *listener;
905
17.6k
    cds_lfht_for_each_entry(update_listeners, &iter, listener,
906
17.6k
          ht_node) {
907
0
      if (!cds_lfht_is_node_deleted(&listener->ht_node)) {
908
0
        listener->onupdate(db, listener->onupdate_arg);
909
0
      }
910
0
    }
911
17.6k
  }
912
17.6k
  rcu_read_unlock();
913
17.6k
}
914
915
static void
916
0
updatenotify_free(struct rcu_head *rcu_head) {
917
0
  dns_dbonupdatelistener_t *listener =
918
0
    caa_container_of(rcu_head, dns_dbonupdatelistener_t, rcu_head);
919
0
  isc_mem_putanddetach(&listener->mctx, listener, sizeof(*listener));
920
0
}
921
922
static int
923
0
updatenotify_match(struct cds_lfht_node *ht_node, const void *_key) {
924
0
  const dns_dbonupdatelistener_t *listener =
925
0
    caa_container_of(ht_node, dns_dbonupdatelistener_t, ht_node);
926
0
  const dns_dbonupdatelistener_t *key = _key;
927
928
0
  return listener->onupdate == key->onupdate &&
929
0
         listener->onupdate_arg == key->onupdate_arg;
930
0
}
931
932
/*
933
 * Attach a notify-on-update function the database
934
 */
935
void
936
dns_db_updatenotify_register(dns_db_t *db, dns_dbupdate_callback_t fn,
937
0
           void *fn_arg) {
938
0
  REQUIRE(db != NULL);
939
0
  REQUIRE(fn != NULL);
940
941
0
  dns_dbonupdatelistener_t key = { .onupdate = fn,
942
0
           .onupdate_arg = fn_arg };
943
0
  uint32_t hash = isc_hash32(&key, sizeof(key), true);
944
0
  dns_dbonupdatelistener_t *listener = isc_mem_get(db->mctx,
945
0
               sizeof(*listener));
946
0
  *listener = key;
947
948
0
  isc_mem_attach(db->mctx, &listener->mctx);
949
950
0
  rcu_read_lock();
951
0
  struct cds_lfht *update_listeners =
952
0
    rcu_dereference(db->update_listeners);
953
0
  INSIST(update_listeners != NULL);
954
0
  struct cds_lfht_node *ht_node =
955
0
    cds_lfht_add_unique(update_listeners, hash, updatenotify_match,
956
0
            &key, &listener->ht_node);
957
0
  rcu_read_unlock();
958
959
0
  if (ht_node != &listener->ht_node) {
960
0
    updatenotify_free(&listener->rcu_head);
961
0
  }
962
0
}
963
964
void
965
dns_db_updatenotify_unregister(dns_db_t *db, dns_dbupdate_callback_t fn,
966
0
             void *fn_arg) {
967
0
  REQUIRE(db != NULL);
968
969
0
  dns_dbonupdatelistener_t key = { .onupdate = fn,
970
0
           .onupdate_arg = fn_arg };
971
0
  uint32_t hash = isc_hash32(&key, sizeof(key), true);
972
0
  struct cds_lfht_iter iter;
973
974
0
  rcu_read_lock();
975
0
  struct cds_lfht *update_listeners =
976
0
    rcu_dereference(db->update_listeners);
977
0
  INSIST(update_listeners != NULL);
978
0
  cds_lfht_lookup(update_listeners, hash, updatenotify_match, &key,
979
0
      &iter);
980
981
0
  struct cds_lfht_node *ht_node = cds_lfht_iter_get_node(&iter);
982
0
  if (ht_node != NULL && !cds_lfht_del(update_listeners, ht_node)) {
983
0
    dns_dbonupdatelistener_t *listener = caa_container_of(
984
0
      ht_node, dns_dbonupdatelistener_t, ht_node);
985
0
    call_rcu(&listener->rcu_head, updatenotify_free);
986
0
  }
987
0
  rcu_read_unlock();
988
0
}
989
990
isc_result_t
991
0
dns_db_setservestalettl(dns_db_t *db, dns_ttl_t ttl) {
992
0
  REQUIRE(DNS_DB_VALID(db));
993
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
994
995
0
  if (db->methods->setservestalettl != NULL) {
996
0
    return (db->methods->setservestalettl)(db, ttl);
997
0
  }
998
0
  return ISC_R_NOTIMPLEMENTED;
999
0
}
1000
1001
isc_result_t
1002
0
dns_db_getservestalettl(dns_db_t *db, dns_ttl_t *ttl) {
1003
0
  REQUIRE(DNS_DB_VALID(db));
1004
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1005
1006
0
  if (db->methods->getservestalettl != NULL) {
1007
0
    return (db->methods->getservestalettl)(db, ttl);
1008
0
  }
1009
0
  return ISC_R_NOTIMPLEMENTED;
1010
0
}
1011
1012
isc_result_t
1013
0
dns_db_setservestalerefresh(dns_db_t *db, uint32_t interval) {
1014
0
  REQUIRE(DNS_DB_VALID(db));
1015
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1016
1017
0
  if (db->methods->setservestalerefresh != NULL) {
1018
0
    return (db->methods->setservestalerefresh)(db, interval);
1019
0
  }
1020
0
  return ISC_R_NOTIMPLEMENTED;
1021
0
}
1022
1023
isc_result_t
1024
0
dns_db_getservestalerefresh(dns_db_t *db, uint32_t *interval) {
1025
0
  REQUIRE(DNS_DB_VALID(db));
1026
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) != 0);
1027
1028
0
  if (db->methods->getservestalerefresh != NULL) {
1029
0
    return (db->methods->getservestalerefresh)(db, interval);
1030
0
  }
1031
0
  return ISC_R_NOTIMPLEMENTED;
1032
0
}
1033
1034
isc_result_t
1035
2
dns_db_setgluecachestats(dns_db_t *db, isc_stats_t *stats) {
1036
2
  REQUIRE(dns_db_iszone(db));
1037
2
  REQUIRE(stats != NULL);
1038
1039
2
  if (db->methods->setgluecachestats != NULL) {
1040
2
    return (db->methods->setgluecachestats)(db, stats);
1041
2
  }
1042
1043
0
  return ISC_R_NOTIMPLEMENTED;
1044
2
}
1045
1046
isc_result_t
1047
dns_db_addglue(dns_db_t *db, dns_dbversion_t *version,
1048
         const dns_name_t *owner_name, dns_rdataset_t *rdataset,
1049
0
         dns_message_t *msg) {
1050
0
  REQUIRE(DNS_DB_VALID(db));
1051
0
  REQUIRE((db->attributes & DNS_DBATTR_CACHE) == 0);
1052
0
  REQUIRE(DNS_RDATASET_VALID(rdataset));
1053
0
  REQUIRE(rdataset->methods != NULL);
1054
0
  REQUIRE(rdataset->type == dns_rdatatype_ns);
1055
1056
0
  if (db->methods->addglue != NULL) {
1057
0
    (db->methods->addglue)(db, version, owner_name, rdataset, msg);
1058
1059
0
    return ISC_R_SUCCESS;
1060
0
  }
1061
1062
0
  return ISC_R_NOTIMPLEMENTED;
1063
0
}
1064
1065
void
1066
0
dns_db_expiredata(dns_dbnode_t *node, void *data) {
1067
0
  REQUIRE(node != NULL && node->methods != NULL);
1068
0
  if (node->methods->expiredata != NULL) {
1069
0
    (node->methods->expiredata)(node, data);
1070
0
  }
1071
0
}
1072
1073
void
1074
0
dns_db_deletedata(dns_dbnode_t *node, void *data) {
1075
0
  REQUIRE(node != NULL && node->methods != NULL);
1076
0
  if (node->methods->deletedata != NULL) {
1077
0
    (node->methods->deletedata)(node, data);
1078
0
  }
1079
0
}
1080
1081
void
1082
2
dns_db_setmaxrrperset(dns_db_t *db, uint32_t value) {
1083
2
  REQUIRE(DNS_DB_VALID(db));
1084
1085
2
  if (db->methods->setmaxrrperset != NULL) {
1086
2
    (db->methods->setmaxrrperset)(db, value);
1087
2
  }
1088
2
}
1089
1090
void
1091
2
dns_db_setmaxtypepername(dns_db_t *db, uint32_t value) {
1092
2
  REQUIRE(DNS_DB_VALID(db));
1093
1094
2
  if (db->methods->setmaxtypepername != NULL) {
1095
2
    (db->methods->setmaxtypepername)(db, value);
1096
2
  }
1097
2
}
1098
1099
void
1100
dns__db_logtoomanyrecords(dns_db_t *db, const dns_name_t *name,
1101
        dns_rdatatype_t type, const char *op,
1102
0
        uint32_t limit) {
1103
0
  char namebuf[DNS_NAME_FORMATSIZE];
1104
0
  char originbuf[DNS_NAME_FORMATSIZE];
1105
0
  char typebuf[DNS_RDATATYPE_FORMATSIZE];
1106
0
  char clsbuf[DNS_RDATACLASS_FORMATSIZE];
1107
1108
0
  dns_name_format(name, namebuf, sizeof(namebuf));
1109
0
  dns_name_format(&db->origin, originbuf, sizeof(originbuf));
1110
0
  dns_rdatatype_format(type, typebuf, sizeof(typebuf));
1111
0
  dns_rdataclass_format(db->rdclass, clsbuf, sizeof(clsbuf));
1112
1113
0
  isc_log_write(
1114
0
    DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DB, ISC_LOG_ERROR,
1115
0
    "error %s '%s/%s' in '%s/%s' (%s): %s (must not exceed %u)", op,
1116
0
    namebuf, typebuf, originbuf, clsbuf,
1117
0
    (db->attributes & DNS_DBATTR_CACHE) != 0 ? "cache" : "zone",
1118
0
    isc_result_totext(DNS_R_TOOMANYRECORDS), limit);
1119
0
}
1120
1121
isc_result_t
1122
0
dns_db_getzoneversion(dns_db_t *db, isc_buffer_t *b) {
1123
0
  REQUIRE(db != NULL);
1124
0
  REQUIRE(b != NULL);
1125
1126
0
  if (db->methods->getzoneversion != NULL) {
1127
0
    return (db->methods->getzoneversion)(db, b);
1128
0
  }
1129
0
  return ISC_R_NOTIMPLEMENTED;
1130
0
}